From fe50fa1d5098b7030aa372a4cc8481b0eb12907d Mon Sep 17 00:00:00 2001 From: Git User Date: Fri, 24 May 2019 11:16:06 -0700 Subject: [PATCH 001/410] Initial empty repository -- GitLab From 9be583aa80c56e9e4cd3ce7fef45850cfbb565df Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Fri, 24 May 2019 15:25:31 -0700 Subject: [PATCH 002/410] Camera: Add makefile support for camera drivers This change adds dummy Makefile support to compile camera driver project along with base kernel. Change-Id: I237ba87442c17869b7cc264371c5c3996f43eb95 Signed-off-by: Jigarkumar Zala --- Makefile | 4 ++++ camera_stub.c | 8 ++++++++ 2 files changed, 12 insertions(+) create mode 100644 Makefile create mode 100644 camera_stub.c diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..b5ddf0094c84 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y := -Wno-unused-function +obj-y := camera_stub.o diff --git a/camera_stub.c b/camera_stub.c new file mode 100644 index 000000000000..e2e808c53e5d --- /dev/null +++ b/camera_stub.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +static void _camera_techpack_stub(void) +{ +} -- GitLab From 05349feaa2032c614aae119891b850ef5aa1f49b Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Fri, 24 May 2019 17:56:58 -0700 Subject: [PATCH 003/410] Camera: Bring over camera driver changes Bring over camera driver changes as of msm-4.19 commit 5a5551a7 (Merge "msm: camera: reqmgr: Fix CRM shift one req issue"). Change-Id: Ic0c2b2d74d1b3470c1c51d98228e312fb13c501a Signed-off-by: Jigarkumar Zala --- Makefile | 23 +- camera_stub.c | 8 - config/konacamera.conf | 1 + config/konacameraconf.h | 8 + drivers/Makefile | 13 + drivers/cam_cdm/Makefile | 12 + drivers/cam_cdm/cam_cdm.h | 253 + drivers/cam_cdm/cam_cdm_core_common.c | 587 ++ drivers/cam_cdm/cam_cdm_core_common.h | 45 + drivers/cam_cdm/cam_cdm_hw_core.c | 1135 +++ drivers/cam_cdm/cam_cdm_intf.c | 573 ++ drivers/cam_cdm/cam_cdm_intf_api.h | 202 + drivers/cam_cdm/cam_cdm_soc.c | 199 + drivers/cam_cdm/cam_cdm_soc.h | 21 + drivers/cam_cdm/cam_cdm_util.c | 717 ++ drivers/cam_cdm/cam_cdm_util.h | 161 + drivers/cam_cdm/cam_cdm_virtual.h | 18 + drivers/cam_cdm/cam_cdm_virtual_core.c | 382 + drivers/cam_cdm/cam_hw_cdm170_reg.h | 135 + drivers/cam_core/Makefile | 10 + drivers/cam_core/cam_context.c | 586 ++ drivers/cam_core/cam_context.h | 460 ++ drivers/cam_core/cam_context_utils.c | 1018 +++ drivers/cam_core/cam_context_utils.h | 33 + drivers/cam_core/cam_hw.h | 46 + drivers/cam_core/cam_hw_intf.h | 80 + drivers/cam_core/cam_hw_mgr_intf.h | 338 + drivers/cam_core/cam_node.c | 836 +++ drivers/cam_core/cam_node.h | 104 + drivers/cam_core/cam_subdev.c | 154 + drivers/cam_cpas/Makefile | 14 + drivers/cam_cpas/cam_cpas_hw.c | 1857 +++++ drivers/cam_cpas/cam_cpas_hw.h | 212 + drivers/cam_cpas/cam_cpas_hw_intf.h | 128 + drivers/cam_cpas/cam_cpas_intf.c | 725 ++ drivers/cam_cpas/cam_cpas_soc.c | 614 ++ drivers/cam_cpas/cam_cpas_soc.h | 123 + drivers/cam_cpas/camss_top/Makefile | 9 + drivers/cam_cpas/camss_top/cam_camsstop_hw.c | 82 + drivers/cam_cpas/cpas_top/Makefile | 9 + drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 635 ++ drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 268 + drivers/cam_cpas/cpas_top/cpastop100.h | 531 ++ drivers/cam_cpas/cpas_top/cpastop_v150_100.h | 530 ++ drivers/cam_cpas/cpas_top/cpastop_v170_110.h | 538 ++ drivers/cam_cpas/cpas_top/cpastop_v175_100.h | 558 ++ drivers/cam_cpas/cpas_top/cpastop_v175_101.h | 558 ++ drivers/cam_cpas/cpas_top/cpastop_v175_120.h | 760 ++ drivers/cam_cpas/cpas_top/cpastop_v175_130.h | 760 ++ drivers/cam_cpas/cpas_top/cpastop_v480_100.h | 743 ++ drivers/cam_cpas/include/cam_cpas_api.h | 543 ++ drivers/cam_fd/Makefile | 17 + drivers/cam_fd/cam_fd_context.c | 249 + drivers/cam_fd/cam_fd_context.h | 30 + drivers/cam_fd/cam_fd_dev.c | 207 + drivers/cam_fd/fd_hw_mgr/Makefile | 17 + drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 1949 +++++ drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h | 179 + drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h | 18 + drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile | 16 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 1164 +++ .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h | 237 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c | 235 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 282 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c | 295 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h | 46 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h | 63 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h | 63 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h | 61 + drivers/cam_icp/Makefile | 17 + drivers/cam_icp/cam_icp_context.c | 271 + drivers/cam_icp/cam_icp_context.h | 42 + drivers/cam_icp/cam_icp_subdev.c | 275 + drivers/cam_icp/fw_inc/hfi_intf.h | 168 + drivers/cam_icp/fw_inc/hfi_reg.h | 336 + drivers/cam_icp/fw_inc/hfi_session_defs.h | 564 ++ drivers/cam_icp/fw_inc/hfi_sys_defs.h | 540 ++ drivers/cam_icp/hfi.c | 942 +++ drivers/cam_icp/icp_hw/Makefile | 12 + drivers/cam_icp/icp_hw/a5_hw/Makefile | 14 + drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 518 ++ drivers/cam_icp/icp_hw/a5_hw/a5_core.h | 81 + drivers/cam_icp/icp_hw/a5_hw/a5_dev.c | 228 + drivers/cam_icp/icp_hw/a5_hw/a5_soc.c | 191 + drivers/cam_icp/icp_hw/a5_hw/a5_soc.h | 36 + drivers/cam_icp/icp_hw/bps_hw/Makefile | 14 + drivers/cam_icp/icp_hw/bps_hw/bps_core.c | 416 ++ drivers/cam_icp/icp_hw/bps_hw/bps_core.h | 39 + drivers/cam_icp/icp_hw/bps_hw/bps_dev.c | 207 + drivers/cam_icp/icp_hw/bps_hw/bps_soc.c | 162 + drivers/cam_icp/icp_hw/bps_hw/bps_soc.h | 26 + drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile | 19 + .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 5582 +++++++++++++++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 397 ++ .../icp_hw_mgr/include/cam_a5_hw_intf.h | 74 + .../icp_hw_mgr/include/cam_bps_hw_intf.h | 37 + .../icp_hw_mgr/include/cam_icp_hw_intf.h | 33 + .../icp_hw_mgr/include/cam_ipe_hw_intf.h | 37 + .../icp_hw/include/cam_icp_hw_mgr_intf.h | 47 + drivers/cam_icp/icp_hw/ipe_hw/Makefile | 14 + drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c | 410 ++ drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h | 39 + drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c | 199 + drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c | 165 + drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h | 26 + drivers/cam_isp/Makefile | 13 + drivers/cam_isp/cam_isp_context.c | 3937 +++++++++++ drivers/cam_isp/cam_isp_context.h | 224 + drivers/cam_isp/cam_isp_dev.c | 197 + drivers/cam_isp/cam_isp_dev.h | 31 + drivers/cam_isp/isp_hw_mgr/Makefile | 17 + drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 6280 +++++++++++++++++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 217 + drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c | 28 + drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h | 67 + drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile | 15 + .../hw_utils/cam_isp_packet_parser.c | 916 +++ .../isp_hw_mgr/hw_utils/cam_tasklet_util.c | 327 + .../hw_utils/include/cam_isp_packet_parser.h | 157 + .../hw_utils/include/cam_tasklet_util.h | 116 + .../hw_utils/irq_controller/Makefile | 5 + .../irq_controller/cam_irq_controller.c | 730 ++ .../irq_controller/cam_irq_controller.h | 272 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 256 + drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile | 4 + .../isp_hw_mgr/isp_hw/ife_csid_hw/Makefile | 14 + .../isp_hw/ife_csid_hw/cam_ife_csid170.h | 305 + .../isp_hw/ife_csid_hw/cam_ife_csid175.h | 346 + .../isp_hw/ife_csid_hw/cam_ife_csid175_200.h | 362 + .../isp_hw/ife_csid_hw/cam_ife_csid17x.c | 86 + .../isp_hw/ife_csid_hw/cam_ife_csid480.h | 379 + .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 3704 ++++++++++ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 513 ++ .../isp_hw/ife_csid_hw/cam_ife_csid_dev.c | 140 + .../isp_hw/ife_csid_hw/cam_ife_csid_dev.h | 16 + .../isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c | 58 + .../isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h | 315 + .../isp_hw/ife_csid_hw/cam_ife_csid_soc.c | 237 + .../isp_hw/ife_csid_hw/cam_ife_csid_soc.h | 119 + .../isp_hw/include/cam_ife_csid_hw_intf.h | 222 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 250 + .../isp_hw/include/cam_vfe_hw_intf.h | 370 + .../cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile | 16 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 748 ++ .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h | 91 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c | 197 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h | 35 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c | 347 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h | 117 + .../isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile | 17 + .../isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c | 74 + .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 843 +++ .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 1013 +++ .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 1121 +++ .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 1360 ++++ .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h | 329 + .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h | 400 ++ .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile | 16 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c | 79 + .../vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c | 1221 ++++ .../vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h | 128 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h | 113 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 3781 ++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 227 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 3924 ++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h | 223 + .../vfe_hw/vfe_bus/include/cam_vfe_bus.h | 98 + .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile | 18 + .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c | 556 ++ .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h | 58 + .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 1145 +++ .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h | 66 + .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 881 +++ .../vfe_hw/vfe_top/cam_vfe_camif_ver2.h | 87 + .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 1299 ++++ .../vfe_hw/vfe_top/cam_vfe_camif_ver3.h | 81 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c | 615 ++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h | 87 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 526 ++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h | 55 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_top.c | 55 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 1059 +++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h | 64 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 1101 +++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h | 85 + .../vfe_hw/vfe_top/include/cam_vfe_top.h | 50 + drivers/cam_jpeg/Makefile | 14 + drivers/cam_jpeg/cam_jpeg_context.c | 202 + drivers/cam_jpeg/cam_jpeg_context.h | 67 + drivers/cam_jpeg/cam_jpeg_dev.c | 201 + drivers/cam_jpeg/cam_jpeg_dev.h | 32 + drivers/cam_jpeg/jpeg_hw/Makefile | 15 + drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 1602 +++++ drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h | 155 + .../jpeg_hw/include/cam_jpeg_hw_intf.h | 37 + .../jpeg_hw/include/cam_jpeg_hw_mgr_intf.h | 16 + drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile | 13 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c | 197 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h | 44 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c | 233 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c | 55 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h | 18 + drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile | 13 + .../cam_jpeg_enc_hw_info_ver_4_2_0.h | 72 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 428 ++ .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h | 79 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c | 231 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c | 55 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h | 18 + drivers/cam_lrme/Makefile | 16 + drivers/cam_lrme/cam_lrme_context.c | 251 + drivers/cam_lrme/cam_lrme_context.h | 33 + drivers/cam_lrme/cam_lrme_dev.c | 235 + drivers/cam_lrme/lrme_hw_mgr/Makefile | 16 + .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 1155 +++ .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h | 126 + .../lrme_hw_mgr/cam_lrme_hw_mgr_intf.h | 18 + drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile | 15 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c | 1274 ++++ .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h | 451 ++ .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 304 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h | 195 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h | 186 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c | 161 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h | 21 + drivers/cam_req_mgr/Makefile | 15 + drivers/cam_req_mgr/cam_mem_mgr.c | 1391 ++++ drivers/cam_req_mgr/cam_mem_mgr.h | 126 + drivers/cam_req_mgr/cam_mem_mgr_api.h | 120 + drivers/cam_req_mgr/cam_req_mgr_core.c | 3242 +++++++++ drivers/cam_req_mgr/cam_req_mgr_core.h | 470 ++ drivers/cam_req_mgr/cam_req_mgr_core_defs.h | 17 + drivers/cam_req_mgr/cam_req_mgr_debug.c | 132 + drivers/cam_req_mgr/cam_req_mgr_debug.h | 14 + drivers/cam_req_mgr/cam_req_mgr_dev.c | 752 ++ drivers/cam_req_mgr/cam_req_mgr_dev.h | 43 + drivers/cam_req_mgr/cam_req_mgr_interface.h | 332 + drivers/cam_req_mgr/cam_req_mgr_timer.c | 90 + drivers/cam_req_mgr/cam_req_mgr_timer.h | 64 + drivers/cam_req_mgr/cam_req_mgr_util.c | 333 + drivers/cam_req_mgr/cam_req_mgr_util.h | 165 + drivers/cam_req_mgr/cam_req_mgr_util_priv.h | 42 + drivers/cam_req_mgr/cam_req_mgr_workq.c | 267 + drivers/cam_req_mgr/cam_req_mgr_workq.h | 144 + drivers/cam_req_mgr/cam_subdev.h | 108 + drivers/cam_sensor_module/Makefile | 12 + .../cam_sensor_module/cam_actuator/Makefile | 12 + .../cam_actuator/cam_actuator_core.c | 981 +++ .../cam_actuator/cam_actuator_core.h | 66 + .../cam_actuator/cam_actuator_dev.c | 442 ++ .../cam_actuator/cam_actuator_dev.h | 123 + .../cam_actuator/cam_actuator_soc.c | 77 + .../cam_actuator/cam_actuator_soc.h | 19 + drivers/cam_sensor_module/cam_cci/Makefile | 11 + .../cam_sensor_module/cam_cci/cam_cci_core.c | 1727 +++++ .../cam_sensor_module/cam_cci/cam_cci_core.h | 39 + .../cam_sensor_module/cam_cci/cam_cci_dev.c | 521 ++ .../cam_sensor_module/cam_cci/cam_cci_dev.h | 313 + .../cam_sensor_module/cam_cci/cam_cci_hwreg.h | 79 + .../cam_sensor_module/cam_cci/cam_cci_soc.c | 417 ++ .../cam_sensor_module/cam_cci/cam_cci_soc.h | 45 + drivers/cam_sensor_module/cam_csiphy/Makefile | 12 + .../cam_csiphy/cam_csiphy_core.c | 971 +++ .../cam_csiphy/cam_csiphy_core.h | 52 + .../cam_csiphy/cam_csiphy_dev.c | 253 + .../cam_csiphy/cam_csiphy_dev.h | 293 + .../cam_csiphy/cam_csiphy_soc.c | 383 + .../cam_csiphy/cam_csiphy_soc.h | 73 + .../cam_csiphy/include/cam_csiphy_1_0_hwreg.h | 348 + .../cam_csiphy/include/cam_csiphy_1_1_hwreg.h | 499 ++ .../include/cam_csiphy_1_2_1_hwreg.h | 491 ++ .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 512 ++ .../cam_csiphy/include/cam_csiphy_2_0_hwreg.h | 289 + drivers/cam_sensor_module/cam_eeprom/Makefile | 11 + .../cam_eeprom/cam_eeprom_core.c | 1506 ++++ .../cam_eeprom/cam_eeprom_core.h | 21 + .../cam_eeprom/cam_eeprom_dev.c | 594 ++ .../cam_eeprom/cam_eeprom_dev.h | 196 + .../cam_eeprom/cam_eeprom_soc.c | 384 + .../cam_eeprom/cam_eeprom_soc.h | 16 + drivers/cam_sensor_module/cam_flash/Makefile | 14 + .../cam_flash/cam_flash_core.c | 1812 +++++ .../cam_flash/cam_flash_core.h | 19 + .../cam_flash/cam_flash_dev.c | 652 ++ .../cam_flash/cam_flash_dev.h | 225 + .../cam_flash/cam_flash_soc.c | 251 + .../cam_flash/cam_flash_soc.h | 14 + drivers/cam_sensor_module/cam_ois/Makefile | 12 + .../cam_sensor_module/cam_ois/cam_ois_core.c | 843 +++ .../cam_sensor_module/cam_ois/cam_ois_core.h | 34 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 422 ++ .../cam_sensor_module/cam_ois/cam_ois_dev.h | 126 + .../cam_sensor_module/cam_ois/cam_ois_soc.c | 122 + .../cam_sensor_module/cam_ois/cam_ois_soc.h | 12 + .../cam_sensor_module/cam_res_mgr/Makefile | 12 + .../cam_res_mgr/cam_res_mgr.c | 739 ++ .../cam_res_mgr/cam_res_mgr_api.h | 141 + .../cam_res_mgr/cam_res_mgr_private.h | 110 + drivers/cam_sensor_module/cam_sensor/Makefile | 13 + .../cam_sensor/cam_sensor_core.c | 1325 ++++ .../cam_sensor/cam_sensor_core.h | 86 + .../cam_sensor/cam_sensor_dev.c | 394 ++ .../cam_sensor/cam_sensor_dev.h | 118 + .../cam_sensor/cam_sensor_soc.c | 285 + .../cam_sensor/cam_sensor_soc.h | 18 + .../cam_sensor_module/cam_sensor_io/Makefile | 12 + .../cam_sensor_io/cam_sensor_cci_i2c.c | 232 + .../cam_sensor_io/cam_sensor_i2c.h | 174 + .../cam_sensor_io/cam_sensor_io.c | 217 + .../cam_sensor_io/cam_sensor_io.h | 116 + .../cam_sensor_io/cam_sensor_qup_i2c.c | 530 ++ .../cam_sensor_io/cam_sensor_spi.c | 615 ++ .../cam_sensor_io/cam_sensor_spi.h | 103 + .../cam_sensor_utils/Makefile | 13 + .../cam_sensor_utils/cam_sensor_cmn_header.h | 396 ++ .../cam_sensor_utils/cam_sensor_util.c | 2057 ++++++ .../cam_sensor_utils/cam_sensor_util.h | 61 + drivers/cam_smmu/Makefile | 7 + drivers/cam_smmu/cam_smmu_api.c | 3570 ++++++++++ drivers/cam_smmu/cam_smmu_api.h | 395 ++ drivers/cam_sync/Makefile | 7 + drivers/cam_sync/cam_sync.c | 1094 +++ drivers/cam_sync/cam_sync_api.h | 144 + drivers/cam_sync/cam_sync_private.h | 196 + drivers/cam_sync/cam_sync_util.c | 450 ++ drivers/cam_sync/cam_sync_util.h | 145 + drivers/cam_utils/Makefile | 9 + drivers/cam_utils/cam_common_util.c | 50 + drivers/cam_utils/cam_common_util.h | 48 + drivers/cam_utils/cam_cx_ipeak.c | 128 + drivers/cam_utils/cam_cx_ipeak.h | 17 + drivers/cam_utils/cam_debug_util.c | 117 + drivers/cam_utils/cam_debug_util.h | 134 + drivers/cam_utils/cam_io_util.c | 280 + drivers/cam_utils/cam_io_util.h | 232 + drivers/cam_utils/cam_packet_util.c | 326 + drivers/cam_utils/cam_packet_util.h | 126 + drivers/cam_utils/cam_soc_util.c | 1752 +++++ drivers/cam_utils/cam_soc_util.h | 638 ++ drivers/cam_utils/cam_trace.c | 8 + drivers/cam_utils/cam_trace.h | 301 + include/Kbuild | 2 + include/uapi/Kbuild | 3 + include/uapi/media/Kbuild | 14 + include/uapi/media/cam_cpas.h | 89 + include/uapi/media/cam_defs.h | 746 ++ include/uapi/media/cam_fd.h | 132 + include/uapi/media/cam_icp.h | 210 + include/uapi/media/cam_isp.h | 693 ++ include/uapi/media/cam_isp_ife.h | 52 + include/uapi/media/cam_isp_vfe.h | 49 + include/uapi/media/cam_jpeg.h | 122 + include/uapi/media/cam_lrme.h | 69 + include/uapi/media/cam_req_mgr.h | 444 ++ include/uapi/media/cam_sensor.h | 485 ++ include/uapi/media/cam_sync.h | 139 + 356 files changed, 134959 insertions(+), 10 deletions(-) delete mode 100644 camera_stub.c create mode 100644 config/konacamera.conf create mode 100644 config/konacameraconf.h create mode 100644 drivers/Makefile create mode 100644 drivers/cam_cdm/Makefile create mode 100644 drivers/cam_cdm/cam_cdm.h create mode 100644 drivers/cam_cdm/cam_cdm_core_common.c create mode 100644 drivers/cam_cdm/cam_cdm_core_common.h create mode 100644 drivers/cam_cdm/cam_cdm_hw_core.c create mode 100644 drivers/cam_cdm/cam_cdm_intf.c create mode 100644 drivers/cam_cdm/cam_cdm_intf_api.h create mode 100644 drivers/cam_cdm/cam_cdm_soc.c create mode 100644 drivers/cam_cdm/cam_cdm_soc.h create mode 100644 drivers/cam_cdm/cam_cdm_util.c create mode 100644 drivers/cam_cdm/cam_cdm_util.h create mode 100644 drivers/cam_cdm/cam_cdm_virtual.h create mode 100644 drivers/cam_cdm/cam_cdm_virtual_core.c create mode 100644 drivers/cam_cdm/cam_hw_cdm170_reg.h create mode 100644 drivers/cam_core/Makefile create mode 100644 drivers/cam_core/cam_context.c create mode 100644 drivers/cam_core/cam_context.h create mode 100644 drivers/cam_core/cam_context_utils.c create mode 100644 drivers/cam_core/cam_context_utils.h create mode 100644 drivers/cam_core/cam_hw.h create mode 100644 drivers/cam_core/cam_hw_intf.h create mode 100644 drivers/cam_core/cam_hw_mgr_intf.h create mode 100644 drivers/cam_core/cam_node.c create mode 100644 drivers/cam_core/cam_node.h create mode 100644 drivers/cam_core/cam_subdev.c create mode 100644 drivers/cam_cpas/Makefile create mode 100644 drivers/cam_cpas/cam_cpas_hw.c create mode 100644 drivers/cam_cpas/cam_cpas_hw.h create mode 100644 drivers/cam_cpas/cam_cpas_hw_intf.h create mode 100644 drivers/cam_cpas/cam_cpas_intf.c create mode 100644 drivers/cam_cpas/cam_cpas_soc.c create mode 100644 drivers/cam_cpas/cam_cpas_soc.h create mode 100644 drivers/cam_cpas/camss_top/Makefile create mode 100644 drivers/cam_cpas/camss_top/cam_camsstop_hw.c create mode 100644 drivers/cam_cpas/cpas_top/Makefile create mode 100644 drivers/cam_cpas/cpas_top/cam_cpastop_hw.c create mode 100644 drivers/cam_cpas/cpas_top/cam_cpastop_hw.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop100.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v150_100.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v170_110.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v175_100.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v175_101.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v175_120.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v175_130.h create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v480_100.h create mode 100644 drivers/cam_cpas/include/cam_cpas_api.h create mode 100644 drivers/cam_fd/Makefile create mode 100644 drivers/cam_fd/cam_fd_context.c create mode 100644 drivers/cam_fd/cam_fd_context.h create mode 100644 drivers/cam_fd/cam_fd_dev.c create mode 100644 drivers/cam_fd/fd_hw_mgr/Makefile create mode 100644 drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c create mode 100644 drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h create mode 100644 drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h create mode 100644 drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h create mode 100644 drivers/cam_icp/Makefile create mode 100644 drivers/cam_icp/cam_icp_context.c create mode 100644 drivers/cam_icp/cam_icp_context.h create mode 100644 drivers/cam_icp/cam_icp_subdev.c create mode 100644 drivers/cam_icp/fw_inc/hfi_intf.h create mode 100644 drivers/cam_icp/fw_inc/hfi_reg.h create mode 100644 drivers/cam_icp/fw_inc/hfi_session_defs.h create mode 100644 drivers/cam_icp/fw_inc/hfi_sys_defs.h create mode 100644 drivers/cam_icp/hfi.c create mode 100644 drivers/cam_icp/icp_hw/Makefile create mode 100644 drivers/cam_icp/icp_hw/a5_hw/Makefile create mode 100644 drivers/cam_icp/icp_hw/a5_hw/a5_core.c create mode 100644 drivers/cam_icp/icp_hw/a5_hw/a5_core.h create mode 100644 drivers/cam_icp/icp_hw/a5_hw/a5_dev.c create mode 100644 drivers/cam_icp/icp_hw/a5_hw/a5_soc.c create mode 100644 drivers/cam_icp/icp_hw/a5_hw/a5_soc.h create mode 100644 drivers/cam_icp/icp_hw/bps_hw/Makefile create mode 100644 drivers/cam_icp/icp_hw/bps_hw/bps_core.c create mode 100644 drivers/cam_icp/icp_hw/bps_hw/bps_core.h create mode 100644 drivers/cam_icp/icp_hw/bps_hw/bps_dev.c create mode 100644 drivers/cam_icp/icp_hw/bps_hw/bps_soc.c create mode 100644 drivers/cam_icp/icp_hw/bps_hw/bps_soc.h create mode 100644 drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile create mode 100644 drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c create mode 100644 drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h create mode 100644 drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h create mode 100644 drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h create mode 100644 drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h create mode 100644 drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h create mode 100644 drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h create mode 100644 drivers/cam_icp/icp_hw/ipe_hw/Makefile create mode 100644 drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c create mode 100644 drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h create mode 100644 drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c create mode 100644 drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c create mode 100644 drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h create mode 100644 drivers/cam_isp/Makefile create mode 100644 drivers/cam_isp/cam_isp_context.c create mode 100644 drivers/cam_isp/cam_isp_context.h create mode 100644 drivers/cam_isp/cam_isp_dev.c create mode 100644 drivers/cam_isp/cam_isp_dev.h create mode 100644 drivers/cam_isp/isp_hw_mgr/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c create mode 100644 drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h create mode 100644 drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c create mode 100644 drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c create mode 100644 drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h create mode 100644 drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h create mode 100644 drivers/cam_jpeg/Makefile create mode 100644 drivers/cam_jpeg/cam_jpeg_context.c create mode 100644 drivers/cam_jpeg/cam_jpeg_context.h create mode 100644 drivers/cam_jpeg/cam_jpeg_dev.c create mode 100644 drivers/cam_jpeg/cam_jpeg_dev.h create mode 100644 drivers/cam_jpeg/jpeg_hw/Makefile create mode 100644 drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c create mode 100644 drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h create mode 100644 drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h create mode 100644 drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c create mode 100644 drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h create mode 100644 drivers/cam_lrme/Makefile create mode 100644 drivers/cam_lrme/cam_lrme_context.c create mode 100644 drivers/cam_lrme/cam_lrme_context.h create mode 100644 drivers/cam_lrme/cam_lrme_dev.c create mode 100644 drivers/cam_lrme/lrme_hw_mgr/Makefile create mode 100644 drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c create mode 100644 drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h create mode 100644 drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c create mode 100644 drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h create mode 100644 drivers/cam_req_mgr/Makefile create mode 100644 drivers/cam_req_mgr/cam_mem_mgr.c create mode 100644 drivers/cam_req_mgr/cam_mem_mgr.h create mode 100644 drivers/cam_req_mgr/cam_mem_mgr_api.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_core.c create mode 100644 drivers/cam_req_mgr/cam_req_mgr_core.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_core_defs.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_debug.c create mode 100644 drivers/cam_req_mgr/cam_req_mgr_debug.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_dev.c create mode 100644 drivers/cam_req_mgr/cam_req_mgr_dev.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_interface.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_timer.c create mode 100644 drivers/cam_req_mgr/cam_req_mgr_timer.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_util.c create mode 100644 drivers/cam_req_mgr/cam_req_mgr_util.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_util_priv.h create mode 100644 drivers/cam_req_mgr/cam_req_mgr_workq.c create mode 100644 drivers/cam_req_mgr/cam_req_mgr_workq.h create mode 100644 drivers/cam_req_mgr/cam_subdev.h create mode 100644 drivers/cam_sensor_module/Makefile create mode 100644 drivers/cam_sensor_module/cam_actuator/Makefile create mode 100644 drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c create mode 100644 drivers/cam_sensor_module/cam_actuator/cam_actuator_core.h create mode 100644 drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c create mode 100644 drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h create mode 100644 drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c create mode 100644 drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.h create mode 100644 drivers/cam_sensor_module/cam_cci/Makefile create mode 100644 drivers/cam_sensor_module/cam_cci/cam_cci_core.c create mode 100644 drivers/cam_sensor_module/cam_cci/cam_cci_core.h create mode 100644 drivers/cam_sensor_module/cam_cci/cam_cci_dev.c create mode 100644 drivers/cam_sensor_module/cam_cci/cam_cci_dev.h create mode 100644 drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h create mode 100644 drivers/cam_sensor_module/cam_cci/cam_cci_soc.c create mode 100644 drivers/cam_sensor_module/cam_cci/cam_cci_soc.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/Makefile create mode 100644 drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c create mode 100644 drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c create mode 100644 drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c create mode 100644 drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h create mode 100644 drivers/cam_sensor_module/cam_eeprom/Makefile create mode 100644 drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c create mode 100644 drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.h create mode 100644 drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c create mode 100644 drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h create mode 100644 drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c create mode 100644 drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h create mode 100644 drivers/cam_sensor_module/cam_flash/Makefile create mode 100644 drivers/cam_sensor_module/cam_flash/cam_flash_core.c create mode 100644 drivers/cam_sensor_module/cam_flash/cam_flash_core.h create mode 100644 drivers/cam_sensor_module/cam_flash/cam_flash_dev.c create mode 100644 drivers/cam_sensor_module/cam_flash/cam_flash_dev.h create mode 100644 drivers/cam_sensor_module/cam_flash/cam_flash_soc.c create mode 100644 drivers/cam_sensor_module/cam_flash/cam_flash_soc.h create mode 100644 drivers/cam_sensor_module/cam_ois/Makefile create mode 100644 drivers/cam_sensor_module/cam_ois/cam_ois_core.c create mode 100644 drivers/cam_sensor_module/cam_ois/cam_ois_core.h create mode 100644 drivers/cam_sensor_module/cam_ois/cam_ois_dev.c create mode 100644 drivers/cam_sensor_module/cam_ois/cam_ois_dev.h create mode 100644 drivers/cam_sensor_module/cam_ois/cam_ois_soc.c create mode 100644 drivers/cam_sensor_module/cam_ois/cam_ois_soc.h create mode 100644 drivers/cam_sensor_module/cam_res_mgr/Makefile create mode 100644 drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c create mode 100644 drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h create mode 100644 drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h create mode 100644 drivers/cam_sensor_module/cam_sensor/Makefile create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.h create mode 100644 drivers/cam_sensor_module/cam_sensor_io/Makefile create mode 100644 drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c create mode 100644 drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h create mode 100644 drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c create mode 100644 drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h create mode 100644 drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c create mode 100644 drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c create mode 100644 drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h create mode 100644 drivers/cam_sensor_module/cam_sensor_utils/Makefile create mode 100644 drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h create mode 100644 drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c create mode 100644 drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h create mode 100644 drivers/cam_smmu/Makefile create mode 100644 drivers/cam_smmu/cam_smmu_api.c create mode 100644 drivers/cam_smmu/cam_smmu_api.h create mode 100644 drivers/cam_sync/Makefile create mode 100644 drivers/cam_sync/cam_sync.c create mode 100644 drivers/cam_sync/cam_sync_api.h create mode 100644 drivers/cam_sync/cam_sync_private.h create mode 100644 drivers/cam_sync/cam_sync_util.c create mode 100644 drivers/cam_sync/cam_sync_util.h create mode 100644 drivers/cam_utils/Makefile create mode 100644 drivers/cam_utils/cam_common_util.c create mode 100644 drivers/cam_utils/cam_common_util.h create mode 100644 drivers/cam_utils/cam_cx_ipeak.c create mode 100644 drivers/cam_utils/cam_cx_ipeak.h create mode 100644 drivers/cam_utils/cam_debug_util.c create mode 100644 drivers/cam_utils/cam_debug_util.h create mode 100644 drivers/cam_utils/cam_io_util.c create mode 100644 drivers/cam_utils/cam_io_util.h create mode 100644 drivers/cam_utils/cam_packet_util.c create mode 100644 drivers/cam_utils/cam_packet_util.h create mode 100644 drivers/cam_utils/cam_soc_util.c create mode 100644 drivers/cam_utils/cam_soc_util.h create mode 100644 drivers/cam_utils/cam_trace.c create mode 100644 drivers/cam_utils/cam_trace.h create mode 100644 include/Kbuild create mode 100644 include/uapi/Kbuild create mode 100644 include/uapi/media/Kbuild create mode 100644 include/uapi/media/cam_cpas.h create mode 100644 include/uapi/media/cam_defs.h create mode 100644 include/uapi/media/cam_fd.h create mode 100644 include/uapi/media/cam_icp.h create mode 100644 include/uapi/media/cam_isp.h create mode 100644 include/uapi/media/cam_isp_ife.h create mode 100644 include/uapi/media/cam_isp_vfe.h create mode 100644 include/uapi/media/cam_jpeg.h create mode 100644 include/uapi/media/cam_lrme.h create mode 100644 include/uapi/media/cam_req_mgr.h create mode 100644 include/uapi/media/cam_sensor.h create mode 100644 include/uapi/media/cam_sync.h diff --git a/Makefile b/Makefile index b5ddf0094c84..f844d98cbdc6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,23 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y := -Wno-unused-function -obj-y := camera_stub.o +# auto-detect subdirs +ifeq ($(CONFIG_ARCH_KONA), y) +include $(srctree)/techpack/camera/config/konacamera.conf +endif + +# Use USERINCLUDE when you must reference the UAPI directories only. +USERINCLUDE += \ + -I$(srctree)/techpack/camera/include/uapi + +# Use LINUXINCLUDE when you must reference the include/ directory. +# Needed to be compatible with the O= option +LINUXINCLUDE += \ + -I$(srctree)/techpack/camera/include/uapi \ + -I$(srctree)/techpack/camera/include + +ifeq ($(CONFIG_ARCH_KONA), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/konacameraconf.h +endif + +obj-y += drivers/ diff --git a/camera_stub.c b/camera_stub.c deleted file mode 100644 index e2e808c53e5d..000000000000 --- a/camera_stub.c +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. - */ - -static void _camera_techpack_stub(void) -{ -} diff --git a/config/konacamera.conf b/config/konacamera.conf new file mode 100644 index 000000000000..9b08bcb80c2b --- /dev/null +++ b/config/konacamera.conf @@ -0,0 +1 @@ +export CONFIG_SPECTRA_CAMERA=y \ No newline at end of file diff --git a/config/konacameraconf.h b/config/konacameraconf.h new file mode 100644 index 000000000000..e0cf514fe3cf --- /dev/null +++ b/config/konacameraconf.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#define CONFIG_SPECTRA_CAMERA 1 + diff --git a/drivers/Makefile b/drivers/Makefile new file mode 100644 index 000000000000..28d4762a55df --- /dev/null +++ b/drivers/Makefile @@ -0,0 +1,13 @@ +obj-y += cam_req_mgr/ +obj-y += cam_utils/ +obj-y += cam_core/ +obj-y += cam_sync/ +obj-y += cam_smmu/ +obj-y += cam_cpas/ +obj-y += cam_cdm/ +obj-y += cam_isp/ +obj-y += cam_sensor_module/ +obj-y += cam_icp/ +obj-y += cam_jpeg/ +obj-y += cam_fd/ +obj-y += cam_lrme/ diff --git a/drivers/cam_cdm/Makefile b/drivers/cam_cdm/Makefile new file mode 100644 index 000000000000..2b5b712cbbb3 --- /dev/null +++ b/drivers/cam_cdm/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm_util.o cam_cdm_intf.o cam_cdm_soc.o\ + cam_cdm_core_common.o cam_cdm_virtual_core.o \ + cam_cdm_hw_core.o diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h new file mode 100644 index 000000000000..ab12ab52f293 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_H_ +#define _CAM_CDM_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_cdm_intf_api.h" +#include "cam_soc_util.h" +#include "cam_cpas_api.h" +#include "cam_hw_intf.h" +#include "cam_hw.h" +#include "cam_debug_util.h" + +#define CAM_MAX_SW_CDM_VERSION_SUPPORTED 1 +#define CAM_SW_CDM_INDEX 0 +#define CAM_CDM_INFLIGHT_WORKS 5 +#define CAM_CDM_HW_RESET_TIMEOUT 300 + +#define CAM_CDM_HW_ID_MASK 0xF +#define CAM_CDM_HW_ID_SHIFT 0x5 +#define CAM_CDM_CLIENTS_ID_MASK 0x1F + +#define CAM_CDM_GET_HW_IDX(x) (((x) >> CAM_CDM_HW_ID_SHIFT) & \ + CAM_CDM_HW_ID_MASK) +#define CAM_CDM_CREATE_CLIENT_HANDLE(hw_idx, client_idx) \ + ((((hw_idx) & CAM_CDM_HW_ID_MASK) << CAM_CDM_HW_ID_SHIFT) | \ + ((client_idx) & CAM_CDM_CLIENTS_ID_MASK)) +#define CAM_CDM_GET_CLIENT_IDX(x) ((x) & CAM_CDM_CLIENTS_ID_MASK) +#define CAM_PER_CDM_MAX_REGISTERED_CLIENTS (CAM_CDM_CLIENTS_ID_MASK + 1) +#define CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM (CAM_CDM_HW_ID_MASK + 1) + +/* enum cam_cdm_reg_attr - read, write, read and write permissions.*/ +enum cam_cdm_reg_attr { + CAM_REG_ATTR_READ, + CAM_REG_ATTR_WRITE, + CAM_REG_ATTR_READ_WRITE, +}; + +/* enum cam_cdm_hw_process_intf_cmd - interface commands.*/ +enum cam_cdm_hw_process_intf_cmd { + CAM_CDM_HW_INTF_CMD_ACQUIRE, + CAM_CDM_HW_INTF_CMD_RELEASE, + CAM_CDM_HW_INTF_CMD_SUBMIT_BL, + CAM_CDM_HW_INTF_CMD_RESET_HW, + CAM_CDM_HW_INTF_CMD_INVALID, +}; + +/* enum cam_cdm_regs - CDM driver offset enums.*/ +enum cam_cdm_regs { + /*cfg_offsets 0*/ + CDM_CFG_HW_VERSION, + CDM_CFG_TITAN_VERSION, + CDM_CFG_RST_CMD, + CDM_CFG_CGC_CFG, + CDM_CFG_CORE_CFG, + CDM_CFG_CORE_EN, + CDM_CFG_FE_CFG, + /*irq_offsets 7*/ + CDM_IRQ_MASK, + CDM_IRQ_CLEAR, + CDM_IRQ_CLEAR_CMD, + CDM_IRQ_SET, + CDM_IRQ_SET_CMD, + CDM_IRQ_STATUS, + CDM_IRQ_USR_DATA, + /*BL FIFO Registers 14*/ + CDM_BL_FIFO_BASE_REG, + CDM_BL_FIFO_LEN_REG, + CDM_BL_FIFO_STORE_REG, + CDM_BL_FIFO_CFG, + CDM_BL_FIFO_RB, + CDM_BL_FIFO_BASE_RB, + CDM_BL_FIFO_LEN_RB, + CDM_BL_FIFO_PENDING_REQ_RB, + /*CDM System Debug Registers 22*/ + CDM_DBG_WAIT_STATUS, + CDM_DBG_SCRATCH_0_REG, + CDM_DBG_SCRATCH_1_REG, + CDM_DBG_SCRATCH_2_REG, + CDM_DBG_SCRATCH_3_REG, + CDM_DBG_SCRATCH_4_REG, + CDM_DBG_SCRATCH_5_REG, + CDM_DBG_SCRATCH_6_REG, + CDM_DBG_SCRATCH_7_REG, + CDM_DBG_LAST_AHB_ADDR, + CDM_DBG_LAST_AHB_DATA, + CDM_DBG_CORE_DBUG, + CDM_DBG_LAST_AHB_ERR_ADDR, + CDM_DBG_LAST_AHB_ERR_DATA, + CDM_DBG_CURRENT_BL_BASE, + CDM_DBG_CURRENT_BL_LEN, + CDM_DBG_CURRENT_USED_AHB_BASE, + CDM_DBG_DEBUG_STATUS, + /*FE Bus Miser Registers 40*/ + CDM_BUS_MISR_CFG_0, + CDM_BUS_MISR_CFG_1, + CDM_BUS_MISR_RD_VAL, + /*Performance Counter registers 43*/ + CDM_PERF_MON_CTRL, + CDM_PERF_MON_0, + CDM_PERF_MON_1, + CDM_PERF_MON_2, + /*Spare registers 47*/ + CDM_SPARE, +}; + +/* struct cam_cdm_reg_offset - struct for offset with attribute.*/ +struct cam_cdm_reg_offset { + uint32_t offset; + enum cam_cdm_reg_attr attribute; +}; + +/* struct cam_cdm_reg_offset_table - struct for whole offset table.*/ +struct cam_cdm_reg_offset_table { + uint32_t first_offset; + uint32_t last_offset; + uint32_t reg_count; + const struct cam_cdm_reg_offset *offsets; + uint32_t offset_max_size; +}; + +/* enum cam_cdm_flags - Bit fields for CDM flags used */ +enum cam_cdm_flags { + CAM_CDM_FLAG_SHARED_CDM, + CAM_CDM_FLAG_PRIVATE_CDM, +}; + +/* enum cam_cdm_type - Enum for possible CAM CDM types */ +enum cam_cdm_type { + CAM_VIRTUAL_CDM, + CAM_HW_CDM, +}; + +/* enum cam_cdm_mem_base_index - Enum for possible CAM CDM types */ +enum cam_cdm_mem_base_index { + CAM_HW_CDM_BASE_INDEX, + CAM_HW_CDM_MAX_INDEX = CAM_SOC_MAX_BLOCK, +}; + +/* struct cam_cdm_client - struct for cdm clients data.*/ +struct cam_cdm_client { + struct cam_cdm_acquire_data data; + void __iomem *changebase_addr; + uint32_t stream_on; + uint32_t refcount; + struct mutex lock; + uint32_t handle; +}; + +/* struct cam_cdm_work_payload - struct for cdm work payload data.*/ +struct cam_cdm_work_payload { + struct cam_hw_info *hw; + uint32_t irq_status; + uint32_t irq_data; + struct work_struct work; +}; + +/* enum cam_cdm_bl_cb_type - Enum for possible CAM CDM cb request types */ +enum cam_cdm_bl_cb_type { + CAM_HW_CDM_BL_CB_CLIENT = 1, + CAM_HW_CDM_BL_CB_INTERNAL, +}; + +/* struct cam_cdm_bl_cb_request_entry - callback entry for work to process.*/ +struct cam_cdm_bl_cb_request_entry { + uint8_t bl_tag; + enum cam_cdm_bl_cb_type request_type; + uint32_t client_hdl; + void *userdata; + uint32_t cookie; + struct list_head entry; +}; + +/* struct cam_cdm_hw_intf_cmd_submit_bl - cdm interface submit command.*/ +struct cam_cdm_hw_intf_cmd_submit_bl { + uint32_t handle; + struct cam_cdm_bl_request *data; +}; + +/* struct cam_cdm_hw_mem - CDM hw memory struct */ +struct cam_cdm_hw_mem { + int32_t handle; + uint32_t vaddr; + uintptr_t kmdvaddr; + size_t size; +}; + +/* struct cam_cdm - CDM hw device struct */ +struct cam_cdm { + uint32_t index; + char name[128]; + enum cam_cdm_id id; + enum cam_cdm_flags flags; + struct completion reset_complete; + struct completion bl_complete; + struct workqueue_struct *work_queue; + struct list_head bl_request_list; + struct cam_hw_version version; + uint32_t hw_version; + uint32_t hw_family_version; + struct cam_iommu_handle iommu_hdl; + struct cam_cdm_reg_offset_table *offset_tbl; + struct cam_cdm_utils_ops *ops; + struct cam_cdm_client *clients[CAM_PER_CDM_MAX_REGISTERED_CLIENTS]; + uint8_t bl_tag; + atomic_t error; + atomic_t bl_done; + struct cam_cdm_hw_mem gen_irq; + uint32_t cpas_handle; +}; + +/* struct cam_cdm_private_dt_data - CDM hw custom dt data */ +struct cam_cdm_private_dt_data { + bool dt_cdm_shared; + uint32_t dt_num_supported_clients; + const char *dt_cdm_client_name[CAM_PER_CDM_MAX_REGISTERED_CLIENTS]; +}; + +/* struct cam_cdm_intf_devices - CDM mgr interface devices */ +struct cam_cdm_intf_devices { + struct mutex lock; + uint32_t refcount; + struct cam_hw_intf *device; + struct cam_cdm_private_dt_data *data; +}; + +/* struct cam_cdm_intf_mgr - CDM mgr interface device struct */ +struct cam_cdm_intf_mgr { + bool probe_done; + struct cam_cdm_intf_devices nodes[CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM]; + uint32_t cdm_count; + uint32_t dt_supported_hw_cdm; + int32_t refcount; +}; + +int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t *index); +int cam_cdm_intf_deregister_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t index); + +#endif /* _CAM_CDM_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c new file mode 100644 index 000000000000..5401945c0e23 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_io_util.h" +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_soc.h" +#include "cam_cdm_core_common.h" + +static void cam_cdm_get_client_refcount(struct cam_cdm_client *client) +{ + mutex_lock(&client->lock); + CAM_DBG(CAM_CDM, "CDM client get refcount=%d", + client->refcount); + client->refcount++; + mutex_unlock(&client->lock); +} + +static void cam_cdm_put_client_refcount(struct cam_cdm_client *client) +{ + mutex_lock(&client->lock); + CAM_DBG(CAM_CDM, "CDM client put refcount=%d", + client->refcount); + if (client->refcount > 0) { + client->refcount--; + } else { + CAM_ERR(CAM_CDM, "Refcount put when zero"); + WARN_ON(1); + } + mutex_unlock(&client->lock); +} + +bool cam_cdm_set_cam_hw_version( + uint32_t ver, struct cam_hw_version *cam_version) +{ + switch (ver) { + case CAM_CDM170_VERSION: + case CAM_CDM175_VERSION: + case CAM_CDM480_VERSION: + cam_version->major = (ver & 0xF0000000); + cam_version->minor = (ver & 0xFFF0000); + cam_version->incr = (ver & 0xFFFF); + cam_version->reserved = 0; + return true; + default: + CAM_ERR(CAM_CDM, "CDM Version=%x not supported in util", ver); + break; + } + return false; +} + +bool cam_cdm_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + if (!irq_data) + return false; + + CAM_DBG(CAM_CDM, "CPAS error callback type=%d", irq_data->irq_type); + + return false; +} + +struct cam_cdm_utils_ops *cam_cdm_get_ops( + uint32_t ver, struct cam_hw_version *cam_version, bool by_cam_version) +{ + if (by_cam_version == false) { + switch (ver) { + case CAM_CDM170_VERSION: + case CAM_CDM175_VERSION: + case CAM_CDM480_VERSION: + return &CDM170_ops; + default: + CAM_ERR(CAM_CDM, "CDM Version=%x not supported in util", + ver); + } + } else if (cam_version) { + if (((cam_version->major == 1) && + (cam_version->minor == 0) && + (cam_version->incr == 0)) || + ((cam_version->major == 1) && + (cam_version->minor == 1) && + (cam_version->incr == 0)) || + ((cam_version->major == 1) && + (cam_version->minor == 2) && + (cam_version->incr == 0))) { + + CAM_DBG(CAM_CDM, + "cam_hw_version=%x:%x:%x supported", + cam_version->major, cam_version->minor, + cam_version->incr); + return &CDM170_ops; + } + + CAM_ERR(CAM_CDM, "cam_hw_version=%x:%x:%x not supported", + cam_version->major, cam_version->minor, + cam_version->incr); + } + + return NULL; +} + +struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( + uint32_t tag, struct list_head *bl_list) +{ + struct cam_cdm_bl_cb_request_entry *node; + + list_for_each_entry(node, bl_list, entry) { + if (node->bl_tag == tag) + return node; + } + CAM_ERR(CAM_CDM, "Could not find the bl request for tag=%x", tag); + + return NULL; +} + +int cam_cdm_get_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_cdm *cdm_core; + + if ((cdm_hw) && (cdm_hw->core_info) && (get_hw_cap_args) && + (sizeof(struct cam_iommu_handle) == arg_size)) { + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + *((struct cam_iommu_handle *)get_hw_cap_args) = + cdm_core->iommu_hdl; + return 0; + } + + return -EINVAL; +} + +int cam_cdm_find_free_client_slot(struct cam_cdm *hw) +{ + int i; + + for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { + if (hw->clients[i] == NULL) { + CAM_DBG(CAM_CDM, "Found client slot %d", i); + return i; + } + } + CAM_ERR(CAM_CDM, "No more client slots"); + + return -EBUSY; +} + + +void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, + enum cam_cdm_cb_status status, void *data) +{ + int i; + struct cam_cdm *core = NULL; + struct cam_cdm_client *client = NULL; + + if (!cdm_hw) { + CAM_ERR(CAM_CDM, "CDM Notify called with NULL hw info"); + return; + } + core = (struct cam_cdm *)cdm_hw->core_info; + + if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + int client_idx; + struct cam_cdm_bl_cb_request_entry *node = + (struct cam_cdm_bl_cb_request_entry *)data; + + client_idx = CAM_CDM_GET_CLIENT_IDX(node->client_hdl); + client = core->clients[client_idx]; + if ((!client) || (client->handle != node->client_hdl)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, + node->client_hdl); + return; + } + cam_cdm_get_client_refcount(client); + if (client->data.cam_cdm_callback) { + CAM_DBG(CAM_CDM, "Calling client=%s cb cookie=%d", + client->data.identifier, node->cookie); + client->data.cam_cdm_callback(node->client_hdl, + node->userdata, CAM_CDM_CB_STATUS_BL_SUCCESS, + node->cookie); + CAM_DBG(CAM_CDM, "Exit client cb cookie=%d", + node->cookie); + } else { + CAM_ERR(CAM_CDM, "No cb registered for client hdl=%x", + node->client_hdl); + } + cam_cdm_put_client_refcount(client); + return; + } + + for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { + if (core->clients[i] != NULL) { + client = core->clients[i]; + mutex_lock(&client->lock); + CAM_DBG(CAM_CDM, "Found client slot %d", i); + if (client->data.cam_cdm_callback) { + if (status == CAM_CDM_CB_STATUS_PAGEFAULT) { + unsigned long iova = + (unsigned long)data; + + client->data.cam_cdm_callback( + client->handle, + client->data.userdata, + CAM_CDM_CB_STATUS_PAGEFAULT, + (iova & 0xFFFFFFFF)); + } + } else { + CAM_ERR(CAM_CDM, + "No cb registered for client hdl=%x", + client->handle); + } + mutex_unlock(&client->lock); + } + } +} + +int cam_cdm_stream_ops_internal(void *hw_priv, + void *start_args, bool operation) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_cdm *core = NULL; + int rc = -EPERM; + int client_idx; + struct cam_cdm_client *client; + uint32_t *handle = start_args; + + if (!hw_priv) + return -EINVAL; + + core = (struct cam_cdm *)cdm_hw->core_info; + client_idx = CAM_CDM_GET_CLIENT_IDX(*handle); + client = core->clients[client_idx]; + if (!client) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, *handle); + return -EINVAL; + } + cam_cdm_get_client_refcount(client); + if (*handle != client->handle) { + CAM_ERR(CAM_CDM, "client id given handle=%x invalid", *handle); + cam_cdm_put_client_refcount(client); + return -EINVAL; + } + if (operation == true) { + if (true == client->stream_on) { + CAM_ERR(CAM_CDM, + "Invalid CDM client is already streamed ON"); + cam_cdm_put_client_refcount(client); + return rc; + } + } else { + if (client->stream_on == false) { + CAM_ERR(CAM_CDM, + "Invalid CDM client is already streamed Off"); + cam_cdm_put_client_refcount(client); + return rc; + } + } + + mutex_lock(&cdm_hw->hw_mutex); + if (operation == true) { + if (!cdm_hw->open_count) { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = + CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core->cpas_handle, + &ahb_vote, &axi_vote); + if (rc != 0) { + CAM_ERR(CAM_CDM, "CPAS start failed"); + goto end; + } + CAM_DBG(CAM_CDM, "CDM init first time"); + if (core->id == CAM_CDM_VIRTUAL) { + CAM_DBG(CAM_CDM, + "Virtual CDM HW init first time"); + rc = 0; + } else { + CAM_DBG(CAM_CDM, "CDM HW init first time"); + rc = cam_hw_cdm_init(hw_priv, NULL, 0); + if (rc == 0) { + rc = cam_hw_cdm_alloc_genirq_mem( + hw_priv); + if (rc != 0) { + CAM_ERR(CAM_CDM, + "Genirqalloc failed"); + cam_hw_cdm_deinit(hw_priv, + NULL, 0); + } + } else { + CAM_ERR(CAM_CDM, "CDM HW init failed"); + } + } + if (rc == 0) { + cdm_hw->open_count++; + client->stream_on = true; + } else { + if (cam_cpas_stop(core->cpas_handle)) + CAM_ERR(CAM_CDM, "CPAS stop failed"); + } + } else { + cdm_hw->open_count++; + CAM_DBG(CAM_CDM, "CDM HW already ON count=%d", + cdm_hw->open_count); + rc = 0; + client->stream_on = true; + } + } else { + if (cdm_hw->open_count) { + cdm_hw->open_count--; + CAM_DBG(CAM_CDM, "stream OFF CDM %d", + cdm_hw->open_count); + if (!cdm_hw->open_count) { + CAM_DBG(CAM_CDM, "CDM Deinit now"); + if (core->id == CAM_CDM_VIRTUAL) { + CAM_DBG(CAM_CDM, + "Virtual CDM HW Deinit"); + rc = 0; + } else { + CAM_DBG(CAM_CDM, "CDM HW Deinit now"); + rc = cam_hw_cdm_deinit( + hw_priv, NULL, 0); + if (cam_hw_cdm_release_genirq_mem( + hw_priv)) + CAM_ERR(CAM_CDM, + "Genirq release fail"); + } + if (rc) { + CAM_ERR(CAM_CDM, + "Deinit failed in streamoff"); + } else { + client->stream_on = false; + rc = cam_cpas_stop(core->cpas_handle); + if (rc) + CAM_ERR(CAM_CDM, + "CPAS stop failed"); + } + } else { + client->stream_on = false; + rc = 0; + CAM_DBG(CAM_CDM, + "Client stream off success =%d", + cdm_hw->open_count); + } + } else { + CAM_DBG(CAM_CDM, "stream OFF CDM Invalid %d", + cdm_hw->open_count); + rc = -ENXIO; + } + } +end: + cam_cdm_put_client_refcount(client); + mutex_unlock(&cdm_hw->hw_mutex); + return rc; +} + +int cam_cdm_stream_start(void *hw_priv, + void *start_args, uint32_t size) +{ + int rc = 0; + + if (!hw_priv) + return -EINVAL; + + rc = cam_cdm_stream_ops_internal(hw_priv, start_args, true); + return rc; + +} + +int cam_cdm_stream_stop(void *hw_priv, + void *start_args, uint32_t size) +{ + int rc = 0; + + if (!hw_priv) + return -EINVAL; + + rc = cam_cdm_stream_ops_internal(hw_priv, start_args, false); + return rc; + +} + +int cam_cdm_process_cmd(void *hw_priv, + uint32_t cmd, void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_hw_soc_info *soc_data = NULL; + struct cam_cdm *core = NULL; + int rc = -EINVAL; + + if ((!hw_priv) || (!cmd_args) || + (cmd >= CAM_CDM_HW_INTF_CMD_INVALID)) + return rc; + + soc_data = &cdm_hw->soc_info; + core = (struct cam_cdm *)cdm_hw->core_info; + switch (cmd) { + case CAM_CDM_HW_INTF_CMD_SUBMIT_BL: { + struct cam_cdm_hw_intf_cmd_submit_bl *req; + int idx; + struct cam_cdm_client *client; + + if (sizeof(struct cam_cdm_hw_intf_cmd_submit_bl) != arg_size) { + CAM_ERR(CAM_CDM, "Invalid CDM cmd %d arg size=%x", cmd, + arg_size); + break; + } + req = (struct cam_cdm_hw_intf_cmd_submit_bl *)cmd_args; + if ((req->data->type < 0) || + (req->data->type > CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA)) { + CAM_ERR(CAM_CDM, "Invalid req bl cmd addr type=%d", + req->data->type); + break; + } + idx = CAM_CDM_GET_CLIENT_IDX(req->handle); + client = core->clients[idx]; + if ((!client) || (req->handle != client->handle)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, + req->handle); + break; + } + cam_cdm_get_client_refcount(client); + if ((req->data->flag == true) && + (!client->data.cam_cdm_callback)) { + CAM_ERR(CAM_CDM, + "CDM request cb without registering cb"); + cam_cdm_put_client_refcount(client); + break; + } + if (client->stream_on != true) { + CAM_ERR(CAM_CDM, + "Invalid CDM needs to be streamed ON first"); + cam_cdm_put_client_refcount(client); + break; + } + if (core->id == CAM_CDM_VIRTUAL) + rc = cam_virtual_cdm_submit_bl(cdm_hw, req, client); + else + rc = cam_hw_cdm_submit_bl(cdm_hw, req, client); + + cam_cdm_put_client_refcount(client); + break; + } + case CAM_CDM_HW_INTF_CMD_ACQUIRE: { + struct cam_cdm_acquire_data *data; + int idx; + struct cam_cdm_client *client; + + if (sizeof(struct cam_cdm_acquire_data) != arg_size) { + CAM_ERR(CAM_CDM, "Invalid CDM cmd %d arg size=%x", cmd, + arg_size); + break; + } + + mutex_lock(&cdm_hw->hw_mutex); + data = (struct cam_cdm_acquire_data *)cmd_args; + CAM_DBG(CAM_CDM, "Trying to acquire client=%s in hw idx=%d", + data->identifier, core->index); + idx = cam_cdm_find_free_client_slot(core); + if ((idx < 0) || (core->clients[idx])) { + mutex_unlock(&cdm_hw->hw_mutex); + CAM_ERR(CAM_CDM, + "Fail to client slots, client=%s in hw idx=%d", + data->identifier, core->index); + break; + } + core->clients[idx] = kzalloc(sizeof(struct cam_cdm_client), + GFP_KERNEL); + if (!core->clients[idx]) { + mutex_unlock(&cdm_hw->hw_mutex); + rc = -ENOMEM; + break; + } + + mutex_unlock(&cdm_hw->hw_mutex); + client = core->clients[idx]; + mutex_init(&client->lock); + data->ops = core->ops; + if (core->id == CAM_CDM_VIRTUAL) { + data->cdm_version.major = 1; + data->cdm_version.minor = 0; + data->cdm_version.incr = 0; + data->cdm_version.reserved = 0; + data->ops = cam_cdm_get_ops(0, + &data->cdm_version, true); + if (!data->ops) { + mutex_destroy(&client->lock); + mutex_lock(&cdm_hw->hw_mutex); + kfree(core->clients[idx]); + core->clients[idx] = NULL; + mutex_unlock( + &cdm_hw->hw_mutex); + rc = -EPERM; + CAM_ERR(CAM_CDM, "Invalid ops for virtual cdm"); + break; + } + } else { + data->cdm_version = core->version; + } + + cam_cdm_get_client_refcount(client); + mutex_lock(&client->lock); + memcpy(&client->data, data, + sizeof(struct cam_cdm_acquire_data)); + client->handle = CAM_CDM_CREATE_CLIENT_HANDLE( + core->index, + idx); + client->stream_on = false; + data->handle = client->handle; + CAM_DBG(CAM_CDM, "Acquired client=%s in hwidx=%d", + data->identifier, core->index); + mutex_unlock(&client->lock); + rc = 0; + break; + } + case CAM_CDM_HW_INTF_CMD_RELEASE: { + uint32_t *handle = cmd_args; + int idx; + struct cam_cdm_client *client; + + if (sizeof(uint32_t) != arg_size) { + CAM_ERR(CAM_CDM, + "Invalid CDM cmd %d size=%x for handle=%x", + cmd, arg_size, *handle); + return -EINVAL; + } + idx = CAM_CDM_GET_CLIENT_IDX(*handle); + mutex_lock(&cdm_hw->hw_mutex); + client = core->clients[idx]; + if ((!client) || (*handle != client->handle)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", + client, *handle); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + cam_cdm_put_client_refcount(client); + mutex_lock(&client->lock); + if (client->refcount != 0) { + CAM_ERR(CAM_CDM, "CDM Client refcount not zero %d", + client->refcount); + rc = -EPERM; + mutex_unlock(&client->lock); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + core->clients[idx] = NULL; + mutex_unlock(&client->lock); + mutex_destroy(&client->lock); + kfree(client); + mutex_unlock(&cdm_hw->hw_mutex); + rc = 0; + break; + } + case CAM_CDM_HW_INTF_CMD_RESET_HW: { + CAM_ERR(CAM_CDM, "CDM HW reset not supported for handle =%x", + *((uint32_t *)cmd_args)); + break; + } + default: + CAM_ERR(CAM_CDM, "CDM HW intf command not valid =%d", cmd); + break; + } + return rc; +} diff --git a/drivers/cam_cdm/cam_cdm_core_common.h b/drivers/cam_cdm/cam_cdm_core_common.h new file mode 100644 index 000000000000..8dcbe8ed1971 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_core_common.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_CORE_COMMON_H_ +#define _CAM_CDM_CORE_COMMON_H_ + +#include "cam_mem_mgr.h" + +#define CAM_CDM170_VERSION 0x10000000 +#define CAM_CDM175_VERSION 0x10010000 +#define CAM_CDM480_VERSION 0x10020000 + +extern struct cam_cdm_utils_ops CDM170_ops; + +int cam_hw_cdm_init(void *hw_priv, void *init_hw_args, uint32_t arg_size); +int cam_hw_cdm_deinit(void *hw_priv, void *init_hw_args, uint32_t arg_size); +int cam_hw_cdm_alloc_genirq_mem(void *hw_priv); +int cam_hw_cdm_release_genirq_mem(void *hw_priv); +int cam_cdm_get_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size); +int cam_cdm_stream_ops_internal(void *hw_priv, void *start_args, + bool operation); +int cam_cdm_stream_start(void *hw_priv, void *start_args, uint32_t size); +int cam_cdm_stream_stop(void *hw_priv, void *start_args, uint32_t size); +int cam_cdm_process_cmd(void *hw_priv, uint32_t cmd, void *cmd_args, + uint32_t arg_size); +bool cam_cdm_set_cam_hw_version( + uint32_t ver, struct cam_hw_version *cam_version); +bool cam_cdm_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data); +struct cam_cdm_utils_ops *cam_cdm_get_ops( + uint32_t ver, struct cam_hw_version *cam_version, bool by_cam_version); +int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client); +int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client); +struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( + uint32_t tag, struct list_head *bl_list); +void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, + enum cam_cdm_cb_status status, void *data); + +#endif /* _CAM_CDM_CORE_COMMON_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c new file mode 100644 index 000000000000..40dba7352f32 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -0,0 +1,1135 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_core_common.h" +#include "cam_cdm_soc.h" +#include "cam_io_util.h" +#include "cam_hw_cdm170_reg.h" + +#define CAM_HW_CDM_CPAS_0_NAME "qcom,cam170-cpas-cdm0" +#define CAM_HW_CDM_IPE_0_NAME "qcom,cam170-ipe0-cdm" +#define CAM_HW_CDM_IPE_1_NAME "qcom,cam170-ipe1-cdm" +#define CAM_HW_CDM_BPS_NAME "qcom,cam170-bps-cdm" + +#define CAM_CDM_BL_FIFO_WAIT_TIMEOUT 2000 + +static void cam_hw_cdm_work(struct work_struct *work); + +/* DT match table entry for all CDM variants*/ +static const struct of_device_id msm_cam_hw_cdm_dt_match[] = { + { + .compatible = CAM_HW_CDM_CPAS_0_NAME, + .data = &cam170_cpas_cdm_offset_table, + }, + {} +}; + +static enum cam_cdm_id cam_hw_cdm_get_id_by_name(char *name) +{ + if (!strcmp(CAM_HW_CDM_CPAS_0_NAME, name)) + return CAM_CDM_CPAS_0; + + return CAM_CDM_MAX; +} + +int cam_hw_cdm_bl_fifo_pending_bl_rb(struct cam_hw_info *cdm_hw, + uint32_t *pending_bl) +{ + int rc = 0; + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB, + pending_bl)) { + CAM_ERR(CAM_CDM, "Failed to read CDM pending BL's"); + rc = -EIO; + } + + return rc; +} + +static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw, + bool enable) +{ + int rc = -EIO; + uint32_t irq_mask = 0; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_MASK, + &irq_mask)) { + CAM_ERR(CAM_CDM, "Failed to read CDM IRQ mask"); + return rc; + } + + if (enable == true) { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, + (irq_mask | 0x4))) { + CAM_ERR(CAM_CDM, "Write failed to enable BL done irq"); + } else { + atomic_inc(&core->bl_done); + rc = 0; + CAM_DBG(CAM_CDM, "BL done irq enabled =%d", + atomic_read(&core->bl_done)); + } + } else { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, + (irq_mask & 0x70003))) { + CAM_ERR(CAM_CDM, "Write failed to disable BL done irq"); + } else { + atomic_dec(&core->bl_done); + rc = 0; + CAM_DBG(CAM_CDM, "BL done irq disable =%d", + atomic_read(&core->bl_done)); + } + } + return rc; +} + +static int cam_hw_cdm_enable_core(struct cam_hw_info *cdm_hw, bool enable) +{ + int rc = 0; + + if (enable == true) { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x01)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core enable"); + rc = -EIO; + } + } else { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x02)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core disable"); + rc = -EIO; + } + } + return rc; +} + +int cam_hw_cdm_enable_core_dbg(struct cam_hw_info *cdm_hw) +{ + int rc = 0; + + if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0x10100)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); + rc = -EIO; + } + + return rc; +} + +int cam_hw_cdm_disable_core_dbg(struct cam_hw_info *cdm_hw) +{ + int rc = 0; + + if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); + rc = -EIO; + } + + return rc; +} + +void cam_hw_cdm_dump_scratch_registors(struct cam_hw_info *cdm_hw) +{ + uint32_t dump_reg = 0; + + cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); + CAM_ERR(CAM_CDM, "dump core en=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_0_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch0=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_1_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch1=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_2_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch2=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_3_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch3=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_4_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch4=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_5_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch5=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_6_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch6=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_7_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch7=%x", dump_reg); + +} + +void cam_hw_cdm_dump_core_debug_registers( + struct cam_hw_info *cdm_hw) +{ + uint32_t dump_reg, core_dbg, loop_cnt; + + mutex_lock(&cdm_hw->hw_mutex); + cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW core status=%x", dump_reg); + /* First pause CDM, If it fails still proceed to dump debug info */ + cam_hw_cdm_enable_core(cdm_hw, false); + cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current pending BL=%x", dump_reg); + loop_cnt = dump_reg; + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_DEBUG_STATUS, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW Debug status reg=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, &core_dbg); + if (core_dbg & 0x100) { + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_LAST_AHB_ADDR, &dump_reg); + CAM_ERR(CAM_CDM, "AHB dump reglastaddr=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_LAST_AHB_DATA, &dump_reg); + CAM_ERR(CAM_CDM, "AHB dump reglastdata=%x", dump_reg); + } else { + CAM_ERR(CAM_CDM, "CDM HW AHB dump not enable"); + } + + if (core_dbg & 0x10000) { + int i; + + CAM_ERR(CAM_CDM, "CDM HW BL FIFO dump with loop count=%d", + loop_cnt); + for (i = 0 ; i < loop_cnt ; i++) { + cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_RB, i); + cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_BASE_RB, + &dump_reg); + CAM_ERR(CAM_CDM, "BL(%d) base addr =%x", i, dump_reg); + cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_LEN_RB, + &dump_reg); + CAM_ERR(CAM_CDM, "BL(%d) len=%d tag=%d", i, + (dump_reg & 0xFFFFF), (dump_reg & 0xFF000000)); + } + } else { + CAM_ERR(CAM_CDM, "CDM HW BL FIFO readback not enable"); + } + + CAM_ERR(CAM_CDM, "CDM HW default dump"); + cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_CFG, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW core cfg=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_STATUS, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW irq status=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_SET, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW irq set reg=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_BL_BASE, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current BL base=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_BL_LEN, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current BL len=%d tag=%d", + (dump_reg & 0xFFFFF), (dump_reg & 0xFF000000)); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_USED_AHB_BASE, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current AHB base=%x", dump_reg); + + cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current pending BL=%x", dump_reg); + + /* Enable CDM back */ + cam_hw_cdm_enable_core(cdm_hw, true); + mutex_unlock(&cdm_hw->hw_mutex); + +} + +int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw, + uint32_t bl_count) +{ + uint32_t pending_bl = 0; + int32_t available_bl_slots = 0; + int rc = -EIO; + long time_left; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + do { + if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB, + &pending_bl)) { + CAM_ERR(CAM_CDM, "Failed to read CDM pending BL's"); + rc = -EIO; + break; + } + available_bl_slots = CAM_CDM_HWFIFO_SIZE - pending_bl; + if (available_bl_slots < 0) { + CAM_ERR(CAM_CDM, "Invalid available slots %d:%d:%d", + available_bl_slots, CAM_CDM_HWFIFO_SIZE, + pending_bl); + break; + } + if (bl_count < (available_bl_slots - 1)) { + CAM_DBG(CAM_CDM, + "BL slot available_cnt=%d requested=%d", + (available_bl_slots - 1), bl_count); + rc = bl_count; + break; + } else if (0 == (available_bl_slots - 1)) { + rc = cam_hw_cdm_enable_bl_done_irq(cdm_hw, true); + if (rc) { + CAM_ERR(CAM_CDM, "Enable BL done irq failed"); + break; + } + time_left = wait_for_completion_timeout( + &core->bl_complete, msecs_to_jiffies( + CAM_CDM_BL_FIFO_WAIT_TIMEOUT)); + if (time_left <= 0) { + CAM_ERR(CAM_CDM, + "CDM HW BL Wait timed out failed"); + if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, + false)) + CAM_ERR(CAM_CDM, + "Disable BL done irq failed"); + rc = -EIO; + break; + } + if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, false)) + CAM_ERR(CAM_CDM, "Disable BL done irq failed"); + rc = 0; + CAM_DBG(CAM_CDM, "CDM HW is ready for data"); + } else { + rc = (bl_count - (available_bl_slots - 1)); + break; + } + } while (1); + + return rc; +} + +bool cam_hw_cdm_bl_write(struct cam_hw_info *cdm_hw, uint32_t src, + uint32_t len, uint32_t tag) +{ + if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_BASE_REG, src)) { + CAM_ERR(CAM_CDM, "Failed to write CDM base to BL base"); + return true; + } + if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_LEN_REG, + ((len & 0xFFFFF) | ((tag & 0xFF) << 20)))) { + CAM_ERR(CAM_CDM, "Failed to write CDM BL len"); + return true; + } + return false; +} + +bool cam_hw_cdm_commit_bl_write(struct cam_hw_info *cdm_hw) +{ + if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_STORE_REG, 1)) { + CAM_ERR(CAM_CDM, "Failed to write CDM commit BL"); + return true; + } + return false; +} + +int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req) +{ + struct cam_cdm_bl_cb_request_entry *node; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + uint32_t len; + int rc; + + if (core->bl_tag > 63) { + CAM_ERR(CAM_CDM, "bl_tag invalid =%d", core->bl_tag); + rc = -EINVAL; + goto end; + } + CAM_DBG(CAM_CDM, "CDM write BL last cmd tag=%x total=%d cookie=%d", + core->bl_tag, req->data->cmd_arrary_count, req->data->cookie); + node = kzalloc(sizeof(struct cam_cdm_bl_cb_request_entry), + GFP_KERNEL); + if (!node) { + rc = -ENOMEM; + goto end; + } + node->request_type = CAM_HW_CDM_BL_CB_CLIENT; + node->client_hdl = req->handle; + node->cookie = req->data->cookie; + node->bl_tag = core->bl_tag; + node->userdata = req->data->userdata; + list_add_tail(&node->entry, &core->bl_request_list); + len = core->ops->cdm_required_size_genirq() * core->bl_tag; + core->ops->cdm_write_genirq(((uint32_t *)core->gen_irq.kmdvaddr + len), + core->bl_tag); + rc = cam_hw_cdm_bl_write(cdm_hw, (core->gen_irq.vaddr + (4*len)), + ((4 * core->ops->cdm_required_size_genirq()) - 1), + core->bl_tag); + if (rc) { + CAM_ERR(CAM_CDM, "CDM hw bl write failed for gen irq bltag=%d", + core->bl_tag); + list_del_init(&node->entry); + kfree(node); + rc = -EIO; + goto end; + } + + if (cam_hw_cdm_commit_bl_write(cdm_hw)) { + CAM_ERR(CAM_CDM, "Cannot commit the genirq BL with tag tag=%d", + core->bl_tag); + list_del_init(&node->entry); + kfree(node); + rc = -EIO; + } + +end: + return rc; +} + +int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client) +{ + int i, rc; + struct cam_cdm_bl_request *cdm_cmd = req->data; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + uint32_t pending_bl = 0; + int write_count = 0; + + if (req->data->cmd_arrary_count > CAM_CDM_HWFIFO_SIZE) { + pr_info("requested BL more than max size, cnt=%d max=%d", + req->data->cmd_arrary_count, CAM_CDM_HWFIFO_SIZE); + } + + if (atomic_read(&core->error)) + return -EIO; + + mutex_lock(&cdm_hw->hw_mutex); + mutex_lock(&client->lock); + rc = cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &pending_bl); + if (rc) { + CAM_ERR(CAM_CDM, "Cannot read the current BL depth"); + mutex_unlock(&client->lock); + mutex_unlock(&cdm_hw->hw_mutex); + return rc; + } + + for (i = 0; i < req->data->cmd_arrary_count ; i++) { + uint64_t hw_vaddr_ptr = 0; + size_t len = 0; + + if ((!cdm_cmd->cmd[i].len) && + (cdm_cmd->cmd[i].len > 0x100000)) { + CAM_ERR(CAM_CDM, + "cmd len(%d) is invalid cnt=%d total cnt=%d", + cdm_cmd->cmd[i].len, i, + req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + if (atomic_read(&core->error)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "In error state cnt=%d total cnt=%d\n", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + if (write_count == 0) { + write_count = cam_hw_cdm_wait_for_bl_fifo(cdm_hw, + (req->data->cmd_arrary_count - i)); + if (write_count < 0) { + CAM_ERR(CAM_CDM, + "wait for bl fifo failed %d:%d", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + } else { + write_count--; + } + + if (req->data->type == CAM_CDM_BL_CMD_TYPE_MEM_HANDLE) { + rc = cam_mem_get_io_buf( + cdm_cmd->cmd[i].bl_addr.mem_handle, + core->iommu_hdl.non_secure, &hw_vaddr_ptr, + &len); + } else if (req->data->type == CAM_CDM_BL_CMD_TYPE_HW_IOVA) { + if (!cdm_cmd->cmd[i].bl_addr.hw_iova) { + CAM_ERR(CAM_CDM, + "Hw bl hw_iova is invalid %d:%d", + i, req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + rc = 0; + hw_vaddr_ptr = + (uint64_t)cdm_cmd->cmd[i].bl_addr.hw_iova; + len = cdm_cmd->cmd[i].len + cdm_cmd->cmd[i].offset; + } else { + CAM_ERR(CAM_CDM, + "Only mem hdl/hw va type is supported %d", + req->data->type); + rc = -EINVAL; + break; + } + + if ((!rc) && (hw_vaddr_ptr) && (len) && + (len >= cdm_cmd->cmd[i].offset)) { + CAM_DBG(CAM_CDM, "Got the HW VA"); + if (core->bl_tag >= + (CAM_CDM_HWFIFO_SIZE - 1)) + core->bl_tag = 0; + rc = cam_hw_cdm_bl_write(cdm_hw, + ((uint32_t)hw_vaddr_ptr + + cdm_cmd->cmd[i].offset), + (cdm_cmd->cmd[i].len - 1), core->bl_tag); + if (rc) { + CAM_ERR(CAM_CDM, "Hw bl write failed %d:%d", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + } else { + CAM_ERR(CAM_CDM, + "Sanity check failed for hdl=%x len=%zu:%d", + cdm_cmd->cmd[i].bl_addr.mem_handle, len, + cdm_cmd->cmd[i].offset); + CAM_ERR(CAM_CDM, "Sanity check failed for %d:%d", + i, req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + + if (!rc) { + CAM_DBG(CAM_CDM, + "write BL success for cnt=%d with tag=%d total_cnt=%d", + i, core->bl_tag, req->data->cmd_arrary_count); + + CAM_DBG(CAM_CDM, "Now commit the BL"); + if (cam_hw_cdm_commit_bl_write(cdm_hw)) { + CAM_ERR(CAM_CDM, + "Cannot commit the BL %d tag=%d", + i, core->bl_tag); + rc = -EIO; + break; + } + CAM_DBG(CAM_CDM, "BL commit success BL %d tag=%d", i, + core->bl_tag); + core->bl_tag++; + if ((req->data->flag == true) && + (i == (req->data->cmd_arrary_count - + 1))) { + rc = cam_hw_cdm_submit_gen_irq( + cdm_hw, req); + if (rc == 0) + core->bl_tag++; + } + } + } + mutex_unlock(&client->lock); + mutex_unlock(&cdm_hw->hw_mutex); + return rc; + +} + +static void cam_hw_cdm_work(struct work_struct *work) +{ + struct cam_cdm_work_payload *payload; + struct cam_hw_info *cdm_hw; + struct cam_cdm *core; + + payload = container_of(work, struct cam_cdm_work_payload, work); + if (payload) { + cdm_hw = payload->hw; + core = (struct cam_cdm *)cdm_hw->core_info; + + CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { + struct cam_cdm_bl_cb_request_entry *node, *tnode; + + CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", + payload->irq_data); + mutex_lock(&cdm_hw->hw_mutex); + list_for_each_entry_safe(node, tnode, + &core->bl_request_list, entry) { + if (node->request_type == + CAM_HW_CDM_BL_CB_CLIENT) { + cam_cdm_notify_clients(cdm_hw, + CAM_CDM_CB_STATUS_BL_SUCCESS, + (void *)node); + } else if (node->request_type == + CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_ERR(CAM_CDM, + "Invalid node=%pK %d", node, + node->request_type); + } + list_del_init(&node->entry); + if (node->bl_tag == payload->irq_data) { + kfree(node); + break; + } + kfree(node); + } + mutex_unlock(&cdm_hw->hw_mutex); + } + + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_RST_DONE_MASK) { + CAM_DBG(CAM_CDM, "CDM HW reset done IRQ"); + complete(&core->reset_complete); + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_BL_DONE_MASK) { + if (atomic_read(&core->bl_done)) { + CAM_DBG(CAM_CDM, "CDM HW BL done IRQ"); + complete(&core->bl_complete); + } + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Invalid command IRQ, Need HW reset\n"); + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "AHB Error IRQ\n"); + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + atomic_dec(&core->error); + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Overflow Error IRQ\n"); + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + atomic_dec(&core->error); + } + kfree(payload); + } else { + CAM_ERR(CAM_CDM, "NULL payload"); + } + +} + +static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *token, + uint32_t buf_info) +{ + struct cam_hw_info *cdm_hw = NULL; + struct cam_cdm *core = NULL; + + if (token) { + cdm_hw = (struct cam_hw_info *)token; + core = (struct cam_cdm *)cdm_hw->core_info; + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + CAM_ERR_RATE_LIMIT(CAM_CDM, "Page fault iova addr %pK\n", + (void *)iova); + cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT, + (void *)iova); + atomic_dec(&core->error); + } else { + CAM_ERR(CAM_CDM, "Invalid token"); + } + +} + +irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) +{ + struct cam_hw_info *cdm_hw = data; + struct cam_cdm *cdm_core = cdm_hw->core_info; + struct cam_cdm_work_payload *payload; + bool work_status; + + CAM_DBG(CAM_CDM, "Got irq"); + payload = kzalloc(sizeof(struct cam_cdm_work_payload), GFP_ATOMIC); + if (payload) { + if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_STATUS, + &payload->irq_status)) { + CAM_ERR(CAM_CDM, "Failed to read CDM HW IRQ status"); + } + if (!payload->irq_status) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Invalid irq received\n"); + kfree(payload); + return IRQ_HANDLED; + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { + if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_USR_DATA, + &payload->irq_data)) { + CAM_ERR(CAM_CDM, + "Failed to read CDM HW IRQ data"); + } + } + CAM_DBG(CAM_CDM, "Got payload=%d", payload->irq_status); + payload->hw = cdm_hw; + INIT_WORK((struct work_struct *)&payload->work, + cam_hw_cdm_work); + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR, + payload->irq_status)) + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ Clear"); + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR_CMD, 0x01)) + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd"); + work_status = queue_work(cdm_core->work_queue, &payload->work); + if (work_status == false) { + CAM_ERR(CAM_CDM, "Failed to queue work for irq=0x%x", + payload->irq_status); + kfree(payload); + } + } + + return IRQ_HANDLED; +} + +int cam_hw_cdm_alloc_genirq_mem(void *hw_priv) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_mem_mgr_request_desc genirq_alloc_cmd; + struct cam_mem_mgr_memory_desc genirq_alloc_out; + struct cam_cdm *cdm_core = NULL; + int rc = -EINVAL; + + if (!hw_priv) + return rc; + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + genirq_alloc_cmd.align = 0; + genirq_alloc_cmd.size = (8 * CAM_CDM_HWFIFO_SIZE); + genirq_alloc_cmd.smmu_hdl = cdm_core->iommu_hdl.non_secure; + genirq_alloc_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; + rc = cam_mem_mgr_request_mem(&genirq_alloc_cmd, + &genirq_alloc_out); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to get genirq cmd space rc=%d", rc); + goto end; + } + cdm_core->gen_irq.handle = genirq_alloc_out.mem_handle; + cdm_core->gen_irq.vaddr = (genirq_alloc_out.iova & 0xFFFFFFFF); + cdm_core->gen_irq.kmdvaddr = genirq_alloc_out.kva; + cdm_core->gen_irq.size = genirq_alloc_out.len; + +end: + return rc; +} + +int cam_hw_cdm_release_genirq_mem(void *hw_priv) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_cdm *cdm_core = NULL; + struct cam_mem_mgr_memory_desc genirq_release_cmd; + int rc = -EINVAL; + + if (!hw_priv) + return rc; + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + genirq_release_cmd.mem_handle = cdm_core->gen_irq.handle; + rc = cam_mem_mgr_release_mem(&genirq_release_cmd); + if (rc) + CAM_ERR(CAM_CDM, "Failed to put genirq cmd space for hw"); + + return rc; +} + +int cam_hw_cdm_init(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_cdm *cdm_core = NULL; + int rc; + long time_left; + + if (!hw_priv) + return -EINVAL; + + soc_info = &cdm_hw->soc_info; + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) { + CAM_ERR(CAM_CDM, "Enable platform failed"); + goto end; + } + + CAM_DBG(CAM_CDM, "Enable soc done"); + +/* Before triggering the reset to HW, clear the reset complete */ + atomic_set(&cdm_core->error, 0); + atomic_set(&cdm_core->bl_done, 0); + reinit_completion(&cdm_core->reset_complete); + reinit_completion(&cdm_core->bl_complete); + + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, 0x70003)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ mask"); + goto disable_return; + } + if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_RST_CMD, 0x9)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); + goto disable_return; + } + + CAM_DBG(CAM_CDM, "Waiting for CDM HW resetdone"); + time_left = wait_for_completion_timeout(&cdm_core->reset_complete, + msecs_to_jiffies(CAM_CDM_HW_RESET_TIMEOUT)); + + if (time_left <= 0) { + CAM_ERR(CAM_CDM, "CDM HW reset Wait failed rc=%d", rc); + goto disable_return; + } else { + CAM_DBG(CAM_CDM, "CDM Init success"); + cdm_hw->hw_state = CAM_HW_STATE_POWER_UP; + cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, 0x70003); + rc = 0; + goto end; + } + +disable_return: + rc = -EIO; + cam_soc_util_disable_platform_resource(soc_info, true, true); +end: + return rc; +} + +int cam_hw_cdm_deinit(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_cdm *cdm_core = NULL; + int rc = 0; + + if (!hw_priv) + return -EINVAL; + + soc_info = &cdm_hw->soc_info; + cdm_core = cdm_hw->core_info; + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CDM, "disable platform failed"); + } else { + CAM_DBG(CAM_CDM, "CDM Deinit success"); + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + } + + return rc; +} + +int cam_hw_cdm_probe(struct platform_device *pdev) +{ + int rc; + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + struct cam_cdm_private_dt_data *soc_private = NULL; + struct cam_cpas_register_params cpas_parms; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + cdm_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!cdm_hw_intf) + return -ENOMEM; + + cdm_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!cdm_hw) { + kfree(cdm_hw_intf); + return -ENOMEM; + } + + cdm_hw->core_info = kzalloc(sizeof(struct cam_cdm), GFP_KERNEL); + if (!cdm_hw->core_info) { + kfree(cdm_hw); + kfree(cdm_hw_intf); + return -ENOMEM; + } + + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + cdm_hw->soc_info.pdev = pdev; + cdm_hw->soc_info.dev = &pdev->dev; + cdm_hw->soc_info.dev_name = pdev->name; + cdm_hw_intf->hw_type = CAM_HW_CDM; + cdm_hw->open_count = 0; + mutex_init(&cdm_hw->hw_mutex); + spin_lock_init(&cdm_hw->hw_lock); + init_completion(&cdm_hw->hw_complete); + + rc = cam_hw_cdm_soc_get_dt_properties(cdm_hw, msm_cam_hw_cdm_dt_match); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to get dt properties"); + goto release_mem; + } + cdm_hw_intf->hw_idx = cdm_hw->soc_info.index; + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + soc_private = (struct cam_cdm_private_dt_data *) + cdm_hw->soc_info.soc_private; + if (soc_private->dt_cdm_shared == true) + cdm_core->flags = CAM_CDM_FLAG_SHARED_CDM; + else + cdm_core->flags = CAM_CDM_FLAG_PRIVATE_CDM; + + cdm_core->bl_tag = 0; + cdm_core->id = cam_hw_cdm_get_id_by_name(cdm_core->name); + if (cdm_core->id >= CAM_CDM_MAX) { + CAM_ERR(CAM_CDM, "Failed to get CDM HW name for %s", + cdm_core->name); + goto release_private_mem; + } + INIT_LIST_HEAD(&cdm_core->bl_request_list); + init_completion(&cdm_core->reset_complete); + init_completion(&cdm_core->bl_complete); + cdm_hw_intf->hw_priv = cdm_hw; + cdm_hw_intf->hw_ops.get_hw_caps = cam_cdm_get_caps; + cdm_hw_intf->hw_ops.init = cam_hw_cdm_init; + cdm_hw_intf->hw_ops.deinit = cam_hw_cdm_deinit; + cdm_hw_intf->hw_ops.start = cam_cdm_stream_start; + cdm_hw_intf->hw_ops.stop = cam_cdm_stream_stop; + cdm_hw_intf->hw_ops.read = NULL; + cdm_hw_intf->hw_ops.write = NULL; + cdm_hw_intf->hw_ops.process_cmd = cam_cdm_process_cmd; + mutex_lock(&cdm_hw->hw_mutex); + + CAM_DBG(CAM_CDM, "type %d index %d", cdm_hw_intf->hw_type, + cdm_hw_intf->hw_idx); + + platform_set_drvdata(pdev, cdm_hw_intf); + + rc = cam_smmu_get_handle("cpas-cdm0", &cdm_core->iommu_hdl.non_secure); + if (rc < 0) { + CAM_ERR(CAM_CDM, "cpas-cdm get iommu handle failed"); + goto unlock_release_mem; + } + cam_smmu_set_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + cam_hw_cdm_iommu_fault_handler, cdm_hw); + + cdm_core->iommu_hdl.secure = -1; + + cdm_core->work_queue = alloc_workqueue(cdm_core->name, + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, + CAM_CDM_INFLIGHT_WORKS); + + rc = cam_soc_util_request_platform_resource(&cdm_hw->soc_info, + cam_hw_cdm_irq, cdm_hw); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to request platform resource"); + goto destroy_non_secure_hdl; + } + + cpas_parms.cam_cpas_client_cb = cam_cdm_cpas_cb; + cpas_parms.cell_index = cdm_hw->soc_info.index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = cdm_hw_intf; + strlcpy(cpas_parms.identifier, "cpas-cdm", CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CDM, "Virtual CDM CPAS registration failed"); + goto release_platform_resource; + } + CAM_DBG(CAM_CDM, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + cdm_core->cpas_handle = cpas_parms.client_handle; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(cdm_core->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS start failed"); + goto cpas_unregister; + } + + rc = cam_hw_cdm_init(cdm_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to Init CDM HW"); + goto cpas_stop; + } + cdm_hw->open_count++; + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_HW_VERSION, + &cdm_core->hw_version)) { + CAM_ERR(CAM_CDM, "Failed to read CDM HW Version"); + goto deinit; + } + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_TITAN_VERSION, + &cdm_core->hw_family_version)) { + CAM_ERR(CAM_CDM, "Failed to read CDM family Version"); + goto deinit; + } + + CAM_DBG(CAM_CDM, "CDM Hw version read success family =%x hw =%x", + cdm_core->hw_family_version, cdm_core->hw_version); + cdm_core->ops = cam_cdm_get_ops(cdm_core->hw_version, NULL, + false); + if (!cdm_core->ops) { + CAM_ERR(CAM_CDM, "Failed to util ops for hw"); + goto deinit; + } + + if (!cam_cdm_set_cam_hw_version(cdm_core->hw_version, + &cdm_core->version)) { + CAM_ERR(CAM_CDM, "Failed to set cam he version for hw"); + goto deinit; + } + + rc = cam_hw_cdm_deinit(cdm_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to Deinit CDM HW"); + cdm_hw->open_count--; + goto cpas_stop; + } + + rc = cam_cpas_stop(cdm_core->cpas_handle); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS stop failed"); + cdm_hw->open_count--; + goto cpas_unregister; + } + + rc = cam_cdm_intf_register_hw_cdm(cdm_hw_intf, + soc_private, CAM_HW_CDM, &cdm_core->index); + if (rc) { + CAM_ERR(CAM_CDM, "HW CDM Interface registration failed"); + cdm_hw->open_count--; + goto cpas_unregister; + } + cdm_hw->open_count--; + mutex_unlock(&cdm_hw->hw_mutex); + + CAM_DBG(CAM_CDM, "CDM%d probe successful", cdm_hw_intf->hw_idx); + + return rc; + +deinit: + if (cam_hw_cdm_deinit(cdm_hw, NULL, 0)) + CAM_ERR(CAM_CDM, "Deinit failed for hw"); + cdm_hw->open_count--; +cpas_stop: + if (cam_cpas_stop(cdm_core->cpas_handle)) + CAM_ERR(CAM_CDM, "CPAS stop failed"); +cpas_unregister: + if (cam_cpas_unregister_client(cdm_core->cpas_handle)) + CAM_ERR(CAM_CDM, "CPAS unregister failed"); +release_platform_resource: + if (cam_soc_util_release_platform_resource(&cdm_hw->soc_info)) + CAM_ERR(CAM_CDM, "Release platform resource failed"); + + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); +destroy_non_secure_hdl: + cam_smmu_set_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + NULL, cdm_hw); + if (cam_smmu_destroy_handle(cdm_core->iommu_hdl.non_secure)) + CAM_ERR(CAM_CDM, "Release iommu secure hdl failed"); +unlock_release_mem: + mutex_unlock(&cdm_hw->hw_mutex); +release_private_mem: + kfree(cdm_hw->soc_info.soc_private); +release_mem: + mutex_destroy(&cdm_hw->hw_mutex); + kfree(cdm_hw_intf); + kfree(cdm_hw->core_info); + kfree(cdm_hw); + return rc; +} + +int cam_hw_cdm_remove(struct platform_device *pdev) +{ + int rc = -EBUSY; + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + + cdm_hw_intf = platform_get_drvdata(pdev); + if (!cdm_hw_intf) { + CAM_ERR(CAM_CDM, "Failed to get dev private data"); + return rc; + } + + cdm_hw = cdm_hw_intf->hw_priv; + if (!cdm_hw) { + CAM_ERR(CAM_CDM, + "Failed to get hw private data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + cdm_core = cdm_hw->core_info; + if (!cdm_core) { + CAM_ERR(CAM_CDM, + "Failed to get hw core data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + if (cdm_hw->open_count != 0) { + CAM_ERR(CAM_CDM, "Hw open count invalid type=%d idx=%d cnt=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx, + cdm_hw->open_count); + return rc; + } + + rc = cam_hw_cdm_deinit(cdm_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "Deinit failed for hw"); + return rc; + } + + rc = cam_cpas_unregister_client(cdm_core->cpas_handle); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS unregister failed"); + return rc; + } + + if (cam_soc_util_release_platform_resource(&cdm_hw->soc_info)) + CAM_ERR(CAM_CDM, "Release platform resource failed"); + + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); + + if (cam_smmu_destroy_handle(cdm_core->iommu_hdl.non_secure)) + CAM_ERR(CAM_CDM, "Release iommu secure hdl failed"); + cam_smmu_unset_client_page_fault_handler( + cdm_core->iommu_hdl.non_secure, cdm_hw); + + mutex_destroy(&cdm_hw->hw_mutex); + kfree(cdm_hw->soc_info.soc_private); + kfree(cdm_hw_intf); + kfree(cdm_hw->core_info); + kfree(cdm_hw); + + return 0; +} + +static struct platform_driver cam_hw_cdm_driver = { + .probe = cam_hw_cdm_probe, + .remove = cam_hw_cdm_remove, + .driver = { + .name = "msm_cam_cdm", + .owner = THIS_MODULE, + .of_match_table = msm_cam_hw_cdm_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_hw_cdm_init_module(void) +{ + return platform_driver_register(&cam_hw_cdm_driver); +} + +static void __exit cam_hw_cdm_exit_module(void) +{ + platform_driver_unregister(&cam_hw_cdm_driver); +} + +module_init(cam_hw_cdm_init_module); +module_exit(cam_hw_cdm_exit_module); +MODULE_DESCRIPTION("MSM Camera HW CDM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_cdm/cam_cdm_intf.c b/drivers/cam_cdm/cam_cdm_intf.c new file mode 100644 index 000000000000..94e2f36d0544 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_intf.c @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_virtual.h" +#include "cam_soc_util.h" +#include "cam_cdm_soc.h" + +static struct cam_cdm_intf_mgr cdm_mgr; +static DEFINE_MUTEX(cam_cdm_mgr_lock); + +static const struct of_device_id msm_cam_cdm_intf_dt_match[] = { + { .compatible = "qcom,cam-cdm-intf", }, + {} +}; + +static int get_cdm_mgr_refcount(void) +{ + int rc = 0; + + mutex_lock(&cam_cdm_mgr_lock); + if (cdm_mgr.probe_done == false) { + CAM_ERR(CAM_CDM, "CDM intf mgr not probed yet"); + rc = -EPERM; + } else { + CAM_DBG(CAM_CDM, "CDM intf mgr get refcount=%d", + cdm_mgr.refcount); + cdm_mgr.refcount++; + } + mutex_unlock(&cam_cdm_mgr_lock); + return rc; +} + +static void put_cdm_mgr_refcount(void) +{ + mutex_lock(&cam_cdm_mgr_lock); + if (cdm_mgr.probe_done == false) { + CAM_ERR(CAM_CDM, "CDM intf mgr not probed yet"); + } else { + CAM_DBG(CAM_CDM, "CDM intf mgr put refcount=%d", + cdm_mgr.refcount); + if (cdm_mgr.refcount > 0) { + cdm_mgr.refcount--; + } else { + CAM_ERR(CAM_CDM, "Refcount put when zero"); + WARN_ON(1); + } + } + mutex_unlock(&cam_cdm_mgr_lock); +} + +static int get_cdm_iommu_handle(struct cam_iommu_handle *cdm_handles, + uint32_t hw_idx) +{ + int rc = -EPERM; + struct cam_hw_intf *hw = cdm_mgr.nodes[hw_idx].device; + + if (hw->hw_ops.get_hw_caps) { + rc = hw->hw_ops.get_hw_caps(hw->hw_priv, cdm_handles, + sizeof(struct cam_iommu_handle)); + } + + return rc; +} + +static int get_cdm_index_by_id(char *identifier, + uint32_t cell_index, uint32_t *hw_index) +{ + int rc = -EPERM, i, j; + char client_name[128]; + + CAM_DBG(CAM_CDM, "Looking for HW id of =%s and index=%d", + identifier, cell_index); + snprintf(client_name, sizeof(client_name), "%s", identifier); + CAM_DBG(CAM_CDM, "Looking for HW id of %s count:%d", client_name, + cdm_mgr.cdm_count); + mutex_lock(&cam_cdm_mgr_lock); + for (i = 0; i < cdm_mgr.cdm_count; i++) { + mutex_lock(&cdm_mgr.nodes[i].lock); + CAM_DBG(CAM_CDM, "dt_num_supported_clients=%d", + cdm_mgr.nodes[i].data->dt_num_supported_clients); + + for (j = 0; j < + cdm_mgr.nodes[i].data->dt_num_supported_clients; j++) { + CAM_DBG(CAM_CDM, "client name:%s", + cdm_mgr.nodes[i].data->dt_cdm_client_name[j]); + if (!strcmp( + cdm_mgr.nodes[i].data->dt_cdm_client_name[j], + client_name)) { + rc = 0; + *hw_index = i; + break; + } + } + mutex_unlock(&cdm_mgr.nodes[i].lock); + if (rc == 0) + break; + } + mutex_unlock(&cam_cdm_mgr_lock); + + return rc; +} + +int cam_cdm_get_iommu_handle(char *identifier, + struct cam_iommu_handle *cdm_handles) +{ + int i, j, rc = -EPERM; + + if ((!identifier) || (!cdm_handles)) + return -EINVAL; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + CAM_DBG(CAM_CDM, "Looking for Iommu handle of %s", identifier); + + for (i = 0; i < cdm_mgr.cdm_count; i++) { + mutex_lock(&cdm_mgr.nodes[i].lock); + if (!cdm_mgr.nodes[i].data) { + mutex_unlock(&cdm_mgr.nodes[i].lock); + continue; + } + for (j = 0; j < + cdm_mgr.nodes[i].data->dt_num_supported_clients; + j++) { + if (!strcmp( + cdm_mgr.nodes[i].data->dt_cdm_client_name[j], + identifier)) { + rc = get_cdm_iommu_handle(cdm_handles, i); + break; + } + } + mutex_unlock(&cdm_mgr.nodes[i].lock); + if (rc == 0) + break; + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_get_iommu_handle); + +int cam_cdm_acquire(struct cam_cdm_acquire_data *data) +{ + int rc = -EPERM; + struct cam_hw_intf *hw; + uint32_t hw_index = 0; + + if ((!data) || (!data->base_array_cnt)) + return -EINVAL; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + if (data->id > CAM_CDM_HW_ANY) { + CAM_ERR(CAM_CDM, + "only CAM_CDM_VIRTUAL/CAM_CDM_HW_ANY is supported"); + rc = -EPERM; + goto end; + } + rc = get_cdm_index_by_id(data->identifier, data->cell_index, + &hw_index); + if ((rc < 0) && (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM)) { + CAM_ERR(CAM_CDM, "Failed to identify associated hw id"); + goto end; + } else { + CAM_DBG(CAM_CDM, "hw_index:%d", hw_index); + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_ACQUIRE, data, + sizeof(struct cam_cdm_acquire_data)); + if (rc < 0) { + CAM_ERR(CAM_CDM, "CDM hw acquire failed"); + goto end; + } + } else { + CAM_ERR(CAM_CDM, "idx %d doesn't have acquire ops", + hw_index); + rc = -EPERM; + } + } +end: + if (rc < 0) { + CAM_ERR(CAM_CDM, "CDM acquire failed for id=%d name=%s, idx=%d", + data->id, data->identifier, data->cell_index); + put_cdm_mgr_refcount(); + } + return rc; +} +EXPORT_SYMBOL(cam_cdm_acquire); + +int cam_cdm_release(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EPERM; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_RELEASE, &handle, + sizeof(handle)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "hw release failed for handle=%x", + handle); + } else + CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops", + hw_index); + } + put_cdm_mgr_refcount(); + if (rc == 0) + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_release); + + +int cam_cdm_submit_bls(uint32_t handle, struct cam_cdm_bl_request *data) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (!data) + return rc; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + struct cam_cdm_hw_intf_cmd_submit_bl req; + + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + req.data = data; + req.handle = handle; + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_SUBMIT_BL, &req, + sizeof(struct cam_cdm_hw_intf_cmd_submit_bl)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "hw submit bl failed for handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have submit ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_submit_bls); + +int cam_cdm_stream_on(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.start) { + rc = hw->hw_ops.start(hw->hw_priv, &handle, + sizeof(uint32_t)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "hw start failed handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, + "hw idx %d doesn't have start ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_stream_on); + +int cam_cdm_stream_off(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.stop) { + rc = hw->hw_ops.stop(hw->hw_priv, &handle, + sizeof(uint32_t)); + if (rc < 0) + CAM_ERR(CAM_CDM, "hw stop failed handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have stop ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_stream_off); + +int cam_cdm_reset_hw(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_RESET_HW, &handle, + sizeof(handle)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "CDM hw release failed for handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_reset_hw); + +int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t *index) +{ + int rc = -EINVAL; + + if ((!hw) || (!data) || (!index)) + return rc; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + mutex_lock(&cam_cdm_mgr_lock); + if ((type == CAM_VIRTUAL_CDM) && + (!cdm_mgr.nodes[CAM_SW_CDM_INDEX].device)) { + mutex_lock(&cdm_mgr.nodes[CAM_SW_CDM_INDEX].lock); + cdm_mgr.nodes[CAM_SW_CDM_INDEX].device = hw; + cdm_mgr.nodes[CAM_SW_CDM_INDEX].data = data; + *index = cdm_mgr.cdm_count; + mutex_unlock(&cdm_mgr.nodes[CAM_SW_CDM_INDEX].lock); + cdm_mgr.cdm_count++; + rc = 0; + } else if ((type == CAM_HW_CDM) && (cdm_mgr.cdm_count > 0)) { + mutex_lock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + cdm_mgr.nodes[cdm_mgr.cdm_count].device = hw; + cdm_mgr.nodes[cdm_mgr.cdm_count].data = data; + *index = cdm_mgr.cdm_count; + mutex_unlock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + cdm_mgr.cdm_count++; + rc = 0; + } else { + CAM_ERR(CAM_CDM, "CDM registration failed type=%d count=%d", + type, cdm_mgr.cdm_count); + } + mutex_unlock(&cam_cdm_mgr_lock); + put_cdm_mgr_refcount(); + + return rc; +} + +int cam_cdm_intf_deregister_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t index) +{ + int rc = -EINVAL; + + if ((!hw) || (!data)) + return rc; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + mutex_lock(&cam_cdm_mgr_lock); + if ((type == CAM_VIRTUAL_CDM) && + (hw == cdm_mgr.nodes[CAM_SW_CDM_INDEX].device) && + (index == CAM_SW_CDM_INDEX)) { + mutex_lock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + cdm_mgr.nodes[CAM_SW_CDM_INDEX].device = NULL; + cdm_mgr.nodes[CAM_SW_CDM_INDEX].data = NULL; + mutex_unlock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + rc = 0; + } else if ((type == CAM_HW_CDM) && + (hw == cdm_mgr.nodes[index].device)) { + mutex_lock(&cdm_mgr.nodes[index].lock); + cdm_mgr.nodes[index].device = NULL; + cdm_mgr.nodes[index].data = NULL; + mutex_unlock(&cdm_mgr.nodes[index].lock); + cdm_mgr.cdm_count--; + rc = 0; + } else { + CAM_ERR(CAM_CDM, "CDM Deregistration failed type=%d index=%d", + type, index); + } + mutex_unlock(&cam_cdm_mgr_lock); + put_cdm_mgr_refcount(); + + return rc; +} + +static int cam_cdm_intf_probe(struct platform_device *pdev) +{ + int i, rc; + + rc = cam_cdm_intf_mgr_soc_get_dt_properties(pdev, &cdm_mgr); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to get dt properties"); + return rc; + } + mutex_lock(&cam_cdm_mgr_lock); + for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) { + mutex_init(&cdm_mgr.nodes[i].lock); + cdm_mgr.nodes[i].device = NULL; + cdm_mgr.nodes[i].data = NULL; + cdm_mgr.nodes[i].refcount = 0; + } + cdm_mgr.probe_done = true; + cdm_mgr.refcount = 0; + mutex_unlock(&cam_cdm_mgr_lock); + rc = cam_virtual_cdm_probe(pdev); + if (rc) { + mutex_lock(&cam_cdm_mgr_lock); + cdm_mgr.probe_done = false; + for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) { + if (cdm_mgr.nodes[i].device || cdm_mgr.nodes[i].data || + (cdm_mgr.nodes[i].refcount != 0)) + CAM_ERR(CAM_CDM, + "Valid node present in index=%d", i); + mutex_destroy(&cdm_mgr.nodes[i].lock); + cdm_mgr.nodes[i].device = NULL; + cdm_mgr.nodes[i].data = NULL; + cdm_mgr.nodes[i].refcount = 0; + } + mutex_unlock(&cam_cdm_mgr_lock); + } + + CAM_DBG(CAM_CDM, "CDM Intf probe done"); + + return rc; +} + +static int cam_cdm_intf_remove(struct platform_device *pdev) +{ + int i, rc = -EBUSY; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + if (cam_virtual_cdm_remove(pdev)) { + CAM_ERR(CAM_CDM, "Virtual CDM remove failed"); + goto end; + } + put_cdm_mgr_refcount(); + + mutex_lock(&cam_cdm_mgr_lock); + if (cdm_mgr.refcount != 0) { + CAM_ERR(CAM_CDM, "cdm manger refcount not zero %d", + cdm_mgr.refcount); + goto end; + } + + for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) { + if (cdm_mgr.nodes[i].device || cdm_mgr.nodes[i].data || + (cdm_mgr.nodes[i].refcount != 0)) { + CAM_ERR(CAM_CDM, "Valid node present in index=%d", i); + mutex_unlock(&cam_cdm_mgr_lock); + goto end; + } + mutex_destroy(&cdm_mgr.nodes[i].lock); + cdm_mgr.nodes[i].device = NULL; + cdm_mgr.nodes[i].data = NULL; + cdm_mgr.nodes[i].refcount = 0; + } + cdm_mgr.probe_done = false; + rc = 0; + +end: + mutex_unlock(&cam_cdm_mgr_lock); + return rc; +} + +static struct platform_driver cam_cdm_intf_driver = { + .probe = cam_cdm_intf_probe, + .remove = cam_cdm_intf_remove, + .driver = { + .name = "msm_cam_cdm_intf", + .owner = THIS_MODULE, + .of_match_table = msm_cam_cdm_intf_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_cdm_intf_init_module(void) +{ + return platform_driver_register(&cam_cdm_intf_driver); +} + +static void __exit cam_cdm_intf_exit_module(void) +{ + platform_driver_unregister(&cam_cdm_intf_driver); +} + +module_init(cam_cdm_intf_init_module); +module_exit(cam_cdm_intf_exit_module); +MODULE_DESCRIPTION("MSM Camera CDM Intf driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_cdm/cam_cdm_intf_api.h b/drivers/cam_cdm/cam_cdm_intf_api.h new file mode 100644 index 000000000000..3e89b22b1b18 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_intf_api.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_API_H_ +#define _CAM_CDM_API_H_ + +#include +#include "cam_cdm_util.h" +#include "cam_soc_util.h" + +/* enum cam_cdm_id - Enum for possible CAM CDM hardwares */ +enum cam_cdm_id { + CAM_CDM_VIRTUAL, + CAM_CDM_HW_ANY, + CAM_CDM_CPAS_0, + CAM_CDM_IPE0, + CAM_CDM_IPE1, + CAM_CDM_BPS, + CAM_CDM_VFE, + CAM_CDM_MAX +}; + +/* enum cam_cdm_cb_status - Enum for possible CAM CDM callback */ +enum cam_cdm_cb_status { + CAM_CDM_CB_STATUS_BL_SUCCESS, + CAM_CDM_CB_STATUS_INVALID_BL_CMD, + CAM_CDM_CB_STATUS_PAGEFAULT, + CAM_CDM_CB_STATUS_HW_RESET_ONGOING, + CAM_CDM_CB_STATUS_HW_RESET_DONE, + CAM_CDM_CB_STATUS_UNKNOWN_ERROR, +}; + +/* enum cam_cdm_bl_cmd_addr_type - Enum for possible CDM bl cmd addr types */ +enum cam_cdm_bl_cmd_addr_type { + CAM_CDM_BL_CMD_TYPE_MEM_HANDLE, + CAM_CDM_BL_CMD_TYPE_HW_IOVA, + CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA, +}; + +/** + * struct cam_cdm_acquire_data - Cam CDM acquire data structure + * + * @identifier : Input identifier string which is the device label from dt + * like vfe, ife, jpeg etc + * @cell_index : Input integer identifier pointing to the cell index from dt + * of the device. This can be used to form a unique string + * with @identifier like vfe0, ife1, jpeg0 etc + * @id : ID of a specific or any CDM HW which needs to be acquired. + * @userdata : Input private data which will be returned as part + * of callback. + * @cam_cdm_callback : Input callback pointer for triggering the + * callbacks from CDM driver + * @handle : CDM Client handle + * @userdata : Private data given at the time of acquire + * @status : Callback status + * @cookie : Cookie if the callback is gen irq status + * @base_array_cnt : Input number of ioremapped address pair pointing + * in base_array, needed only if selected cdm is a virtual. + * @base_array : Input pointer to ioremapped address pair arrary + * needed only if selected cdm is a virtual. + * @cdm_version : CDM version is output while acquiring HW cdm and + * it is Input while acquiring virtual cdm, Currently fixing it + * to one version below acquire API. + * @ops : Output pointer updated by cdm driver to the CDM + * util ops for this HW version of CDM acquired. + * @handle : Output Unique handle generated for this acquire + * + */ +struct cam_cdm_acquire_data { + char identifier[128]; + uint32_t cell_index; + enum cam_cdm_id id; + void *userdata; + void (*cam_cdm_callback)(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie); + uint32_t base_array_cnt; + struct cam_soc_reg_map *base_array[CAM_SOC_MAX_BLOCK]; + struct cam_hw_version cdm_version; + struct cam_cdm_utils_ops *ops; + uint32_t handle; +}; + +/** + * struct cam_cdm_bl_cmd - Cam CDM HW bl command + * + * @bl_addr : Union of all three type for CDM BL commands + * @mem_handle : Input mem handle of bl cmd + * @offset : Input offset of the actual bl cmd in the memory pointed + * by mem_handle + * @len : Input length of the BL command, Cannot be more than 1MB and + * this is will be validated with offset+size of the memory pointed + * by mem_handle + * + */ +struct cam_cdm_bl_cmd { + union { + int32_t mem_handle; + uint32_t *hw_iova; + uintptr_t kernel_iova; + } bl_addr; + uint32_t offset; + uint32_t len; +}; + +/** + * struct cam_cdm_bl_request - Cam CDM HW base & length (BL) request + * + * @flag : 1 for callback needed and 0 for no callback when this BL + * request is done + * @userdata :Input private data which will be returned as part + * of callback if request for this bl request in flags. + * @cookie : Cookie if the callback is gen irq status + * @type : type of the submitted bl cmd address. + * @cmd_arrary_count : Input number of BL commands to be submitted to CDM + * @bl_cmd_array : Input payload holding the BL cmd's arrary + * to be sumbitted. + * + */ +struct cam_cdm_bl_request { + int flag; + void *userdata; + uint64_t cookie; + enum cam_cdm_bl_cmd_addr_type type; + uint32_t cmd_arrary_count; + struct cam_cdm_bl_cmd cmd[1]; +}; + +/** + * @brief : API to get the CDM capabilities for a camera device type + * + * @identifier : Input pointer to a string which is the device label from dt + * like vfe, ife, jpeg etc, We do not need cell index + * assuming all devices of a single type maps to one SMMU + * client + * @cdm_handles : Input iommu handle memory pointer to update handles + * + * @return 0 on success + */ +int cam_cdm_get_iommu_handle(char *identifier, + struct cam_iommu_handle *cdm_handles); + +/** + * @brief : API to acquire a CDM + * + * @data : Input data for the CDM to be acquired + * + * @return 0 on success + */ +int cam_cdm_acquire(struct cam_cdm_acquire_data *data); + +/** + * @brief : API to release a previously acquired CDM + * + * @handle : Input handle for the CDM to be released + * + * @return 0 on success + */ +int cam_cdm_release(uint32_t handle); + +/** + * @brief : API to submit the base & length (BL's) for acquired CDM + * + * @handle : Input cdm handle to which the BL's needs to be sumbitted. + * @data : Input pointer to the BL's to be sumbitted + * + * @return 0 on success + */ +int cam_cdm_submit_bls(uint32_t handle, struct cam_cdm_bl_request *data); + +/** + * @brief : API to stream ON a previously acquired CDM, + * during this we turn on/off clocks/power based on active clients. + * + * @handle : Input handle for the CDM to be released + * + * @return 0 on success + */ +int cam_cdm_stream_on(uint32_t handle); + +/** + * @brief : API to stream OFF a previously acquired CDM, + * during this we turn on/off clocks/power based on active clients. + * + * @handle : Input handle for the CDM to be released + * + * @return 0 on success + */ +int cam_cdm_stream_off(uint32_t handle); + +/** + * @brief : API to reset previously acquired CDM, + * this can be only performed only the CDM is private. + * + * @handle : Input handle of the CDM to reset + * + * @return 0 on success + */ +int cam_cdm_reset_hw(uint32_t handle); + +#endif /* _CAM_CDM_API_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_soc.c b/drivers/cam_cdm/cam_cdm_soc.c new file mode 100644 index 000000000000..2fb5d5fe97b9 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_soc.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_cdm.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" + +#define CAM_CDM_OFFSET_FROM_REG(x, y) ((x)->offsets[y].offset) +#define CAM_CDM_ATTR_FROM_REG(x, y) ((x)->offsets[y].attribute) + +bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t *value) +{ + void __iomem *reg_addr; + struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info; + void __iomem *base = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base; + resource_size_t mem_len = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size; + + CAM_DBG(CAM_CDM, "E: b=%pK blen=%d reg=%x off=%x", (void __iomem *)base, + (int)mem_len, reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, + reg))); + CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x", (void __iomem *)base, + reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg))); + + if ((reg > cdm->offset_tbl->offset_max_size) || + (reg > cdm->offset_tbl->last_offset)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Invalid reg=%d\n", reg); + goto permission_error; + } else { + reg_addr = (base + (CAM_CDM_OFFSET_FROM_REG( + cdm->offset_tbl, reg))); + if (reg_addr > (base + mem_len)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Invalid mapped region %d", reg); + goto permission_error; + } + *value = cam_io_r_mb(reg_addr); + CAM_DBG(CAM_CDM, "X b=%pK reg=%x off=%x val=%x", + (void __iomem *)base, reg, + (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)), + *value); + return false; + } +permission_error: + *value = 0; + return true; + +} + +bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t value) +{ + void __iomem *reg_addr; + struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info; + void __iomem *base = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base; + resource_size_t mem_len = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size; + + CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x val=%x", (void __iomem *)base, + reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)), value); + + if ((reg > cdm->offset_tbl->offset_max_size) || + (reg > cdm->offset_tbl->last_offset)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "CDM accessing invalid reg=%d\n", + reg); + goto permission_error; + } else { + reg_addr = (base + CAM_CDM_OFFSET_FROM_REG( + cdm->offset_tbl, reg)); + if (reg_addr > (base + mem_len)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Accessing invalid region %d:%d\n", + reg, (CAM_CDM_OFFSET_FROM_REG( + cdm->offset_tbl, reg))); + goto permission_error; + } + cam_io_w_mb(value, reg_addr); + return false; + } +permission_error: + return true; + +} + +int cam_cdm_soc_load_dt_private(struct platform_device *pdev, + struct cam_cdm_private_dt_data *ptr) +{ + int i, rc = -EINVAL; + + ptr->dt_num_supported_clients = of_property_count_strings( + pdev->dev.of_node, + "cdm-client-names"); + CAM_DBG(CAM_CDM, "Num supported cdm_client = %d", + ptr->dt_num_supported_clients); + if (ptr->dt_num_supported_clients > + CAM_PER_CDM_MAX_REGISTERED_CLIENTS) { + CAM_ERR(CAM_CDM, "Invalid count of client names count=%d", + ptr->dt_num_supported_clients); + rc = -EINVAL; + return rc; + } + if (ptr->dt_num_supported_clients < 0) { + CAM_DBG(CAM_CDM, "No cdm client names found"); + ptr->dt_num_supported_clients = 0; + ptr->dt_cdm_shared = false; + } else { + ptr->dt_cdm_shared = true; + } + for (i = 0; i < ptr->dt_num_supported_clients; i++) { + rc = of_property_read_string_index(pdev->dev.of_node, + "cdm-client-names", i, &(ptr->dt_cdm_client_name[i])); + CAM_DBG(CAM_CDM, "cdm-client-names[%d] = %s", i, + ptr->dt_cdm_client_name[i]); + if (rc < 0) { + CAM_ERR(CAM_CDM, "Reading cdm-client-names failed"); + break; + } + } + + return rc; +} + +int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, + const struct of_device_id *table) +{ + int rc; + struct cam_hw_soc_info *soc_ptr; + const struct of_device_id *id; + + if (!cdm_hw || (cdm_hw->soc_info.soc_private) + || !(cdm_hw->soc_info.pdev)) + return -EINVAL; + + soc_ptr = &cdm_hw->soc_info; + + rc = cam_soc_util_get_dt_properties(soc_ptr); + if (rc != 0) { + CAM_ERR(CAM_CDM, "Failed to retrieve the CDM dt properties"); + } else { + soc_ptr->soc_private = kzalloc( + sizeof(struct cam_cdm_private_dt_data), + GFP_KERNEL); + if (!soc_ptr->soc_private) + return -ENOMEM; + + rc = cam_cdm_soc_load_dt_private(soc_ptr->pdev, + soc_ptr->soc_private); + if (rc != 0) { + CAM_ERR(CAM_CDM, "Failed to load CDM dt private data"); + goto error; + } + id = of_match_node(table, soc_ptr->pdev->dev.of_node); + if ((!id) || !(id->data)) { + CAM_ERR(CAM_CDM, "Failed to retrieve the CDM id table"); + goto error; + } + CAM_DBG(CAM_CDM, "CDM Hw Id compatible =%s", id->compatible); + ((struct cam_cdm *)cdm_hw->core_info)->offset_tbl = + (struct cam_cdm_reg_offset_table *)id->data; + strlcpy(((struct cam_cdm *)cdm_hw->core_info)->name, + id->compatible, + sizeof(((struct cam_cdm *)cdm_hw->core_info)->name)); + } + + return rc; + +error: + rc = -EINVAL; + kfree(soc_ptr->soc_private); + soc_ptr->soc_private = NULL; + return rc; +} + +int cam_cdm_intf_mgr_soc_get_dt_properties( + struct platform_device *pdev, struct cam_cdm_intf_mgr *mgr) +{ + int rc; + + rc = of_property_read_u32(pdev->dev.of_node, + "num-hw-cdm", &mgr->dt_supported_hw_cdm); + CAM_DBG(CAM_CDM, "Number of HW cdm supported =%d", + mgr->dt_supported_hw_cdm); + + return rc; +} diff --git a/drivers/cam_cdm/cam_cdm_soc.h b/drivers/cam_cdm/cam_cdm_soc.h new file mode 100644 index 000000000000..b422b34f244b --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_soc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_SOC_H_ +#define _CAM_CDM_SOC_H_ + +int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, + const struct of_device_id *table); +bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t *value); +bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t value); +int cam_cdm_intf_mgr_soc_get_dt_properties( + struct platform_device *pdev, + struct cam_cdm_intf_mgr *mgr); +int cam_cdm_soc_load_dt_private(struct platform_device *pdev, + struct cam_cdm_private_dt_data *ptr); + +#endif /* _CAM_CDM_SOC_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_util.c b/drivers/cam_cdm/cam_cdm_util.c new file mode 100644 index 000000000000..278dadb18db4 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_util.c @@ -0,0 +1,717 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_cdm_intf_api.h" +#include "cam_cdm_util.h" +#include "cam_cdm.h" +#include "cam_io_util.h" + +#define CAM_CDM_DWORD 4 + +#define CAM_CDM_SW_CMD_COUNT 2 +#define CAM_CMD_LENGTH_MASK 0xFFFF +#define CAM_CDM_COMMAND_OFFSET 24 +#define CAM_CDM_REG_OFFSET_MASK 0x00FFFFFF + +#define CAM_CDM_DMI_DATA_HI_OFFSET 8 +#define CAM_CDM_DMI_DATA_OFFSET 8 +#define CAM_CDM_DMI_DATA_LO_OFFSET 12 + +static unsigned int CDMCmdHeaderSizes[ + CAM_CDM_CMD_PRIVATE_BASE + CAM_CDM_SW_CMD_COUNT] = { + 0, /* UNUSED*/ + 3, /* DMI*/ + 0, /* UNUSED*/ + 2, /* RegContinuous*/ + 1, /* RegRandom*/ + 2, /* BUFFER_INDIREC*/ + 2, /* GenerateIRQ*/ + 3, /* WaitForEvent*/ + 1, /* ChangeBase*/ + 1, /* PERF_CONTROL*/ + 3, /* DMI32*/ + 3, /* DMI64*/ +}; + +/** + * struct cdm_regrandom_cmd - Definition for CDM random register command. + * @count: Number of register writes + * @reserved: reserved bits + * @cmd: Command ID (CDMCmd) + */ +struct cdm_regrandom_cmd { + unsigned int count : 16; + unsigned int reserved : 8; + unsigned int cmd : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_regcontinuous_cmd - Definition for a CDM register range command. + * @count: Number of register writes + * @reserved0: reserved bits + * @cmd: Command ID (CDMCmd) + * @offset: Start address of the range of registers + * @reserved1: reserved bits + */ +struct cdm_regcontinuous_cmd { + unsigned int count : 16; + unsigned int reserved0 : 8; + unsigned int cmd : 8; + unsigned int offset : 24; + unsigned int reserved1 : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_dmi_cmd - Definition for a CDM DMI command. + * @length: Number of bytes in LUT - 1 + * @reserved: reserved bits + * @cmd: Command ID (CDMCmd) + * @addr: Address of the LUT in memory + * @DMIAddr: Address of the target DMI config register + * @DMISel: DMI identifier + */ +struct cdm_dmi_cmd { + unsigned int length : 16; + unsigned int reserved : 8; + unsigned int cmd : 8; + unsigned int addr; + unsigned int DMIAddr : 24; + unsigned int DMISel : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_indirect_cmd - Definition for a CDM indirect buffer command. + * @length: Number of bytes in buffer - 1 + * @reserved: reserved bits + * @cmd: Command ID (CDMCmd) + * @addr: Device address of the indirect buffer + */ +struct cdm_indirect_cmd { + unsigned int length : 16; + unsigned int reserved : 8; + unsigned int cmd : 8; + unsigned int addr; +} __attribute__((__packed__)); + +/** + * struct cdm_changebase_cmd - Definition for CDM base address change command. + * @base: Base address to be changed to + * @cmd:Command ID (CDMCmd) + */ +struct cdm_changebase_cmd { + unsigned int base : 24; + unsigned int cmd : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_wait_event_cmd - Definition for a CDM Gen IRQ command. + * @mask: Mask for the events + * @id: ID to read back for debug + * @iw_reserved: reserved bits + * @iw: iw AHB write bit + * @cmd:Command ID (CDMCmd) + * @offset: Offset to where data is written + * @offset_reserved: reserved bits + * @data: data returned in IRQ_USR_DATA + */ +struct cdm_wait_event_cmd { + unsigned int mask : 8; + unsigned int id : 8; + unsigned int iw_reserved : 7; + unsigned int iw : 1; + unsigned int cmd : 8; + unsigned int offset : 24; + unsigned int offset_reserved : 8; + unsigned int data; +} __attribute__((__packed__)); + +/** + * struct cdm_genirq_cmd - Definition for a CDM Wait event command. + * @reserved: reserved bits + * @cmd:Command ID (CDMCmd) + * @userdata: userdata returned in IRQ_USR_DATA + */ +struct cdm_genirq_cmd { + unsigned int reserved : 24; + unsigned int cmd : 8; + unsigned int userdata; +} __attribute__((__packed__)); + +/** + * struct cdm_perf_ctrl_cmd_t - Definition for CDM perf control command. + * @perf: perf command + * @reserved: reserved bits + * @cmd:Command ID (CDMCmd) + */ +struct cdm_perf_ctrl_cmd { + unsigned int perf : 2; + unsigned int reserved : 22; + unsigned int cmd : 8; +} __attribute__((__packed__)); + +uint32_t cdm_get_cmd_header_size(unsigned int command) +{ + return CDMCmdHeaderSizes[command]; +} + +uint32_t cdm_required_size_reg_continuous(uint32_t numVals) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT) + numVals; +} + +uint32_t cdm_required_size_reg_random(uint32_t numRegVals) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM) + + (2 * numRegVals); +} + +uint32_t cdm_required_size_dmi(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); +} + +uint32_t cdm_required_size_genirq(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_GEN_IRQ); +} + +uint32_t cdm_required_size_indirect(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT); +} + +uint32_t cdm_required_size_changebase(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE); +} + +uint32_t cdm_offsetof_dmi_addr(void) +{ + return offsetof(struct cdm_dmi_cmd, addr); +} + +uint32_t cdm_offsetof_indirect_addr(void) +{ + return offsetof(struct cdm_indirect_cmd, addr); +} + +uint32_t *cdm_write_regcontinuous(uint32_t *pCmdBuffer, uint32_t reg, + uint32_t numVals, uint32_t *pVals) +{ + uint32_t i; + struct cdm_regcontinuous_cmd *pHeader = + (struct cdm_regcontinuous_cmd *)pCmdBuffer; + + pHeader->count = numVals; + pHeader->cmd = CAM_CDM_CMD_REG_CONT; + pHeader->reserved0 = 0; + pHeader->reserved1 = 0; + pHeader->offset = reg; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + + for (i = 0; i < numVals; i++) + (((uint32_t *)pCmdBuffer)[i]) = (((uint32_t *)pVals)[i]); + + pCmdBuffer += numVals; + + return pCmdBuffer; +} + +uint32_t *cdm_write_regrandom(uint32_t *pCmdBuffer, uint32_t numRegVals, + uint32_t *pRegVals) +{ + uint32_t i; + uint32_t *dst, *src; + struct cdm_regrandom_cmd *pHeader = + (struct cdm_regrandom_cmd *)pCmdBuffer; + + pHeader->count = numRegVals; + pHeader->cmd = CAM_CDM_CMD_REG_RANDOM; + pHeader->reserved = 0; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + dst = pCmdBuffer; + src = pRegVals; + for (i = 0; i < numRegVals; i++) { + *dst++ = *src++; + *dst++ = *src++; + } + + return dst; +} + +uint32_t *cdm_write_dmi(uint32_t *pCmdBuffer, uint8_t dmiCmd, + uint32_t DMIAddr, uint8_t DMISel, uint32_t dmiBufferAddr, + uint32_t length) +{ + struct cdm_dmi_cmd *pHeader = (struct cdm_dmi_cmd *)pCmdBuffer; + + pHeader->cmd = dmiCmd; + pHeader->addr = dmiBufferAddr; + pHeader->length = length - 1; + pHeader->DMIAddr = DMIAddr; + pHeader->DMISel = DMISel; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); + + return pCmdBuffer; +} + +uint32_t *cdm_write_indirect(uint32_t *pCmdBuffer, uint32_t indirectBufAddr, + uint32_t length) +{ + struct cdm_indirect_cmd *pHeader = + (struct cdm_indirect_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CMD_BUFF_INDIRECT; + pHeader->addr = indirectBufAddr; + pHeader->length = length - 1; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT); + + return pCmdBuffer; +} + +uint32_t *cdm_write_changebase(uint32_t *pCmdBuffer, uint32_t base) +{ + struct cdm_changebase_cmd *pHeader = + (struct cdm_changebase_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CMD_CHANGE_BASE; + pHeader->base = base; + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE); + + return pCmdBuffer; +} + +void cdm_write_genirq(uint32_t *pCmdBuffer, uint32_t userdata) +{ + struct cdm_genirq_cmd *pHeader = (struct cdm_genirq_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CMD_GEN_IRQ; + pHeader->userdata = userdata; +} + +struct cam_cdm_utils_ops CDM170_ops = { + cdm_get_cmd_header_size, + cdm_required_size_reg_continuous, + cdm_required_size_reg_random, + cdm_required_size_dmi, + cdm_required_size_genirq, + cdm_required_size_indirect, + cdm_required_size_changebase, + cdm_offsetof_dmi_addr, + cdm_offsetof_indirect_addr, + cdm_write_regcontinuous, + cdm_write_regrandom, + cdm_write_dmi, + cdm_write_indirect, + cdm_write_changebase, + cdm_write_genirq, +}; + +int cam_cdm_get_ioremap_from_base(uint32_t hw_base, + uint32_t base_array_size, + struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK], + void __iomem **device_base) +{ + int ret = -EINVAL, i; + + for (i = 0; i < base_array_size; i++) { + if (base_table[i]) + CAM_DBG(CAM_CDM, "In loop %d ioremap for %x addr=%x", + i, (base_table[i])->mem_cam_base, hw_base); + if ((base_table[i]) && + ((base_table[i])->mem_cam_base == hw_base)) { + *device_base = (base_table[i])->mem_base; + ret = 0; + break; + } + } + + return ret; +} + +static int cam_cdm_util_reg_cont_write(void __iomem *base_addr, + uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes) +{ + int ret = 0; + uint32_t *data; + struct cdm_regcontinuous_cmd *reg_cont; + + if ((cmd_buf_size < cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) || + (!base_addr)) { + CAM_ERR(CAM_CDM, "invalid base addr and data length %d %pK", + cmd_buf_size, base_addr); + return -EINVAL; + } + + reg_cont = (struct cdm_regcontinuous_cmd *)cmd_buf; + if ((!reg_cont->count) || (reg_cont->count > 0x10000) || + (((reg_cont->count * sizeof(uint32_t)) + + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) > + cmd_buf_size)) { + CAM_ERR(CAM_CDM, "buffer size %d is not sufficient for count%d", + cmd_buf_size, reg_cont->count); + return -EINVAL; + } + data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + cam_io_memcpy(base_addr + reg_cont->offset, data, + reg_cont->count * sizeof(uint32_t)); + + *used_bytes = (reg_cont->count * sizeof(uint32_t)) + + (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)); + + return ret; +} + +static int cam_cdm_util_reg_random_write(void __iomem *base_addr, + uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes) +{ + uint32_t i; + struct cdm_regrandom_cmd *reg_random; + uint32_t *data; + + if (!base_addr) { + CAM_ERR(CAM_CDM, "invalid base address"); + return -EINVAL; + } + + reg_random = (struct cdm_regrandom_cmd *) cmd_buf; + if ((!reg_random->count) || (reg_random->count > 0x10000) || + (((reg_random->count * (sizeof(uint32_t) * 2)) + + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM)) > + cmd_buf_size)) { + CAM_ERR(CAM_CDM, "invalid reg_count %d cmd_buf_size %d", + reg_random->count, cmd_buf_size); + return -EINVAL; + } + data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + + for (i = 0; i < reg_random->count; i++) { + CAM_DBG(CAM_CDM, "reg random: offset %pK, value 0x%x", + ((void __iomem *)(base_addr + data[0])), + data[1]); + cam_io_w(data[1], base_addr + data[0]); + data += 2; + } + + *used_bytes = ((reg_random->count * (sizeof(uint32_t) * 2)) + + (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM))); + + return 0; +} + +static int cam_cdm_util_swd_dmi_write(uint32_t cdm_cmd_type, + void __iomem *base_addr, uint32_t *cmd_buf, uint32_t cmd_buf_size, + uint32_t *used_bytes) +{ + uint32_t i; + struct cdm_dmi_cmd *swd_dmi; + uint32_t *data; + + swd_dmi = (struct cdm_dmi_cmd *)cmd_buf; + + if (cmd_buf_size < (cdm_required_size_dmi() + swd_dmi->length + 1)) { + CAM_ERR(CAM_CDM, "invalid CDM_SWD_DMI length %d", + swd_dmi->length + 1); + return -EINVAL; + } + data = cmd_buf + cdm_required_size_dmi(); + + if (cdm_cmd_type == CAM_CDM_CMD_SWD_DMI_64) { + for (i = 0; i < (swd_dmi->length + 1)/8; i++) { + cam_io_w_mb(data[0], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET); + cam_io_w_mb(data[1], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_HI_OFFSET); + data += 2; + } + } else if (cdm_cmd_type == CAM_CDM_CMD_DMI) { + for (i = 0; i < (swd_dmi->length + 1)/4; i++) { + cam_io_w_mb(data[0], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_OFFSET); + data += 1; + } + } else { + for (i = 0; i < (swd_dmi->length + 1)/4; i++) { + cam_io_w_mb(data[0], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET); + data += 1; + } + } + *used_bytes = (4 * cdm_required_size_dmi()) + swd_dmi->length + 1; + + return 0; +} + +int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base, + uint32_t *cmd_buf, uint32_t cmd_buf_size, + struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK], + uint32_t base_array_size, uint8_t bl_tag) +{ + int ret = 0; + uint32_t cdm_cmd_type = 0, total_cmd_buf_size = 0; + uint32_t used_bytes = 0; + + total_cmd_buf_size = cmd_buf_size; + + while (cmd_buf_size > 0) { + CAM_DBG(CAM_CDM, "cmd data=%x", *cmd_buf); + cdm_cmd_type = (*cmd_buf >> CAM_CDM_COMMAND_OFFSET); + switch (cdm_cmd_type) { + case CAM_CDM_CMD_REG_CONT: { + ret = cam_cdm_util_reg_cont_write(*current_device_base, + cmd_buf, cmd_buf_size, &used_bytes); + if (ret) + break; + + if (used_bytes > 0) { + cmd_buf_size -= used_bytes; + cmd_buf += used_bytes/4; + } + } + break; + case CAM_CDM_CMD_REG_RANDOM: { + ret = cam_cdm_util_reg_random_write( + *current_device_base, cmd_buf, cmd_buf_size, + &used_bytes); + if (ret) + break; + + if (used_bytes > 0) { + cmd_buf_size -= used_bytes; + cmd_buf += used_bytes / 4; + } + } + break; + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_SWD_DMI_32: + case CAM_CDM_CMD_SWD_DMI_64: { + if (*current_device_base == 0) { + CAM_ERR(CAM_CDM, + "Got SWI DMI cmd =%d for invalid hw", + cdm_cmd_type); + ret = -EINVAL; + break; + } + ret = cam_cdm_util_swd_dmi_write(cdm_cmd_type, + *current_device_base, cmd_buf, cmd_buf_size, + &used_bytes); + if (ret) + break; + + if (used_bytes > 0) { + cmd_buf_size -= used_bytes; + cmd_buf += used_bytes / 4; + } + } + break; + case CAM_CDM_CMD_CHANGE_BASE: { + struct cdm_changebase_cmd *change_base_cmd = + (struct cdm_changebase_cmd *)cmd_buf; + + ret = cam_cdm_get_ioremap_from_base( + change_base_cmd->base, base_array_size, + base_table, current_device_base); + if (ret != 0) { + CAM_ERR(CAM_CDM, + "Get ioremap change base failed %x", + change_base_cmd->base); + break; + } + CAM_DBG(CAM_CDM, "Got ioremap for %x addr=%pK", + change_base_cmd->base, + current_device_base); + cmd_buf_size -= (4 * + cdm_required_size_changebase()); + cmd_buf += cdm_required_size_changebase(); + } + break; + default: + CAM_ERR(CAM_CDM, "unsupported cdm_cmd_type type 0%x", + cdm_cmd_type); + ret = -EINVAL; + break; + } + + if (ret < 0) + break; + } + + return ret; +} + +static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI]; + CAM_INFO(CAM_CDM, "DMI"); + return ret; +} + +static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT]; + CAM_INFO(CAM_CDM, "Buff Indirect"); + return ret; +} + +static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_regcontinuous_cmd *p_regcont_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + int i = 0; + + p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + + CAM_INFO(CAM_CDM, "REG_CONT: COUNT: %u OFFSET: 0x%X", + p_regcont_cmd->count, p_regcont_cmd->offset); + + for (i = 0; i < p_regcont_cmd->count; i++) { + CAM_INFO(CAM_CDM, "DATA_%d: 0x%X", i, + *temp_ptr); + temp_ptr++; + ret++; + } + + return ret; +} + +static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr) +{ + struct cdm_regrandom_cmd *p_regrand_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + long ret = 0; + int i = 0; + + p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + + CAM_INFO(CAM_CDM, "REG_RAND: COUNT: %u", + p_regrand_cmd->count); + + for (i = 0; i < p_regrand_cmd->count; i++) { + CAM_INFO(CAM_CDM, "OFFSET_%d: 0x%X DATA_%d: 0x%X", + i, *temp_ptr & CAM_CDM_REG_OFFSET_MASK, i, + *(temp_ptr + 1)); + temp_ptr += 2; + ret += 2; + } + + return ret; +} + +static long cam_cdm_util_dump_gen_irq_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ]; + + CAM_INFO(CAM_CDM, "GEN_IRQ"); + + return ret; +} + +static long cam_cdm_util_dump_wait_event_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT]; + + CAM_INFO(CAM_CDM, "WAIT_EVENT"); + + return ret; +} + +static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_changebase_cmd *p_cbase_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + + p_cbase_cmd = (struct cdm_changebase_cmd *)temp_ptr; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE]; + + CAM_INFO(CAM_CDM, "CHANGE_BASE: 0x%X", + p_cbase_cmd->base); + + return ret; +} + +static long cam_cdm_util_dump_perf_ctrl_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL]; + + CAM_INFO(CAM_CDM, "PERF_CTRL"); + + return ret; +} + +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buf_start, uint32_t *cmd_buf_end) +{ + uint32_t *buf_now = cmd_buf_start; + uint32_t cmd = 0; + + if (!cmd_buf_start || !cmd_buf_end) { + CAM_INFO(CAM_CDM, "Invalid args"); + return; + } + + do { + cmd = *buf_now; + cmd = cmd >> CAM_CDM_COMMAND_OFFSET; + + switch (cmd) { + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_DMI_32: + case CAM_CDM_CMD_DMI_64: + buf_now += cam_cdm_util_dump_dmi_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_CONT: + buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_RANDOM: + buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now); + break; + case CAM_CDM_CMD_BUFF_INDIRECT: + buf_now += cam_cdm_util_dump_buff_indirect(buf_now); + break; + case CAM_CDM_CMD_GEN_IRQ: + buf_now += cam_cdm_util_dump_gen_irq_cmd(buf_now); + break; + case CAM_CDM_CMD_WAIT_EVENT: + buf_now += cam_cdm_util_dump_wait_event_cmd(buf_now); + break; + case CAM_CDM_CMD_CHANGE_BASE: + buf_now += cam_cdm_util_dump_change_base_cmd(buf_now); + break; + case CAM_CDM_CMD_PERF_CTRL: + buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now); + break; + default: + CAM_INFO(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x", + cmd, *buf_now); + buf_now++; + break; + } + } while (buf_now <= cmd_buf_end); +} diff --git a/drivers/cam_cdm/cam_cdm_util.h b/drivers/cam_cdm/cam_cdm_util.h new file mode 100644 index 000000000000..663eca92a5fe --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_util.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_UTIL_H_ +#define _CAM_CDM_UTIL_H_ + +enum cam_cdm_command { + CAM_CDM_CMD_UNUSED = 0x0, + CAM_CDM_CMD_DMI = 0x1, + CAM_CDM_CMD_NOT_DEFINED = 0x2, + CAM_CDM_CMD_REG_CONT = 0x3, + CAM_CDM_CMD_REG_RANDOM = 0x4, + CAM_CDM_CMD_BUFF_INDIRECT = 0x5, + CAM_CDM_CMD_GEN_IRQ = 0x6, + CAM_CDM_CMD_WAIT_EVENT = 0x7, + CAM_CDM_CMD_CHANGE_BASE = 0x8, + CAM_CDM_CMD_PERF_CTRL = 0x9, + CAM_CDM_CMD_DMI_32 = 0xa, + CAM_CDM_CMD_DMI_64 = 0xb, + CAM_CDM_CMD_PRIVATE_BASE = 0xc, + CAM_CDM_CMD_SWD_DMI_32 = (CAM_CDM_CMD_PRIVATE_BASE + 0x64), + CAM_CDM_CMD_SWD_DMI_64 = (CAM_CDM_CMD_PRIVATE_BASE + 0x65), + CAM_CDM_CMD_PRIVATE_BASE_MAX = 0x7F +}; + +/** + * struct cam_cdm_utils_ops - Camera CDM util ops + * + * @cdm_get_cmd_header_size: Returns the size of the given command header + * in DWORDs. + * @command Command ID + * @return Size of the command in DWORDs + * + * @cdm_required_size_reg_continuous: Calculates the size of a reg-continuous + * command in dwords. + * @numVals Number of continuous values + * @return Size in dwords + * + * @cdm_required_size_reg_random: Calculates the size of a reg-random command + * in dwords. + * @numRegVals Number of register/value pairs + * @return Size in dwords + * + * @cdm_required_size_dmi: Calculates the size of a DMI command in dwords. + * @return Size in dwords + * + * @cdm_required_size_genirq: Calculates size of a Genirq command in dwords. + * @return Size in dwords + * + * @cdm_required_size_indirect: Calculates the size of an indirect command + * in dwords. + * @return Size in dwords + * + * @cdm_required_size_changebase: Calculates the size of a change-base command + * in dwords. + * @return Size in dwords + * + * @cdm_offsetof_dmi_addr: Returns the offset of address field in the DMI + * command header. + * @return Offset of addr field + * + * @cdm_offsetof_indirect_addr: Returns the offset of address field in the + * indirect command header. + * @return Offset of addr field + * + * @cdm_write_regcontinuous: Writes a command into the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @reg: Beginning of the register address range where + * values will be written. + * @numVals: Number of values (registers) that will be written + * @pVals : An array of values that will be written + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_regrandom: Writes a command into the command buffer in + * register/value pairs. + * @pCmdBuffer: Pointer to command buffer + * @numRegVals: Number of register/value pairs that will be written + * @pRegVals: An array of register/value pairs that will be written + * The even indices are registers and the odd indices + * arevalues, e.g., {reg1, val1, reg2, val2, ...}. + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_dmi: Writes a DMI command into the command bufferM. + * @pCmdBuffer: Pointer to command buffer + * @dmiCmd: DMI command + * @DMIAddr: Address of the DMI + * @DMISel: Selected bank that the DMI will write to + * @length: Size of data in bytes + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_indirect: Writes a indirect command into the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @indirectBufferAddr: Device address of the indirect cmd buffer. + * @length: Size of data in bytes + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_changebase: Writes a changing CDM (address) base command into + * the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @base: New base (device) address + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_genirq: Writes a gen irq command into the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @userdata: userdata or cookie return by hardware during irq. + */ +struct cam_cdm_utils_ops { +uint32_t (*cdm_get_cmd_header_size)(unsigned int command); +uint32_t (*cdm_required_size_reg_continuous)(uint32_t numVals); +uint32_t (*cdm_required_size_reg_random)(uint32_t numRegVals); +uint32_t (*cdm_required_size_dmi)(void); +uint32_t (*cdm_required_size_genirq)(void); +uint32_t (*cdm_required_size_indirect)(void); +uint32_t (*cdm_required_size_changebase)(void); +uint32_t (*cdm_offsetof_dmi_addr)(void); +uint32_t (*cdm_offsetof_indirect_addr)(void); +uint32_t* (*cdm_write_regcontinuous)( + uint32_t *pCmdBuffer, + uint32_t reg, + uint32_t numVals, + uint32_t *pVals); +uint32_t *(*cdm_write_regrandom)( + uint32_t *pCmdBuffer, + uint32_t numRegVals, + uint32_t *pRegVals); +uint32_t *(*cdm_write_dmi)( + uint32_t *pCmdBuffer, + uint8_t dmiCmd, + uint32_t DMIAddr, + uint8_t DMISel, + uint32_t dmiBufferAddr, + uint32_t length); +uint32_t *(*cdm_write_indirect)( + uint32_t *pCmdBuffer, + uint32_t indirectBufferAddr, + uint32_t length); +uint32_t *(*cdm_write_changebase)( + uint32_t *pCmdBuffer, + uint32_t base); +void (*cdm_write_genirq)( + uint32_t *pCmdBuffer, + uint32_t userdata); +}; + +/** + * cam_cdm_util_log_cmd_bufs() + * + * @brief: Util function to log cdm command buffers + * + * @cmd_buffer_start: Pointer to start of cmd buffer + * @cmd_buffer_end: Pointer to end of cmd buffer + * + */ +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end); + + + +#endif /* _CAM_CDM_UTIL_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_virtual.h b/drivers/cam_cdm/cam_cdm_virtual.h new file mode 100644 index 000000000000..193e01be4796 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_virtual.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_VIRTUAL_H_ +#define _CAM_CDM_VIRTUAL_H_ + +#include "cam_cdm_intf_api.h" + +int cam_virtual_cdm_probe(struct platform_device *pdev); +int cam_virtual_cdm_remove(struct platform_device *pdev); +int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base, + uint32_t *cmd_buf, uint32_t cmd_buf_size, + struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK], + uint32_t base_array_size, uint8_t bl_tag); + +#endif /* _CAM_CDM_VIRTUAL_H_ */ diff --git a/drivers/cam_cdm/cam_cdm_virtual_core.c b/drivers/cam_cdm/cam_cdm_virtual_core.c new file mode 100644 index 000000000000..5abca3939338 --- /dev/null +++ b/drivers/cam_cdm/cam_cdm_virtual_core.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_util.h" +#include "cam_cdm_virtual.h" +#include "cam_cdm_core_common.h" +#include "cam_cdm_soc.h" +#include "cam_io_util.h" + +#define CAM_CDM_VIRTUAL_NAME "qcom,cam_virtual_cdm" + +static void cam_virtual_cdm_work(struct work_struct *work) +{ + struct cam_cdm_work_payload *payload; + struct cam_hw_info *cdm_hw; + struct cam_cdm *core; + + payload = container_of(work, struct cam_cdm_work_payload, work); + if (payload) { + cdm_hw = payload->hw; + core = (struct cam_cdm *)cdm_hw->core_info; + if (payload->irq_status & 0x2) { + struct cam_cdm_bl_cb_request_entry *node; + + CAM_DBG(CAM_CDM, "CDM HW Gen/inline IRQ with data=%x", + payload->irq_data); + mutex_lock(&cdm_hw->hw_mutex); + node = cam_cdm_find_request_by_bl_tag( + payload->irq_data, + &core->bl_request_list); + if (node) { + if (node->request_type == + CAM_HW_CDM_BL_CB_CLIENT) { + cam_cdm_notify_clients(cdm_hw, + CAM_CDM_CB_STATUS_BL_SUCCESS, + (void *)node); + } else if (node->request_type == + CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_ERR(CAM_CDM, "Invalid node=%pK %d", + node, node->request_type); + } + list_del_init(&node->entry); + kfree(node); + } else { + CAM_ERR(CAM_CDM, "Invalid node for inline irq"); + } + mutex_unlock(&cdm_hw->hw_mutex); + } + if (payload->irq_status & 0x1) { + CAM_DBG(CAM_CDM, "CDM HW reset done IRQ"); + complete(&core->reset_complete); + } + kfree(payload); + } + +} + +int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client) +{ + int i, rc = -EINVAL; + struct cam_cdm_bl_request *cdm_cmd = req->data; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + mutex_lock(&client->lock); + for (i = 0; i < req->data->cmd_arrary_count ; i++) { + uintptr_t vaddr_ptr = 0; + size_t len = 0; + + if ((!cdm_cmd->cmd[i].len) && + (cdm_cmd->cmd[i].len > 0x100000)) { + CAM_ERR(CAM_CDM, + "len(%d) is invalid count=%d total cnt=%d", + cdm_cmd->cmd[i].len, i, + req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + if (req->data->type == CAM_CDM_BL_CMD_TYPE_MEM_HANDLE) { + rc = cam_mem_get_cpu_buf( + cdm_cmd->cmd[i].bl_addr.mem_handle, &vaddr_ptr, + &len); + } else if (req->data->type == + CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA) { + rc = 0; + vaddr_ptr = cdm_cmd->cmd[i].bl_addr.kernel_iova; + len = cdm_cmd->cmd[i].offset + cdm_cmd->cmd[i].len; + } else { + CAM_ERR(CAM_CDM, + "Only mem hdl/Kernel va type is supported %d", + req->data->type); + rc = -EINVAL; + break; + } + + if ((!rc) && (vaddr_ptr) && (len) && + (len >= cdm_cmd->cmd[i].offset)) { + + + if ((len - cdm_cmd->cmd[i].offset) < + cdm_cmd->cmd[i].len) { + CAM_ERR(CAM_CDM, "Not enough buffer"); + rc = -EINVAL; + break; + } + CAM_DBG(CAM_CDM, + "hdl=%x vaddr=%pK offset=%d cmdlen=%d:%zu", + cdm_cmd->cmd[i].bl_addr.mem_handle, + (void *)vaddr_ptr, cdm_cmd->cmd[i].offset, + cdm_cmd->cmd[i].len, len); + rc = cam_cdm_util_cmd_buf_write( + &client->changebase_addr, + ((uint32_t *)vaddr_ptr + + ((cdm_cmd->cmd[i].offset)/4)), + cdm_cmd->cmd[i].len, client->data.base_array, + client->data.base_array_cnt, core->bl_tag); + if (rc) { + CAM_ERR(CAM_CDM, + "write failed for cnt=%d:%d len %u", + i, req->data->cmd_arrary_count, + cdm_cmd->cmd[i].len); + break; + } + } else { + CAM_ERR(CAM_CDM, + "Sanity check failed for hdl=%x len=%zu:%d", + cdm_cmd->cmd[i].bl_addr.mem_handle, len, + cdm_cmd->cmd[i].offset); + CAM_ERR(CAM_CDM, + "Sanity check failed for cmd_count=%d cnt=%d", + i, req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + if (!rc) { + struct cam_cdm_work_payload *payload; + + CAM_DBG(CAM_CDM, + "write BL success for cnt=%d with tag=%d", + i, core->bl_tag); + if ((true == req->data->flag) && + (i == req->data->cmd_arrary_count)) { + struct cam_cdm_bl_cb_request_entry *node; + + node = kzalloc(sizeof( + struct cam_cdm_bl_cb_request_entry), + GFP_KERNEL); + if (!node) { + rc = -ENOMEM; + break; + } + node->request_type = CAM_HW_CDM_BL_CB_CLIENT; + node->client_hdl = req->handle; + node->cookie = req->data->cookie; + node->bl_tag = core->bl_tag; + node->userdata = req->data->userdata; + mutex_lock(&cdm_hw->hw_mutex); + list_add_tail(&node->entry, + &core->bl_request_list); + mutex_unlock(&cdm_hw->hw_mutex); + + payload = kzalloc(sizeof( + struct cam_cdm_work_payload), + GFP_ATOMIC); + if (payload) { + payload->irq_status = 0x2; + payload->irq_data = core->bl_tag; + payload->hw = cdm_hw; + INIT_WORK((struct work_struct *) + &payload->work, + cam_virtual_cdm_work); + queue_work(core->work_queue, + &payload->work); + } + } + core->bl_tag++; + CAM_DBG(CAM_CDM, + "Now commit the BL nothing for virtual"); + if (!rc && (core->bl_tag == 63)) + core->bl_tag = 0; + } + } + mutex_unlock(&client->lock); + return rc; +} + +int cam_virtual_cdm_probe(struct platform_device *pdev) +{ + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + struct cam_cdm_private_dt_data *soc_private = NULL; + int rc; + struct cam_cpas_register_params cpas_parms; + + cdm_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!cdm_hw_intf) + return -ENOMEM; + + cdm_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!cdm_hw) { + kfree(cdm_hw_intf); + return -ENOMEM; + } + + cdm_hw->core_info = kzalloc(sizeof(struct cam_cdm), GFP_KERNEL); + if (!cdm_hw->core_info) { + kfree(cdm_hw); + kfree(cdm_hw_intf); + return -ENOMEM; + } + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + cdm_hw->soc_info.pdev = pdev; + cdm_hw_intf->hw_type = CAM_VIRTUAL_CDM; + cdm_hw->soc_info.soc_private = kzalloc( + sizeof(struct cam_cdm_private_dt_data), GFP_KERNEL); + if (!cdm_hw->soc_info.soc_private) { + rc = -ENOMEM; + goto soc_load_failed; + } + + rc = cam_cdm_soc_load_dt_private(pdev, cdm_hw->soc_info.soc_private); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to load CDM dt private data"); + kfree(cdm_hw->soc_info.soc_private); + cdm_hw->soc_info.soc_private = NULL; + goto soc_load_failed; + } + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + soc_private = (struct cam_cdm_private_dt_data *) + cdm_hw->soc_info.soc_private; + if (soc_private->dt_cdm_shared == true) + cdm_core->flags = CAM_CDM_FLAG_SHARED_CDM; + else + cdm_core->flags = CAM_CDM_FLAG_PRIVATE_CDM; + + cdm_core->bl_tag = 0; + INIT_LIST_HEAD(&cdm_core->bl_request_list); + init_completion(&cdm_core->reset_complete); + cdm_hw_intf->hw_priv = cdm_hw; + cdm_hw_intf->hw_ops.get_hw_caps = cam_cdm_get_caps; + cdm_hw_intf->hw_ops.init = NULL; + cdm_hw_intf->hw_ops.deinit = NULL; + cdm_hw_intf->hw_ops.start = cam_cdm_stream_start; + cdm_hw_intf->hw_ops.stop = cam_cdm_stream_stop; + cdm_hw_intf->hw_ops.read = NULL; + cdm_hw_intf->hw_ops.write = NULL; + cdm_hw_intf->hw_ops.process_cmd = cam_cdm_process_cmd; + + CAM_DBG(CAM_CDM, "type %d index %d", cdm_hw_intf->hw_type, + cdm_hw_intf->hw_idx); + + platform_set_drvdata(pdev, cdm_hw_intf); + + cdm_hw->open_count = 0; + cdm_core->iommu_hdl.non_secure = -1; + cdm_core->iommu_hdl.secure = -1; + mutex_init(&cdm_hw->hw_mutex); + spin_lock_init(&cdm_hw->hw_lock); + init_completion(&cdm_hw->hw_complete); + mutex_lock(&cdm_hw->hw_mutex); + cdm_core->id = CAM_CDM_VIRTUAL; + memcpy(cdm_core->name, CAM_CDM_VIRTUAL_NAME, + sizeof(CAM_CDM_VIRTUAL_NAME)); + cdm_core->work_queue = alloc_workqueue(cdm_core->name, + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, + CAM_CDM_INFLIGHT_WORKS); + cdm_core->ops = NULL; + + cpas_parms.cam_cpas_client_cb = cam_cdm_cpas_cb; + cpas_parms.cell_index = cdm_hw->soc_info.index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = cdm_hw_intf; + strlcpy(cpas_parms.identifier, "cam-cdm-intf", + CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CDM, "Virtual CDM CPAS registration failed"); + goto cpas_registration_failed; + } + CAM_DBG(CAM_CDM, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + cdm_core->cpas_handle = cpas_parms.client_handle; + + CAM_DBG(CAM_CDM, "CDM%d probe successful", cdm_hw_intf->hw_idx); + + rc = cam_cdm_intf_register_hw_cdm(cdm_hw_intf, + soc_private, CAM_VIRTUAL_CDM, &cdm_core->index); + if (rc) { + CAM_ERR(CAM_CDM, "Virtual CDM Interface registration failed"); + goto intf_registration_failed; + } + CAM_DBG(CAM_CDM, "CDM%d registered to intf successful", + cdm_hw_intf->hw_idx); + mutex_unlock(&cdm_hw->hw_mutex); + + return 0; +intf_registration_failed: + cam_cpas_unregister_client(cdm_core->cpas_handle); +cpas_registration_failed: + kfree(cdm_hw->soc_info.soc_private); + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); + mutex_unlock(&cdm_hw->hw_mutex); + mutex_destroy(&cdm_hw->hw_mutex); +soc_load_failed: + kfree(cdm_hw->core_info); + kfree(cdm_hw); + kfree(cdm_hw_intf); + return rc; +} + +int cam_virtual_cdm_remove(struct platform_device *pdev) +{ + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + int rc = -EBUSY; + + cdm_hw_intf = platform_get_drvdata(pdev); + if (!cdm_hw_intf) { + CAM_ERR(CAM_CDM, "Failed to get dev private data"); + return rc; + } + + cdm_hw = cdm_hw_intf->hw_priv; + if (!cdm_hw) { + CAM_ERR(CAM_CDM, + "Failed to get virtual private data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + cdm_core = cdm_hw->core_info; + if (!cdm_core) { + CAM_ERR(CAM_CDM, + "Failed to get virtual core data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + rc = cam_cpas_unregister_client(cdm_core->cpas_handle); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS unregister failed"); + return rc; + } + + rc = cam_cdm_intf_deregister_hw_cdm(cdm_hw_intf, + cdm_hw->soc_info.soc_private, CAM_VIRTUAL_CDM, + cdm_core->index); + if (rc) { + CAM_ERR(CAM_CDM, + "Virtual CDM Interface de-registration failed"); + return rc; + } + + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); + mutex_destroy(&cdm_hw->hw_mutex); + kfree(cdm_hw->soc_info.soc_private); + kfree(cdm_hw->core_info); + kfree(cdm_hw); + kfree(cdm_hw_intf); + rc = 0; + + return rc; +} diff --git a/drivers/cam_cdm/cam_hw_cdm170_reg.h b/drivers/cam_cdm/cam_hw_cdm170_reg.h new file mode 100644 index 000000000000..4a0fbda825c5 --- /dev/null +++ b/drivers/cam_cdm/cam_hw_cdm170_reg.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_CDM170_REG_H_ +#define _CAM_HW_CDM170_REG_H_ + +#define CAM_CDM_REG_OFFSET_FIRST 0x0 +#define CAM_CDM_REG_OFFSET_LAST 0x200 +#define CAM_CDM_REGS_COUNT 0x30 +#define CAM_CDM_HWFIFO_SIZE 0x40 + +#define CAM_CDM_OFFSET_HW_VERSION 0x0 +#define CAM_CDM_OFFSET_TITAN_VERSION 0x4 +#define CAM_CDM_OFFSET_RST_CMD 0x10 +#define CAM_CDM_OFFSET_CGC_CFG 0x14 +#define CAM_CDM_OFFSET_CORE_CFG 0x18 +#define CAM_CDM_OFFSET_CORE_EN 0x1c +#define CAM_CDM_OFFSET_FE_CFG 0x20 +#define CAM_CDM_OFFSET_IRQ_MASK 0x30 +#define CAM_CDM_OFFSET_IRQ_CLEAR 0x34 +#define CAM_CDM_OFFSET_IRQ_CLEAR_CMD 0x38 +#define CAM_CDM_OFFSET_IRQ_SET 0x3c +#define CAM_CDM_OFFSET_IRQ_SET_CMD 0x40 + +#define CAM_CDM_OFFSET_IRQ_STATUS 0x44 +#define CAM_CDM_IRQ_STATUS_INFO_RST_DONE_MASK 0x1 +#define CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK 0x2 +#define CAM_CDM_IRQ_STATUS_INFO_BL_DONE_MASK 0x4 +#define CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK 0x10000 +#define CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK 0x20000 +#define CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK 0x40000 + +#define CAM_CDM_OFFSET_BL_FIFO_BASE_REG 0x50 +#define CAM_CDM_OFFSET_BL_FIFO_LEN_REG 0x54 +#define CAM_CDM_OFFSET_BL_FIFO_STORE_REG 0x58 +#define CAM_CDM_OFFSET_BL_FIFO_CFG 0x5c +#define CAM_CDM_OFFSET_BL_FIFO_RB 0x60 +#define CAM_CDM_OFFSET_BL_FIFO_BASE_RB 0x64 +#define CAM_CDM_OFFSET_BL_FIFO_LEN_RB 0x68 +#define CAM_CDM_OFFSET_BL_FIFO_PENDING_REQ_RB 0x6c +#define CAM_CDM_OFFSET_IRQ_USR_DATA 0x80 +#define CAM_CDM_OFFSET_WAIT_STATUS 0x84 +#define CAM_CDM_OFFSET_SCRATCH_0_REG 0x90 +#define CAM_CDM_OFFSET_SCRATCH_1_REG 0x94 +#define CAM_CDM_OFFSET_SCRATCH_2_REG 0x98 +#define CAM_CDM_OFFSET_SCRATCH_3_REG 0x9c +#define CAM_CDM_OFFSET_SCRATCH_4_REG 0xa0 +#define CAM_CDM_OFFSET_SCRATCH_5_REG 0xa4 +#define CAM_CDM_OFFSET_SCRATCH_6_REG 0xa8 +#define CAM_CDM_OFFSET_SCRATCH_7_REG 0xac +#define CAM_CDM_OFFSET_LAST_AHB_ADDR 0xd0 +#define CAM_CDM_OFFSET_LAST_AHB_DATA 0xd4 +#define CAM_CDM_OFFSET_CORE_DBUG 0xd8 +#define CAM_CDM_OFFSET_LAST_AHB_ERR_ADDR 0xe0 +#define CAM_CDM_OFFSET_LAST_AHB_ERR_DATA 0xe4 +#define CAM_CDM_OFFSET_CURRENT_BL_BASE 0xe8 +#define CAM_CDM_OFFSET_CURRENT_BL_LEN 0xec +#define CAM_CDM_OFFSET_CURRENT_USED_AHB_BASE 0xf0 +#define CAM_CDM_OFFSET_DEBUG_STATUS 0xf4 +#define CAM_CDM_OFFSET_BUS_MISR_CFG_0 0x100 +#define CAM_CDM_OFFSET_BUS_MISR_CFG_1 0x104 +#define CAM_CDM_OFFSET_BUS_MISR_RD_VAL 0x108 +#define CAM_CDM_OFFSET_PERF_MON_CTRL 0x110 +#define CAM_CDM_OFFSET_PERF_MON_0 0x114 +#define CAM_CDM_OFFSET_PERF_MON_1 0x118 +#define CAM_CDM_OFFSET_PERF_MON_2 0x11c +#define CAM_CDM_OFFSET_SPARE 0x200 + +/* + * Always make sure below register offsets are aligned with + * enum cam_cdm_regs offsets + */ +struct cam_cdm_reg_offset cam170_cpas_cdm_register_offsets[] = { + { CAM_CDM_OFFSET_HW_VERSION, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_TITAN_VERSION, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_RST_CMD, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_CGC_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_CORE_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_CORE_EN, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_FE_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_MASK, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_CLEAR, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_CLEAR_CMD, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_IRQ_SET, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_SET_CMD, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_IRQ_STATUS, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_IRQ_USR_DATA, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_BASE_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_LEN_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_STORE_REG, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_RB, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_BASE_RB, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_BL_FIFO_LEN_RB, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_BL_FIFO_PENDING_REQ_RB, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_WAIT_STATUS, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_SCRATCH_0_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_1_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_2_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_3_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_4_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_5_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_6_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_7_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_LAST_AHB_ADDR, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_LAST_AHB_DATA, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CORE_DBUG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_LAST_AHB_ERR_ADDR, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_LAST_AHB_ERR_DATA, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CURRENT_BL_BASE, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CURRENT_BL_LEN, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CURRENT_USED_AHB_BASE, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_DEBUG_STATUS, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_BUS_MISR_CFG_0, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BUS_MISR_CFG_1, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BUS_MISR_RD_VAL, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_PERF_MON_CTRL, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_PERF_MON_0, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_PERF_MON_1, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_PERF_MON_2, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_SPARE, CAM_REG_ATTR_READ_WRITE } +}; + +struct cam_cdm_reg_offset_table cam170_cpas_cdm_offset_table = { + .first_offset = 0x0, + .last_offset = 0x200, + .reg_count = 0x30, + .offsets = cam170_cpas_cdm_register_offsets, + .offset_max_size = (sizeof(cam170_cpas_cdm_register_offsets)/ + sizeof(struct cam_cdm_reg_offset)), +}; + +#endif /* _CAM_HW_CDM170_REG_H_ */ diff --git a/drivers/cam_core/Makefile b/drivers/cam_core/Makefile new file mode 100644 index 000000000000..986b65f0ecd4 --- /dev/null +++ b/drivers/cam_core/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_context_utils.o cam_node.o cam_subdev.o diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c new file mode 100644 index 000000000000..85908a3b6a4d --- /dev/null +++ b/drivers/cam_core/cam_context.c @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include + +#include "cam_context.h" +#include "cam_debug_util.h" +#include "cam_node.h" + +static int cam_context_handle_hw_event(void *context, uint32_t evt_id, + void *evt_data) +{ + int rc = 0; + struct cam_context *ctx = (struct cam_context *)context; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (ctx->state_machine[ctx->state].irq_ops) + rc = ctx->state_machine[ctx->state].irq_ops(ctx, evt_id, + evt_data); + else + CAM_DBG(CAM_CORE, + "No function to handle event %d in dev %d, state %d", + evt_id, ctx->dev_hdl, ctx->state); + return rc; +} + +int cam_context_shutdown(struct cam_context *ctx) +{ + int rc = 0; + struct cam_release_dev_cmd cmd; + + if (ctx->state > CAM_CTX_AVAILABLE && ctx->state < CAM_CTX_STATE_MAX) { + cmd.session_handle = ctx->session_hdl; + cmd.dev_handle = ctx->dev_hdl; + rc = cam_context_handle_release_dev(ctx, &cmd); + if (rc) + CAM_ERR(CAM_CORE, + "context release failed for dev_name %s", + ctx->dev_name); + else + cam_context_putref(ctx); + } else { + CAM_WARN(CAM_CORE, + "dev %s context id %u state %d invalid to release hdl", + ctx->dev_name, ctx->ctx_id, ctx->state); + rc = -EINVAL; + } + + rc = cam_destroy_device_hdl(ctx->dev_hdl); + if (rc) + CAM_ERR(CAM_CORE, "destroy device hdl failed for node %s", + ctx->dev_name); + else + ctx->dev_hdl = -1; + + return rc; +} + +int cam_context_handle_crm_get_dev_info(struct cam_context *ctx, + struct cam_req_mgr_device_info *info) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!info) { + CAM_ERR(CAM_CORE, "Invalid get device info payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.get_dev_info) { + rc = ctx->state_machine[ctx->state].crm_ops.get_dev_info( + ctx, info); + } else { + CAM_ERR(CAM_CORE, "No get device info in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_link(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!link) { + CAM_ERR(CAM_CORE, "Invalid link payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.link) { + rc = ctx->state_machine[ctx->state].crm_ops.link(ctx, link); + } else { + CAM_ERR(CAM_CORE, "No crm link in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_unlink(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!unlink) { + CAM_ERR(CAM_CORE, "Invalid unlink payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.unlink) { + rc = ctx->state_machine[ctx->state].crm_ops.unlink( + ctx, unlink); + } else { + CAM_ERR(CAM_CORE, "No crm unlink in dev %d, name %s, state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_apply_req(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!apply) { + CAM_ERR(CAM_CORE, "Invalid apply request payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.apply_req) { + rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx, + apply); + } else { + CAM_ERR(CAM_CORE, "No crm apply req in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_flush_req(struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.flush_req) { + rc = ctx->state_machine[ctx->state].crm_ops.flush_req(ctx, + flush); + } else { + CAM_ERR(CAM_CORE, "No crm flush req in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *process_evt) +{ + int rc = 0; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.process_evt) { + rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx, + process_evt); + } else { + /* handling of this message is optional */ + CAM_DBG(CAM_CORE, "No crm process evt in dev %d, state %d", + ctx->dev_hdl, ctx->state); + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, + uint32_t buf_info) +{ + int rc = 0; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (ctx->state_machine[ctx->state].pagefault_ops) { + rc = ctx->state_machine[ctx->state].pagefault_ops(ctx, iova, + buf_info); + } else { + CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d", + ctx->dev_hdl, ctx->state); + } + + return rc; +} + +int cam_context_handle_acquire_dev(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + int i; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid acquire device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.acquire_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_dev( + ctx, cmd); + } else { + CAM_ERR(CAM_CORE, "No acquire device in dev %d, state %d", + cmd->dev_handle, ctx->state); + rc = -EPROTO; + } + + INIT_LIST_HEAD(&ctx->active_req_list); + INIT_LIST_HEAD(&ctx->wait_req_list); + INIT_LIST_HEAD(&ctx->pending_req_list); + INIT_LIST_HEAD(&ctx->free_req_list); + + for (i = 0; i < ctx->req_size; i++) { + INIT_LIST_HEAD(&ctx->req_list[i].list); + list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list); + } + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_acquire_hw(struct cam_context *ctx, + void *args) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_CORE, "Invalid acquire device hw command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.acquire_hw) { + rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_hw( + ctx, args); + } else { + CAM_ERR(CAM_CORE, "No acquire hw for dev %s, state %d", + ctx->dev_name, ctx->state); + rc = -EPROTO; + } + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_release_dev(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid release device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev( + ctx, cmd); + } else { + CAM_ERR(CAM_CORE, "No release device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_release_hw(struct cam_context *ctx, + void *args) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_CORE, "Invalid release HW command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.release_hw) { + rc = ctx->state_machine[ctx->state].ioctl_ops.release_hw( + ctx, args); + } else { + CAM_ERR(CAM_CORE, "No release hw for dev %s, state %d", + ctx->dev_name, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_flush_dev(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc = 0; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid flush device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.flush_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.flush_dev( + ctx, cmd); + } else { + CAM_WARN(CAM_CORE, "No flush device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_config_dev(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid config device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.config_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.config_dev( + ctx, cmd); + } else { + CAM_ERR(CAM_CORE, "No config device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_start_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid start device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.start_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev( + ctx, cmd); + else + /* start device can be optional for some driver */ + CAM_DBG(CAM_CORE, "No start device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_stop_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid stop device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev( + ctx, cmd); + else + /* stop device can be optional for some driver */ + CAM_WARN(CAM_CORE, "No stop device in dev %d, name %s state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + + ctx->last_flush_req = 0; + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_init(struct cam_context *ctx, + const char *dev_name, + uint64_t dev_id, + uint32_t ctx_id, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_mgr_intf, + struct cam_ctx_request *req_list, + uint32_t req_size) +{ + int i; + + /* crm_node_intf is optinal */ + if (!ctx || !hw_mgr_intf || !req_list) { + CAM_ERR(CAM_CORE, "Invalid input parameters"); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + ctx->session_hdl = -1; + INIT_LIST_HEAD(&ctx->list); + mutex_init(&ctx->ctx_mutex); + mutex_init(&ctx->sync_mutex); + spin_lock_init(&ctx->lock); + + ctx->dev_name = dev_name; + ctx->dev_id = dev_id; + ctx->ctx_id = ctx_id; + ctx->last_flush_req = 0; + ctx->ctx_crm_intf = NULL; + ctx->crm_ctx_intf = crm_node_intf; + ctx->hw_mgr_intf = hw_mgr_intf; + ctx->irq_cb_intf = cam_context_handle_hw_event; + + INIT_LIST_HEAD(&ctx->active_req_list); + INIT_LIST_HEAD(&ctx->wait_req_list); + INIT_LIST_HEAD(&ctx->pending_req_list); + INIT_LIST_HEAD(&ctx->free_req_list); + ctx->req_list = req_list; + ctx->req_size = req_size; + for (i = 0; i < req_size; i++) { + INIT_LIST_HEAD(&ctx->req_list[i].list); + list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list); + ctx->req_list[i].ctx = ctx; + } + ctx->state = CAM_CTX_AVAILABLE; + ctx->state_machine = NULL; + ctx->ctx_priv = NULL; + + return 0; +} + +int cam_context_deinit(struct cam_context *ctx) +{ + if (!ctx) + return -EINVAL; + + /** + * This is called from platform device remove. + * Everyting should be released at this moment. + * so we just free the memory for the context + */ + if (ctx->state != CAM_CTX_AVAILABLE) + CAM_ERR(CAM_CORE, "Device did not shutdown cleanly"); + + memset(ctx, 0, sizeof(*ctx)); + + return 0; +} + +void cam_context_putref(struct cam_context *ctx) +{ + kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + CAM_DBG(CAM_CORE, + "ctx device hdl %ld, ref count %d, dev_name %s", + ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), + ctx->dev_name); +} + +void cam_context_getref(struct cam_context *ctx) +{ + if (kref_get_unless_zero(&ctx->refcount) == 0) { + /* should never happen */ + WARN(1, "%s fail\n", __func__); + } + CAM_DBG(CAM_CORE, + "ctx device hdl %ld, ref count %d, dev_name %s", + ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), + ctx->dev_name); +} diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h new file mode 100644 index 000000000000..55fd376f33d6 --- /dev/null +++ b/drivers/cam_core/cam_context.h @@ -0,0 +1,460 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CONTEXT_H_ +#define _CAM_CONTEXT_H_ + +#include +#include +#include +#include "cam_req_mgr_interface.h" +#include "cam_hw_mgr_intf.h" + +/* Forward declarations */ +struct cam_context; + +/* max request number */ +#define CAM_CTX_REQ_MAX 20 +#define CAM_CTX_CFG_MAX 20 +#define CAM_CTX_RES_MAX 20 + +/** + * enum cam_ctx_state - context top level states + * + */ +enum cam_context_state { + CAM_CTX_UNINIT = 0, + CAM_CTX_AVAILABLE = 1, + CAM_CTX_ACQUIRED = 2, + CAM_CTX_READY = 3, + CAM_CTX_ACTIVATED = 4, + CAM_CTX_STATE_MAX = 5, +}; + +/** + * struct cam_ctx_request - Common request structure for the context + * + * @list: Link list entry + * @status: Request status + * @request_id: Request id + * @req_priv: Derived request object + * @hw_update_entries: Hardware update entries + * @num_hw_update_entries: Number of hardware update entries + * @in_map_entries: Entries for in fences + * @num_in_map_entries: Number of in map entries + * @out_map_entries: Entries for out fences + * @num_out_map_entries: Number of out map entries + * @num_in_acked: Number of in fence acked + * @num_out_acked: Number of out fence acked + * @flushed: Request is flushed + * @ctx: The context to which this request belongs + * @pf_data page fault debug data + * + */ +struct cam_ctx_request { + struct list_head list; + uint32_t status; + uint64_t request_id; + void *req_priv; + struct cam_hw_update_entry hw_update_entries[CAM_CTX_CFG_MAX]; + uint32_t num_hw_update_entries; + struct cam_hw_fence_map_entry in_map_entries[CAM_CTX_CFG_MAX]; + uint32_t num_in_map_entries; + struct cam_hw_fence_map_entry out_map_entries[CAM_CTX_CFG_MAX]; + uint32_t num_out_map_entries; + atomic_t num_in_acked; + uint32_t num_out_acked; + int flushed; + struct cam_context *ctx; + struct cam_hw_mgr_dump_pf_data pf_data; +}; + +/** + * struct cam_ctx_ioctl_ops - Function table for handling IOCTL calls + * + * @acquire_dev: Function pointer for acquire device + * @release_dev: Function pointer for release device + * @config_dev: Function pointer for config device + * @start_dev: Function pointer for start device + * @stop_dev: Function pointer for stop device + * @flush_dev: Function pointer for flush device + * @acquire_hw: Function pointer for acquire hw + * @release_hw: Function pointer for release hw + * + */ +struct cam_ctx_ioctl_ops { + int (*acquire_dev)(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd); + int (*release_dev)(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd); + int (*config_dev)(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd); + int (*start_dev)(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + int (*stop_dev)(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + int (*flush_dev)(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); + int (*acquire_hw)(struct cam_context *ctx, void *args); + int (*release_hw)(struct cam_context *ctx, void *args); +}; + +/** + * struct cam_ctx_crm_ops - Function table for handling CRM to context calls + * + * @get_dev_info: Get device informaiton + * @link: Link the context + * @unlink: Unlink the context + * @apply_req: Apply setting for the context + * @flush_req: Flush request to remove request ids + * @process_evt: Handle event notification from CRM.(optional) + * + */ +struct cam_ctx_crm_ops { + int (*get_dev_info)(struct cam_context *ctx, + struct cam_req_mgr_device_info *device_info); + int (*link)(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link); + int (*unlink)(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink); + int (*apply_req)(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply); + int (*flush_req)(struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush); + int (*process_evt)(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *evt_data); +}; + + +/** + * struct cam_ctx_ops - Collection of the interface funciton tables + * + * @ioctl_ops: Ioctl funciton table + * @crm_ops: CRM to context interface function table + * @irq_ops: Hardware event handle function + * @pagefault_ops: Function to be called on page fault + * + */ +struct cam_ctx_ops { + struct cam_ctx_ioctl_ops ioctl_ops; + struct cam_ctx_crm_ops crm_ops; + cam_hw_event_cb_func irq_ops; + cam_hw_pagefault_cb_func pagefault_ops; +}; + +/** + * struct cam_context - camera context object for the subdevice node + * + * @dev_name: String giving name of device associated + * @dev_id: ID of device associated + * @ctx_id: ID for this context + * @list: Link list entry + * @sessoin_hdl: Session handle + * @dev_hdl: Device handle + * @link_hdl: Link handle + * @ctx_mutex: Mutex for ioctl calls + * @lock: Spin lock + * @active_req_list: Requests pending for done event + * @pending_req_list: Requests pending for reg upd event + * @wait_req_list: Requests waiting for apply + * @free_req_list: Requests that are free + * @req_list: Reference to the request storage + * @req_size: Size of the request storage + * @hw_mgr_intf: Context to HW interface + * @ctx_crm_intf: Context to CRM interface + * @crm_ctx_intf: CRM to context interface + * @irq_cb_intf: HW to context callback interface + * @state: Current state for top level state machine + * @state_machine: Top level state machine + * @ctx_priv: Private context pointer + * @ctxt_to_hw_map: Context to hardware mapping pointer + * @refcount: Context object refcount + * @node: The main node to which this context belongs + * @sync_mutex: mutex to sync with sync cb thread + * @last_flush_req: Last request to flush + * + */ +struct cam_context { + const char *dev_name; + uint64_t dev_id; + uint32_t ctx_id; + struct list_head list; + int32_t session_hdl; + int32_t dev_hdl; + int32_t link_hdl; + + struct mutex ctx_mutex; + spinlock_t lock; + + struct list_head active_req_list; + struct list_head pending_req_list; + struct list_head wait_req_list; + struct list_head free_req_list; + struct cam_ctx_request *req_list; + uint32_t req_size; + + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_req_mgr_crm_cb *ctx_crm_intf; + struct cam_req_mgr_kmd_ops *crm_ctx_intf; + cam_hw_event_cb_func irq_cb_intf; + + enum cam_context_state state; + struct cam_ctx_ops *state_machine; + + void *ctx_priv; + void *ctxt_to_hw_map; + + struct kref refcount; + void *node; + struct mutex sync_mutex; + uint32_t last_flush_req; +}; + +/** + * cam_context_shutdown() + * + * @brief: Calls while device close or shutdown + * + * @ctx: Object pointer for cam_context + * + */ +int cam_context_shutdown(struct cam_context *ctx); + +/** + * cam_context_handle_crm_get_dev_info() + * + * @brief: Handle get device information command + * + * @ctx: Object pointer for cam_context + * @info: Device information returned + * + */ +int cam_context_handle_crm_get_dev_info(struct cam_context *ctx, + struct cam_req_mgr_device_info *info); + +/** + * cam_context_handle_crm_link() + * + * @brief: Handle link command + * + * @ctx: Object pointer for cam_context + * @link: Link command payload + * + */ +int cam_context_handle_crm_link(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link); + +/** + * cam_context_handle_crm_unlink() + * + * @brief: Handle unlink command + * + * @ctx: Object pointer for cam_context + * @unlink: Unlink command payload + * + */ +int cam_context_handle_crm_unlink(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink); + +/** + * cam_context_handle_crm_apply_req() + * + * @brief: Handle apply request command + * + * @ctx: Object pointer for cam_context + * @apply: Apply request command payload + * + */ +int cam_context_handle_crm_apply_req(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply); + +/** + * cam_context_handle_crm_flush_req() + * + * @brief: Handle flush request command + * + * @ctx: Object pointer for cam_context + * @apply: Flush request command payload + * + */ +int cam_context_handle_crm_flush_req(struct cam_context *ctx, + struct cam_req_mgr_flush_request *apply); + +/** + * cam_context_handle_crm_process_evt() + * + * @brief: Handle process event command + * + * @ctx: Object pointer for cam_context + * @process_evt: process event command payload + * + */ +int cam_context_handle_crm_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *process_evt); + +/** + * cam_context_dump_pf_info() + * + * @brief: Handle dump active request request command + * + * @ctx: Object pointer for cam_context + * @iova: Page fault address + * @buf_info: Information about closest memory handle + * + */ +int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, + uint32_t buf_info); + +/** + * cam_context_handle_acquire_dev() + * + * @brief: Handle acquire device command + * + * @ctx: Object pointer for cam_context + * @cmd: Acquire device command payload + * + */ +int cam_context_handle_acquire_dev(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd); + +/** + * cam_context_handle_acquire_hw() + * + * @brief: Handle acquire HW command + * + * @ctx: Object pointer for cam_context + * @cmd: Acquire HW command payload + * + */ +int cam_context_handle_acquire_hw(struct cam_context *ctx, + void *cmd); + +/** + * cam_context_handle_release_dev() + * + * @brief: Handle release device command + * + * @ctx: Object pointer for cam_context + * @cmd: Release device command payload + * + */ +int cam_context_handle_release_dev(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd); + +/** + * cam_context_handle_release_hw() + * + * @brief: Handle release HW command + * + * @ctx: Object pointer for cam_context + * @cmd: Release HW command payload + * + */ +int cam_context_handle_release_hw(struct cam_context *ctx, + void *cmd); + +/** + * cam_context_handle_config_dev() + * + * @brief: Handle config device command + * + * @ctx: Object pointer for cam_context + * @cmd: Config device command payload + * + */ +int cam_context_handle_config_dev(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd); + +/** + * cam_context_handle_flush_dev() + * + * @brief: Handle flush device command + * + * @ctx: Object pointer for cam_context + * @cmd: Flush device command payload + * + */ +int cam_context_handle_flush_dev(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); + +/** + * cam_context_handle_start_dev() + * + * @brief: Handle start device command + * + * @ctx: Object pointer for cam_context + * @cmd: Start device command payload + * + */ +int cam_context_handle_start_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + +/** + * cam_context_handle_stop_dev() + * + * @brief: Handle stop device command + * + * @ctx: Object pointer for cam_context + * @cmd: Stop device command payload + * + */ +int cam_context_handle_stop_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + +/** + * cam_context_deinit() + * + * @brief: Camera context deinitialize function + * + * @ctx: Object pointer for cam_context + * + */ +int cam_context_deinit(struct cam_context *ctx); + +/** + * cam_context_init() + * + * @brief: Camera context initialize function + * + * @ctx: Object pointer for cam_context + * @dev_name: String giving name of device associated + * @dev_id: ID of the device associated + * @ctx_id: ID for this context + * @crm_node_intf: Function table for crm to context interface + * @hw_mgr_intf: Function table for context to hw interface + * @req_list: Requests storage + * @req_size: Size of the request storage + * + */ +int cam_context_init(struct cam_context *ctx, + const char *dev_name, + uint64_t dev_id, + uint32_t ctx_id, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_mgr_intf, + struct cam_ctx_request *req_list, + uint32_t req_size); + +/** + * cam_context_putref() + * + * @brief: Put back context reference. + * + * @ctx: Context for which ref is returned + * + */ +void cam_context_putref(struct cam_context *ctx); + +/** + * cam_context_getref() + * + * @brief: Get back context reference. + * + * @ctx: Context for which ref is taken + * + */ +void cam_context_getref(struct cam_context *ctx); + +#endif /* _CAM_CONTEXT_H_ */ diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c new file mode 100644 index 000000000000..6b6b17743d1b --- /dev/null +++ b/drivers/cam_core/cam_context_utils.c @@ -0,0 +1,1018 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_mem_mgr.h" +#include "cam_node.h" +#include "cam_req_mgr_util.h" +#include "cam_sync_api.h" +#include "cam_trace.h" +#include "cam_debug_util.h" + +static uint cam_debug_ctx_req_list; +module_param(cam_debug_ctx_req_list, uint, 0644); + +static inline int cam_context_validate_thread(void) +{ + if (in_interrupt()) { + WARN(1, "Invalid execution context\n"); + return -EINVAL; + } + return 0; +} + +int cam_context_buf_done_from_hw(struct cam_context *ctx, + void *done_event_data, uint32_t bubble_state) +{ + int j; + int result; + struct cam_ctx_request *req; + struct cam_hw_done_event_data *done = + (struct cam_hw_done_event_data *)done_event_data; + int rc; + + if (!ctx || !done) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, done); + return -EINVAL; + } + + rc = cam_context_validate_thread(); + if (rc) + return rc; + + spin_lock(&ctx->lock); + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_CTXT, "[%s][%d] no active request", + ctx->dev_name, ctx->ctx_id); + spin_unlock(&ctx->lock); + return -EIO; + } + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + + trace_cam_buf_done("UTILS", ctx, req); + + if (done->request_id != req->request_id) { + CAM_ERR(CAM_CTXT, + "[%s][%d] mismatch: done req[%lld], active req[%lld]", + ctx->dev_name, ctx->ctx_id, + done->request_id, req->request_id); + spin_unlock(&ctx->lock); + return -EIO; + } + + if (!req->num_out_map_entries) { + CAM_ERR(CAM_CTXT, "[%s][%d] no output fence to signal", + ctx->dev_name, ctx->ctx_id); + spin_unlock(&ctx->lock); + return -EIO; + } + + /* + * since another thread may be adding/removing from active + * list, so hold the lock + */ + list_del_init(&req->list); + spin_unlock(&ctx->lock); + if (!bubble_state) { + result = CAM_SYNC_STATE_SIGNALED_SUCCESS; + } else { + CAM_DBG(CAM_REQ, + "[%s][ctx_id %d] : req[%llu] is done with error", + ctx->dev_name, ctx->ctx_id, req->request_id); + + for (j = 0; j < req->num_out_map_entries; j++) + CAM_DBG(CAM_REQ, "fence %d signaled with error", + req->out_map_entries[j].sync_id); + + result = CAM_SYNC_STATE_SIGNALED_ERROR; + } + + for (j = 0; j < req->num_out_map_entries; j++) { + cam_sync_signal(req->out_map_entries[j].sync_id, result); + req->out_map_entries[j].sync_id = -1; + } + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from active_list to free_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + /* + * another thread may be adding/removing from free list, + * so hold the lock + */ + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + req->ctx = NULL; + spin_unlock(&ctx->lock); + + return 0; +} + +static int cam_context_apply_req_to_hw(struct cam_ctx_request *req, + struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_context *ctx = req->ctx; + struct cam_hw_config_args cfg; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + spin_lock(&ctx->lock); + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from pending_list to active_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cfg.request_id = req->request_id; + cfg.hw_update_entries = req->hw_update_entries; + cfg.num_hw_update_entries = req->num_hw_update_entries; + cfg.out_map_entries = req->out_map_entries; + cfg.num_out_map_entries = req->num_out_map_entries; + cfg.priv = req->req_priv; + + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + spin_lock(&ctx->lock); + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from active_list to free_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + } + +end: + return rc; +} + +static void cam_context_sync_callback(int32_t sync_obj, int status, void *data) +{ + struct cam_ctx_request *req = data; + struct cam_context *ctx = NULL; + struct cam_flush_dev_cmd flush_cmd; + struct cam_req_mgr_apply_request apply; + int rc; + + if (!req) { + CAM_ERR(CAM_CTXT, "Invalid input param"); + return; + } + rc = cam_context_validate_thread(); + if (rc) + return; + + ctx = req->ctx; + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid ctx for req %llu", req->request_id); + return; + } + + if (atomic_inc_return(&req->num_in_acked) == req->num_in_map_entries) { + apply.request_id = req->request_id; + /* + * take mutex to ensure that another thread does + * not flush the request while this + * thread is submitting it to h/w. The submit to + * h/w and adding to the active list should happen + * in a critical section which is provided by this + * mutex. + */ + if (status == CAM_SYNC_STATE_SIGNALED_ERROR) { + CAM_DBG(CAM_CTXT, "fence error: %d", sync_obj); + flush_cmd.req_id = req->request_id; + cam_context_flush_req_to_hw(ctx, &flush_cmd); + } + + mutex_lock(&ctx->sync_mutex); + if (!req->flushed) { + cam_context_apply_req_to_hw(req, &apply); + mutex_unlock(&ctx->sync_mutex); + } else { + req->flushed = 0; + req->ctx = NULL; + mutex_unlock(&ctx->sync_mutex); + spin_lock(&ctx->lock); + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from pending_list to free_list", + ctx->dev_name, ctx->ctx_id, + req->request_id); + } + } + cam_context_putref(ctx); +} + +int32_t cam_context_release_dev_to_hw(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + struct cam_hw_release_args arg; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input param"); + return -EINVAL; + } + + if ((!ctx->hw_mgr_intf) || (!ctx->hw_mgr_intf->hw_release)) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + + arg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + arg.active_req = false; + + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &arg); + ctx->ctxt_to_hw_map = NULL; + + ctx->session_hdl = -1; + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + + return 0; +} + +int32_t cam_context_config_dev_to_hw( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + size_t len; + struct cam_hw_stream_setttings cfg; + uintptr_t packet_addr; + struct cam_packet *packet; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + return -EINVAL; + } + + if (!ctx->hw_mgr_intf->hw_config_stream_settings) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + return rc; + } + + rc = cam_context_validate_thread(); + if (rc) { + CAM_ERR(CAM_CTXT, + "Not executing in the right context"); + return rc; + } + + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc) { + CAM_ERR(CAM_CTXT, "[%s][%d] Can not get packet address", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + return rc; + } + + packet = (struct cam_packet *) ((uint8_t *)packet_addr + + (uint32_t)cmd->offset); + + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cfg.priv = NULL; + + CAM_DBG(CAM_CTXT, "Processing config settings"); + rc = ctx->hw_mgr_intf->hw_config_stream_settings( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Config failed stream settings", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + } + + return rc; +} + +int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_hw_prepare_update_args cfg; + uintptr_t packet_addr; + struct cam_packet *packet; + size_t len = 0; + size_t remain_len = 0; + int32_t i = 0, j = 0; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + return -EINVAL; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + return -EFAULT; + } + rc = cam_context_validate_thread(); + if (rc) + return rc; + + spin_lock(&ctx->lock); + if (!list_empty(&ctx->free_req_list)) { + req = list_first_entry(&ctx->free_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + } + spin_unlock(&ctx->lock); + + if (!req) { + CAM_ERR(CAM_CTXT, "[%s][%d] No more request obj free", + ctx->dev_name, ctx->ctx_id); + return -ENOMEM; + } + + memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->list); + req->ctx = ctx; + + /* for config dev, only memory handle is supported */ + /* map packet from the memhandle */ + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc != 0) { + CAM_ERR(CAM_CTXT, "[%s][%d] Can not get packet address", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + goto free_req; + } + + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, "Not enough buf"); + return -EINVAL; + + } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_CTXT, "invalid buff length: %zu or offset", len); + rc = -EINVAL; + goto free_req; + } + + remain_len -= (size_t)cmd->offset; + packet = (struct cam_packet *) ((uint8_t *)packet_addr + + (uint32_t)cmd->offset); + + if (packet->header.request_id <= ctx->last_flush_req) { + CAM_ERR(CAM_CORE, + "request %lld has been flushed, reject packet", + packet->header.request_id); + rc = -EINVAL; + goto free_req; + } + + if (packet->header.request_id > ctx->last_flush_req) + ctx->last_flush_req = 0; + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.remain_len = remain_len; + cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cfg.max_hw_update_entries = CAM_CTX_CFG_MAX; + cfg.num_hw_update_entries = req->num_hw_update_entries; + cfg.hw_update_entries = req->hw_update_entries; + cfg.max_out_map_entries = CAM_CTX_CFG_MAX; + cfg.out_map_entries = req->out_map_entries; + cfg.max_in_map_entries = CAM_CTX_CFG_MAX; + cfg.in_map_entries = req->in_map_entries; + cfg.pf_data = &(req->pf_data); + + rc = ctx->hw_mgr_intf->hw_prepare_update( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc != 0) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Prepare config packet failed in HW layer", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto free_req; + } + req->num_hw_update_entries = cfg.num_hw_update_entries; + req->num_out_map_entries = cfg.num_out_map_entries; + req->num_in_map_entries = cfg.num_in_map_entries; + atomic_set(&req->num_in_acked, 0); + req->request_id = packet->header.request_id; + req->status = 1; + req->req_priv = cfg.priv; + + for (i = 0; i < req->num_out_map_entries; i++) { + rc = cam_sync_get_obj_ref(req->out_map_entries[i].sync_id); + if (rc) { + CAM_ERR(CAM_CTXT, "Can't get ref for sync %d", + req->out_map_entries[i].sync_id); + goto put_ref; + } + } + + if (req->num_in_map_entries > 0) { + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->pending_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from free_list to pending_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + for (j = 0; j < req->num_in_map_entries; j++) { + cam_context_getref(ctx); + rc = cam_sync_register_callback( + cam_context_sync_callback, + (void *)req, + req->in_map_entries[j].sync_id); + if (rc) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Failed register fence cb: %d ret = %d", + ctx->dev_name, ctx->ctx_id, + req->in_map_entries[j].sync_id, rc); + spin_lock(&ctx->lock); + list_del_init(&req->list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from pending_list to free_list", + ctx->dev_name, ctx->ctx_id, + req->request_id); + + goto put_ctx_ref; + } + CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", + req->in_map_entries[j].sync_id, rc); + } + } + + return rc; +put_ctx_ref: + for (j; j >= 0; j--) + cam_context_putref(ctx); +put_ref: + for (--i; i >= 0; i--) { + if (cam_sync_put_obj_ref(req->out_map_entries[i].sync_id)) + CAM_ERR(CAM_CTXT, "Failed to put ref of fence %d", + req->out_map_entries[i].sync_id); + } +free_req: + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + req->ctx = NULL; + spin_unlock(&ctx->lock); + + return rc; +} + +int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + struct cam_hw_acquire_args param; + struct cam_create_dev_hdl req_hdl_param; + struct cam_hw_release_args release; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_CTXT, "ses hdl: %x, num_res: %d, type: %d, res: %lld", + cmd->session_handle, cmd->num_resources, cmd->handle_type, + cmd->resource_hdl); + + if (cmd->num_resources > CAM_CTX_RES_MAX) { + CAM_ERR(CAM_CTXT, "[%s][%d] resource limit exceeded", + ctx->dev_name, ctx->ctx_id); + rc = -ENOMEM; + goto end; + } + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_CTXT, "[%s][%d] Only user pointer is supported", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + goto end; + } + + /* fill in parameters */ + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = cmd->num_resources; + param.acquire_info = cmd->resource_hdl; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_CTXT, "[%s][%d] Acquire device failed", + ctx->dev_name, ctx->ctx_id); + goto end; + } + + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + /* if hw resource acquire successful, acquire dev handle */ + req_hdl_param.session_hdl = cmd->session_handle; + /* bridge is not ready for these flags. so false for now */ + req_hdl_param.v4l2_sub_dev_flag = 0; + req_hdl_param.media_entity_flag = 0; + req_hdl_param.priv = ctx; + req_hdl_param.ops = ctx->crm_ctx_intf; + + ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); + if (ctx->dev_hdl <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_CTXT, "[%s][%d] Can not create device handle", + ctx->dev_name, ctx->ctx_id); + goto free_hw; + } + cmd->dev_handle = ctx->dev_hdl; + + /* store session information */ + ctx->session_hdl = cmd->session_handle; + + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); + ctx->ctxt_to_hw_map = NULL; + ctx->dev_hdl = -1; +end: + return rc; +} + +int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) +{ + struct cam_hw_flush_args flush_args; + struct list_head temp_list; + struct cam_ctx_request *req; + uint32_t i; + int rc = 0; + bool free_req; + + CAM_DBG(CAM_CTXT, "[%s] E: NRT flush ctx", ctx->dev_name); + memset(&flush_args, 0, sizeof(flush_args)); + + /* + * flush pending requests, take the sync lock to synchronize with the + * sync callback thread so that the sync cb thread does not try to + * submit request to h/w while the request is being flushed + */ + mutex_lock(&ctx->sync_mutex); + INIT_LIST_HEAD(&temp_list); + spin_lock(&ctx->lock); + list_splice_init(&ctx->pending_req_list, &temp_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving all pending requests from pending_list to temp_list", + ctx->dev_name, ctx->ctx_id); + + flush_args.num_req_pending = 0; + while (true) { + spin_lock(&ctx->lock); + if (list_empty(&temp_list)) { + spin_unlock(&ctx->lock); + break; + } + + req = list_first_entry(&temp_list, + struct cam_ctx_request, list); + + list_del_init(&req->list); + spin_unlock(&ctx->lock); + req->flushed = 1; + + flush_args.flush_req_pending[flush_args.num_req_pending++] = + req->req_priv; + + free_req = false; + for (i = 0; i < req->num_in_map_entries; i++) { + rc = cam_sync_deregister_callback( + cam_context_sync_callback, + (void *)req, + req->in_map_entries[i].sync_id); + if (!rc) { + cam_context_putref(ctx); + if (atomic_inc_return(&req->num_in_acked) == + req->num_in_map_entries) + free_req = true; + } + } + + for (i = 0; i < req->num_out_map_entries; i++) { + if (req->out_map_entries[i].sync_id != -1) { + rc = cam_sync_signal( + req->out_map_entries[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc == -EALREADY) { + CAM_ERR(CAM_CTXT, + "Req: %llu already signalled, sync_id:%d", + req->request_id, + req->out_map_entries[i].sync_id); + break; + } + } + } + + /* + * If we have deregistered the last sync callback, req will + * not be put on the free list. So put it on the free list here + */ + if (free_req) { + req->ctx = NULL; + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + } + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Deleting req[%llu] from temp_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + } + mutex_unlock(&ctx->sync_mutex); + + if (ctx->hw_mgr_intf->hw_flush) { + flush_args.num_req_active = 0; + spin_lock(&ctx->lock); + list_for_each_entry(req, &ctx->active_req_list, list) { + flush_args.flush_req_active[flush_args.num_req_active++] + = req->req_priv; + } + spin_unlock(&ctx->lock); + + if (flush_args.num_req_pending || flush_args.num_req_active) { + flush_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + flush_args.flush_type = CAM_FLUSH_TYPE_ALL; + ctx->hw_mgr_intf->hw_flush( + ctx->hw_mgr_intf->hw_mgr_priv, &flush_args); + } + } + + INIT_LIST_HEAD(&temp_list); + spin_lock(&ctx->lock); + list_splice_init(&ctx->active_req_list, &temp_list); + INIT_LIST_HEAD(&ctx->active_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving all requests from active_list to temp_list", + ctx->dev_name, ctx->ctx_id); + + while (true) { + spin_lock(&ctx->lock); + if (list_empty(&temp_list)) { + spin_unlock(&ctx->lock); + break; + } + req = list_first_entry(&temp_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + spin_unlock(&ctx->lock); + + for (i = 0; i < req->num_out_map_entries; i++) { + if (req->out_map_entries[i].sync_id != -1) { + rc = cam_sync_signal( + req->out_map_entries[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc == -EALREADY) { + CAM_ERR(CAM_CTXT, + "Req: %llu already signalled ctx: %pK dev_name: %s dev_handle: %d ctx_state: %d", + req->request_id, req->ctx, + req->ctx->dev_name, + req->ctx->dev_hdl, + req->ctx->state); + break; + } + } + } + + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + req->ctx = NULL; + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from temp_list to free_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + } + + CAM_DBG(CAM_CTXT, "[%s] X: NRT flush ctx", ctx->dev_name); + + return 0; +} + +int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + struct cam_ctx_request *req = NULL; + struct cam_hw_flush_args flush_args; + uint32_t i; + int32_t sync_id = 0; + int rc = 0; + bool free_req = false; + + CAM_DBG(CAM_CTXT, "[%s] E: NRT flush req", ctx->dev_name); + + memset(&flush_args, 0, sizeof(flush_args)); + flush_args.num_req_pending = 0; + flush_args.num_req_active = 0; + mutex_lock(&ctx->sync_mutex); + spin_lock(&ctx->lock); + list_for_each_entry(req, &ctx->pending_req_list, list) { + if (req->request_id != cmd->req_id) + continue; + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Deleting req[%llu] from pending_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + list_del_init(&req->list); + req->flushed = 1; + + flush_args.flush_req_pending[flush_args.num_req_pending++] = + req->req_priv; + break; + } + spin_unlock(&ctx->lock); + mutex_unlock(&ctx->sync_mutex); + + if (ctx->hw_mgr_intf->hw_flush) { + if (!flush_args.num_req_pending) { + spin_lock(&ctx->lock); + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id != cmd->req_id) + continue; + + list_del_init(&req->list); + + flush_args.flush_req_active[ + flush_args.num_req_active++] = + req->req_priv; + break; + } + spin_unlock(&ctx->lock); + } + + if (flush_args.num_req_pending || flush_args.num_req_active) { + flush_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + flush_args.flush_type = CAM_FLUSH_TYPE_REQ; + ctx->hw_mgr_intf->hw_flush( + ctx->hw_mgr_intf->hw_mgr_priv, &flush_args); + } + } + + if (req) { + if (flush_args.num_req_pending) { + for (i = 0; i < req->num_in_map_entries; i++) { + rc = cam_sync_deregister_callback( + cam_context_sync_callback, + (void *)req, + req->in_map_entries[i].sync_id); + if (rc) + continue; + + cam_context_putref(ctx); + if (atomic_inc_return(&req->num_in_acked) == + req->num_in_map_entries) + free_req = true; + } + } + + if (flush_args.num_req_pending || flush_args.num_req_active) { + for (i = 0; i < req->num_out_map_entries; i++) { + sync_id = + req->out_map_entries[i].sync_id; + if (sync_id != -1) { + rc = cam_sync_signal(sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc == -EALREADY) { + CAM_ERR(CAM_CTXT, + "Req: %llu already signalled, sync_id:%d", + req->request_id, sync_id); + break; + } + } + } + if (flush_args.num_req_active || free_req) { + req->ctx = NULL; + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from %s to free_list", + ctx->dev_name, ctx->ctx_id, + req->request_id, + flush_args.num_req_active ? + "active_list" : + "pending_list"); + } + } + } + CAM_DBG(CAM_CTXT, "[%s] X: NRT flush req", ctx->dev_name); + + return 0; +} + +int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + + int rc = 0; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if (cmd->flush_type == CAM_FLUSH_TYPE_ALL) { + ctx->last_flush_req = cmd->req_id; + rc = cam_context_flush_ctx_to_hw(ctx); + } else if (cmd->flush_type == CAM_FLUSH_TYPE_REQ) + rc = cam_context_flush_req_to_hw(ctx, cmd); + else { + rc = -EINVAL; + CAM_ERR(CAM_CORE, "[%s][%d] Invalid flush type %d", + ctx->dev_name, ctx->ctx_id, cmd->flush_type); + } + +end: + return rc; +} + +int32_t cam_context_start_dev_to_hw(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_start_args arg; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if ((cmd->session_handle != ctx->session_hdl) || + (cmd->dev_handle != ctx->dev_hdl)) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Invalid session hdl[%d], dev_handle[%d]", + ctx->dev_name, ctx->ctx_id, + cmd->session_handle, cmd->dev_handle); + rc = -EPERM; + goto end; + } + + if (ctx->hw_mgr_intf->hw_start) { + arg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &arg); + if (rc) { + /* HW failure. user need to clean up the resource */ + CAM_ERR(CAM_CTXT, "[%s][%d] Start HW failed", + ctx->dev_name, ctx->ctx_id); + goto end; + } + } + +end: + return rc; +} + +int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_stop_args stop; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input param"); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + rc = cam_context_validate_thread(); + if (rc) + goto end; + + rc = cam_context_flush_ctx_to_hw(ctx); + if (rc) + goto end; + + /* stop hw first */ + if (ctx->hw_mgr_intf->hw_stop) { + stop.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop); + } + +end: + return rc; +} + +int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, + struct cam_packet *packet, unsigned long iova, uint32_t buf_info, + bool *mem_found) +{ + int rc = 0; + struct cam_hw_cmd_args cmd_args; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK ", ctx); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if (ctx->hw_mgr_intf->hw_cmd) { + cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cmd_args.cmd_type = CAM_HW_MGR_CMD_DUMP_PF_INFO; + cmd_args.u.pf_args.pf_data.packet = packet; + cmd_args.u.pf_args.iova = iova; + cmd_args.u.pf_args.buf_info = buf_info; + cmd_args.u.pf_args.mem_found = mem_found; + ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &cmd_args); + } + +end: + return rc; +} diff --git a/drivers/cam_core/cam_context_utils.h b/drivers/cam_core/cam_context_utils.h new file mode 100644 index 000000000000..c3483327ba81 --- /dev/null +++ b/drivers/cam_core/cam_context_utils.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CONTEXT_UTILS_H_ +#define _CAM_CONTEXT_UTILS_H_ + +#include + +int cam_context_buf_done_from_hw(struct cam_context *ctx, + void *done_event_data, uint32_t bubble_state); +int32_t cam_context_release_dev_to_hw(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd); +int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd); +int32_t cam_context_config_dev_to_hw( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd); +int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd); +int32_t cam_context_start_dev_to_hw(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); +int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx); +int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); +int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx); +int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); +int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, + struct cam_packet *packet, unsigned long iova, uint32_t buf_info, + bool *mem_found); + +#endif /* _CAM_CONTEXT_UTILS_H_ */ diff --git a/drivers/cam_core/cam_hw.h b/drivers/cam_core/cam_hw.h new file mode 100644 index 000000000000..8ee889fcffb9 --- /dev/null +++ b/drivers/cam_core/cam_hw.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_H_ +#define _CAM_HW_H_ + +#include "cam_soc_util.h" + +/* + * This file declares Enums, Structures and APIs to be used as template + * when writing any HW driver in the camera subsystem. + */ + +/* Hardware state enum */ +enum cam_hw_state { + CAM_HW_STATE_POWER_DOWN, + CAM_HW_STATE_POWER_UP, +}; + +/** + * struct cam_hw_info - Common hardware information + * + * @hw_mutex: Hardware mutex + * @hw_lock: Hardware spinlock + * @hw_complete: Hardware Completion + * @open_count: Count to track the HW enable from the client + * @hw_state: Hardware state + * @soc_info: Platform SOC properties for hardware + * @node_info: Private HW data related to nodes + * @core_info: Private HW data related to core logic + * + */ +struct cam_hw_info { + struct mutex hw_mutex; + spinlock_t hw_lock; + struct completion hw_complete; + uint32_t open_count; + enum cam_hw_state hw_state; + struct cam_hw_soc_info soc_info; + void *node_info; + void *core_info; +}; + +#endif /* _CAM_HW_H_ */ diff --git a/drivers/cam_core/cam_hw_intf.h b/drivers/cam_core/cam_hw_intf.h new file mode 100644 index 000000000000..63e88dd24aea --- /dev/null +++ b/drivers/cam_core/cam_hw_intf.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_INTF_H_ +#define _CAM_HW_INTF_H_ + +#include + +/* + * This file declares Constants, Enums, Structures and APIs to be used as + * Interface between HW driver and HW Manager. + */ + +/** + * struct cam_hw_ops - Hardware layer interface functions + * + * @get_hw_caps: Function pointer for get hw caps + * @init: Function poniter for initialize hardware + * @deinit: Function pointer for deinitialize hardware + * @reset: Function pointer for reset hardware + * @reserve: Function pointer for reserve hardware + * @release: Function pointer for release hardware + * @start: Function pointer for start hardware + * @stop: Function pointer for stop hardware + * @read: Function pointer for read hardware registers + * @write: Function pointer for Write hardware registers + * @process_cmd: Function pointer for additional hardware controls + * @flush_cmd: Function pointer for flush requests + * + */ +struct cam_hw_ops { + int (*get_hw_caps)(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size); + int (*init)(void *hw_priv, + void *init_hw_args, uint32_t arg_size); + int (*deinit)(void *hw_priv, + void *init_hw_args, uint32_t arg_size); + int (*reset)(void *hw_priv, + void *reset_core_args, uint32_t arg_size); + int (*reserve)(void *hw_priv, + void *reserve_args, uint32_t arg_size); + int (*release)(void *hw_priv, + void *release_args, uint32_t arg_size); + int (*start)(void *hw_priv, + void *start_args, uint32_t arg_size); + int (*stop)(void *hw_priv, + void *stop_args, uint32_t arg_size); + int (*read)(void *hw_priv, + void *read_args, uint32_t arg_size); + int (*write)(void *hw_priv, + void *write_args, uint32_t arg_size); + int (*process_cmd)(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + int (*flush)(void *hw_priv, + void *flush_args, uint32_t arg_size); +}; + +/** + * struct cam_hw_intf - Common hardware node + * + * @hw_type: Hardware type + * @hw_idx: Hardware ID + * @hw_ops: Hardware interface function table + * @hw_priv: Private hardware node pointer + * + */ +struct cam_hw_intf { + uint32_t hw_type; + uint32_t hw_idx; + struct cam_hw_ops hw_ops; + void *hw_priv; +}; + +/* hardware event callback function type */ +typedef int (*cam_hw_mgr_event_cb_func)(void *priv, uint32_t evt_id, + void *evt_data); + +#endif /* _CAM_HW_INTF_H_ */ diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h new file mode 100644 index 000000000000..56138c33091d --- /dev/null +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_MGR_INTF_H_ +#define _CAM_HW_MGR_INTF_H_ + +#include +#include +#include +/* + * This file declares Constants, Enums, Structures and APIs to be used as + * Interface between HW Manager and Context. + */ + + +/* maximum context numbers */ +#define CAM_CTX_MAX 8 + +/* maximum buf done irqs */ +#define CAM_NUM_OUT_PER_COMP_IRQ_MAX 12 + +/* hardware event callback function type */ +typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, + void *evt_data); + +/* hardware page fault callback function type */ +typedef int (*cam_hw_pagefault_cb_func)(void *context, unsigned long iova, + uint32_t buf_info); + +/** + * struct cam_hw_update_entry - Entry for hardware config + * + * @handle: Memory handle for the configuration + * @offset: Memory offset + * @len: Size of the configuration + * @flags: Flags for the config entry(eg. DMI) + * @addr: Address of hardware update entry + * + */ +struct cam_hw_update_entry { + int handle; + uint32_t offset; + uint32_t len; + uint32_t flags; + uintptr_t addr; +}; + +/** + * struct cam_hw_fence_map_entry - Entry for the resource to sync id map + * + * @resrouce_handle: Resource port id for the buffer + * @sync_id: Sync id + * + */ +struct cam_hw_fence_map_entry { + uint32_t resource_handle; + int32_t sync_id; +}; + +/** + * struct cam_hw_done_event_data - Payload for hw done event + * + * @num_handles: number of handles in the event + * @resrouce_handle: list of the resource handle + * @timestamp: time stamp + * @request_id: request identifier + * + */ +struct cam_hw_done_event_data { + uint32_t num_handles; + uint32_t resource_handle[CAM_NUM_OUT_PER_COMP_IRQ_MAX]; + struct timeval timestamp; + uint64_t request_id; +}; + +/** + * struct cam_hw_acquire_args - Payload for acquire command + * + * @context_data: Context data pointer for the callback function + * @event_cb: Callback function array + * @num_acq: Total number of acquire in the payload + * @acquire_info: Acquired resource array pointer + * @ctxt_to_hw_map: HW context (returned) + * @acquired_hw_id: Acquired hardware mask + * @acquired_hw_path: Acquired path mask for an input + * if input splits into multiple paths, + * its updated per hardware + * valid_acquired_hw: Valid num of acquired hardware + * + */ +struct cam_hw_acquire_args { + void *context_data; + cam_hw_event_cb_func event_cb; + uint32_t num_acq; + uint32_t acquire_info_size; + uintptr_t acquire_info; + void *ctxt_to_hw_map; + + uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; + uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; + uint32_t valid_acquired_hw; +}; + +/** + * struct cam_hw_release_args - Payload for release command + * + * @ctxt_to_hw_map: HW context from the acquire + * @active_req: Active request flag + * + */ +struct cam_hw_release_args { + void *ctxt_to_hw_map; + bool active_req; +}; + +/** + * struct cam_hw_start_args - Payload for start command + * + * @ctxt_to_hw_map: HW context from the acquire + * @num_hw_update_entries: Number of Hardware configuration + * @hw_update_entries: Hardware configuration list + * + */ +struct cam_hw_start_args { + void *ctxt_to_hw_map; + uint32_t num_hw_update_entries; + struct cam_hw_update_entry *hw_update_entries; +}; + +/** + * struct cam_hw_stop_args - Payload for stop command + * + * @ctxt_to_hw_map: HW context from the acquire + * @args: Arguments to pass for stop + * + */ +struct cam_hw_stop_args { + void *ctxt_to_hw_map; + void *args; +}; + + +/** + * struct cam_hw_mgr_dump_pf_data - page fault debug data + * + * packet: pointer to packet + */ +struct cam_hw_mgr_dump_pf_data { + void *packet; +}; + +/** + * struct cam_hw_prepare_update_args - Payload for prepare command + * + * @packet: CSL packet from user mode driver + * @remain_len Remaining length of CPU buffer after config offset + * @ctxt_to_hw_map: HW context from the acquire + * @max_hw_update_entries: Maximum hardware update entries supported + * @hw_update_entries: Actual hardware update configuration (returned) + * @num_hw_update_entries: Number of actual hardware update entries (returned) + * @max_out_map_entries: Maximum output fence mapping supported + * @out_map_entries: Actual output fence mapping list (returned) + * @num_out_map_entries: Number of actual output fence mapping (returned) + * @max_in_map_entries: Maximum input fence mapping supported + * @in_map_entries: Actual input fence mapping list (returned) + * @num_in_map_entries: Number of acutal input fence mapping (returned) + * @priv: Private pointer of hw update + * @pf_data: Debug data for page fault + * + */ +struct cam_hw_prepare_update_args { + struct cam_packet *packet; + size_t remain_len; + void *ctxt_to_hw_map; + uint32_t max_hw_update_entries; + struct cam_hw_update_entry *hw_update_entries; + uint32_t num_hw_update_entries; + uint32_t max_out_map_entries; + struct cam_hw_fence_map_entry *out_map_entries; + uint32_t num_out_map_entries; + uint32_t max_in_map_entries; + struct cam_hw_fence_map_entry *in_map_entries; + uint32_t num_in_map_entries; + void *priv; + struct cam_hw_mgr_dump_pf_data *pf_data; +}; + +/** + * struct cam_hw_stream_setttings - Payload for config stream command + * + * @packet: CSL packet from user mode driver + * @ctxt_to_hw_map: HW context from the acquire + * @priv: Private pointer of hw update + * + */ +struct cam_hw_stream_setttings { + struct cam_packet *packet; + void *ctxt_to_hw_map; + void *priv; +}; + +/** + * struct cam_hw_config_args - Payload for config command + * + * @ctxt_to_hw_map: HW context from the acquire + * @num_hw_update_entries: Number of hardware update entries + * @hw_update_entries: Hardware update list + * @out_map_entries: Out map info + * @num_out_map_entries: Number of out map entries + * @priv: Private pointer + * @request_id: Request ID + * + */ +struct cam_hw_config_args { + void *ctxt_to_hw_map; + uint32_t num_hw_update_entries; + struct cam_hw_update_entry *hw_update_entries; + struct cam_hw_fence_map_entry *out_map_entries; + uint32_t num_out_map_entries; + void *priv; + uint64_t request_id; + bool init_packet; +}; + +/** + * struct cam_hw_flush_args - Flush arguments + * + * @ctxt_to_hw_map: HW context from the acquire + * @num_req_pending: Num request to flush, valid when flush type is REQ + * @flush_req_pending: Request pending pointers to flush + * @num_req_active: Num request to flush, valid when flush type is REQ + * @flush_req_active: Request active pointers to flush + * @flush_type: The flush type + * + */ +struct cam_hw_flush_args { + void *ctxt_to_hw_map; + uint32_t num_req_pending; + void *flush_req_pending[20]; + uint32_t num_req_active; + void *flush_req_active[20]; + enum flush_type_t flush_type; +}; + +/** + * struct cam_hw_dump_pf_args - Payload for dump pf info command + * + * @pf_data: Debug data for page fault + * @iova: Page fault address + * @buf_info: Info about memory buffer where page + * fault occurred + * @mem_found: If fault memory found in current + * request + * + */ +struct cam_hw_dump_pf_args { + struct cam_hw_mgr_dump_pf_data pf_data; + unsigned long iova; + uint32_t buf_info; + bool *mem_found; +}; + +/* enum cam_hw_mgr_command - Hardware manager command type */ +enum cam_hw_mgr_command { + CAM_HW_MGR_CMD_INTERNAL, + CAM_HW_MGR_CMD_DUMP_PF_INFO, +}; + +/** + * struct cam_hw_cmd_args - Payload for hw manager command + * + * @ctxt_to_hw_map: HW context from the acquire + * @cmd_type HW command type + * @internal_args Arguments for internal command + * @pf_args Arguments for Dump PF info command + * + */ +struct cam_hw_cmd_args { + void *ctxt_to_hw_map; + uint32_t cmd_type; + union { + void *internal_args; + struct cam_hw_dump_pf_args pf_args; + } u; +}; + +/** + * cam_hw_mgr_intf - HW manager interface + * + * @hw_mgr_priv: HW manager object + * @hw_get_caps: Function pointer for get hw caps + * args = cam_query_cap_cmd + * @hw_acquire: Function poniter for acquire hw resources + * args = cam_hw_acquire_args + * @hw_release: Function pointer for release hw device resource + * args = cam_hw_release_args + * @hw_start: Function pointer for start hw devices + * args = cam_hw_start_args + * @hw_stop: Function pointer for stop hw devices + * args = cam_hw_stop_args + * @hw_prepare_update: Function pointer for prepare hw update for hw + * devices args = cam_hw_prepare_update_args + * @hw_config_stream_settings: Function pointer for configure stream for hw + * devices args = cam_hw_stream_setttings + * @hw_config: Function pointer for configure hw devices + * args = cam_hw_config_args + * @hw_read: Function pointer for read hardware registers + * @hw_write: Function pointer for Write hardware registers + * @hw_cmd: Function pointer for any customized commands for + * the hardware manager + * @hw_open: Function pointer for HW init + * @hw_close: Function pointer for HW deinit + * @hw_flush: Function pointer for HW flush + * + */ +struct cam_hw_mgr_intf { + void *hw_mgr_priv; + + int (*hw_get_caps)(void *hw_priv, void *hw_caps_args); + int (*hw_acquire)(void *hw_priv, void *hw_acquire_args); + int (*hw_release)(void *hw_priv, void *hw_release_args); + int (*hw_start)(void *hw_priv, void *hw_start_args); + int (*hw_stop)(void *hw_priv, void *hw_stop_args); + int (*hw_prepare_update)(void *hw_priv, void *hw_prepare_update_args); + int (*hw_config_stream_settings)(void *hw_priv, + void *hw_stream_settings); + int (*hw_config)(void *hw_priv, void *hw_config_args); + int (*hw_read)(void *hw_priv, void *read_args); + int (*hw_write)(void *hw_priv, void *write_args); + int (*hw_cmd)(void *hw_priv, void *write_args); + int (*hw_open)(void *hw_priv, void *fw_download_args); + int (*hw_close)(void *hw_priv, void *hw_close_args); + int (*hw_flush)(void *hw_priv, void *hw_flush_args); +}; + +#endif /* _CAM_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c new file mode 100644 index 000000000000..1ef4aa59302e --- /dev/null +++ b/drivers/cam_core/cam_node.c @@ -0,0 +1,836 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include + +#include "cam_node.h" +#include "cam_trace.h" +#include "cam_debug_util.h" + +static void cam_node_print_ctx_state( + struct cam_node *node) +{ + int i; + struct cam_context *ctx; + + CAM_INFO(CAM_CORE, "[%s] state=%d, ctx_size %d", + node->name, node->state, node->ctx_size); + + mutex_lock(&node->list_mutex); + for (i = 0; i < node->ctx_size; i++) { + ctx = &node->ctx_list[i]; + + spin_lock_bh(&ctx->lock); + CAM_INFO(CAM_CORE, + "[%s][%d] : state=%d, refcount=%d, active_req_list=%d, pending_req_list=%d, wait_req_list=%d, free_req_list=%d", + ctx->dev_name ? ctx->dev_name : "null", + i, ctx->state, + atomic_read(&(ctx->refcount.refcount.refs)), + list_empty(&ctx->active_req_list), + list_empty(&ctx->pending_req_list), + list_empty(&ctx->wait_req_list), + list_empty(&ctx->free_req_list)); + spin_unlock_bh(&ctx->lock); + } + mutex_unlock(&node->list_mutex); +} + +static struct cam_context *cam_node_get_ctxt_from_free_list( + struct cam_node *node) +{ + struct cam_context *ctx = NULL; + + mutex_lock(&node->list_mutex); + if (!list_empty(&node->free_ctx_list)) { + ctx = list_first_entry(&node->free_ctx_list, + struct cam_context, list); + list_del_init(&ctx->list); + } + mutex_unlock(&node->list_mutex); + if (ctx) + kref_init(&ctx->refcount); + return ctx; +} + +void cam_node_put_ctxt_to_free_list(struct kref *ref) +{ + struct cam_context *ctx = + container_of(ref, struct cam_context, refcount); + struct cam_node *node = ctx->node; + + mutex_lock(&node->list_mutex); + list_add_tail(&ctx->list, &node->free_ctx_list); + mutex_unlock(&node->list_mutex); +} + +static int __cam_node_handle_query_cap(struct cam_node *node, + struct cam_query_cap_cmd *query) +{ + int rc = -EFAULT; + + if (!query) { + CAM_ERR(CAM_CORE, "Invalid params"); + return -EINVAL; + } + + if (node->hw_mgr_intf.hw_get_caps) { + rc = node->hw_mgr_intf.hw_get_caps( + node->hw_mgr_intf.hw_mgr_priv, query); + } + + return rc; +} + +static int __cam_node_handle_acquire_dev(struct cam_node *node, + struct cam_acquire_dev_cmd *acquire) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!acquire) + return -EINVAL; + + ctx = cam_node_get_ctxt_from_free_list(node); + if (!ctx) { + CAM_ERR(CAM_CORE, "No free ctx in free list node %s", + node->name); + cam_node_print_ctx_state(node); + + rc = -ENOMEM; + goto err; + } + + ctx->last_flush_req = 0; + rc = cam_context_handle_acquire_dev(ctx, acquire); + if (rc) { + CAM_ERR(CAM_CORE, "Acquire device failed for node %s", + node->name); + goto free_ctx; + } + + CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d", + node->name, ctx->ctx_id); + + return 0; +free_ctx: + cam_context_putref(ctx); +err: + return rc; +} + +static int __cam_node_handle_acquire_hw_v1(struct cam_node *node, + struct cam_acquire_hw_cmd_v1 *acquire) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!acquire) + return -EINVAL; + + if (acquire->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (acquire->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(acquire->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + acquire->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_acquire_hw(ctx, acquire); + if (rc) { + CAM_ERR(CAM_CORE, "Acquire device failed for node %s", + node->name); + return rc; + } + + CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d", + node->name, ctx->ctx_id); + + return 0; +} + +static int __cam_node_handle_acquire_hw_v2(struct cam_node *node, + struct cam_acquire_hw_cmd_v2 *acquire) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!acquire) + return -EINVAL; + + if (acquire->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (acquire->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(acquire->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + acquire->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_acquire_hw(ctx, acquire); + if (rc) { + CAM_ERR(CAM_CORE, "Acquire device failed for node %s", + node->name); + return rc; + } + + CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d", + node->name, ctx->ctx_id); + + return 0; +} + +static int __cam_node_handle_start_dev(struct cam_node *node, + struct cam_start_stop_dev_cmd *start) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!start) + return -EINVAL; + + if (start->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (start->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(start->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + start->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_start_dev(ctx, start); + if (rc) + CAM_ERR(CAM_CORE, "Start failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_stop_dev(struct cam_node *node, + struct cam_start_stop_dev_cmd *stop) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!stop) + return -EINVAL; + + if (stop->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (stop->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(stop->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + stop->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_stop_dev(ctx, stop); + if (rc) + CAM_ERR(CAM_CORE, "Stop failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_config_dev(struct cam_node *node, + struct cam_config_dev_cmd *config) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!config) + return -EINVAL; + + if (config->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (config->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(config->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + config->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_config_dev(ctx, config); + if (rc) + CAM_ERR(CAM_CORE, "Config failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_flush_dev(struct cam_node *node, + struct cam_flush_dev_cmd *flush) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!flush) + return -EINVAL; + + if (flush->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (flush->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(flush->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + flush->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_flush_dev(ctx, flush); + if (rc) + CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_release_dev(struct cam_node *node, + struct cam_release_dev_cmd *release) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!release) + return -EINVAL; + + if (release->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (release->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(release->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d node %s", + release->dev_handle, node->name); + return -EINVAL; + } + + if (ctx->state > CAM_CTX_UNINIT && ctx->state < CAM_CTX_STATE_MAX) { + rc = cam_context_handle_release_dev(ctx, release); + if (rc) + CAM_ERR(CAM_CORE, "context release failed for node %s", + node->name); + } else { + CAM_WARN(CAM_CORE, + "node %s context id %u state %d invalid to release hdl", + node->name, ctx->ctx_id, ctx->state); + goto destroy_dev_hdl; + } + + cam_context_putref(ctx); + +destroy_dev_hdl: + rc = cam_destroy_device_hdl(release->dev_handle); + if (rc) + CAM_ERR(CAM_CORE, "destroy device hdl failed for node %s", + node->name); + else + ctx->dev_hdl = -1; + + CAM_DBG(CAM_CORE, "[%s] Release ctx_id=%d, refcount=%d", + node->name, ctx->ctx_id, + atomic_read(&(ctx->refcount.refcount.refs))); + + return rc; +} + +static int __cam_node_handle_release_hw_v1(struct cam_node *node, + struct cam_release_hw_cmd_v1 *release) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!release) + return -EINVAL; + + if (release->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (release->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(release->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d node %s", + release->dev_handle, node->name); + return -EINVAL; + } + + rc = cam_context_handle_release_hw(ctx, release); + if (rc) + CAM_ERR(CAM_CORE, "context release failed node %s", node->name); + + CAM_DBG(CAM_CORE, "[%s] Release ctx_id=%d, refcount=%d", + node->name, ctx->ctx_id, + atomic_read(&(ctx->refcount.refcount.refs))); + + return rc; +} + +static int __cam_node_crm_get_dev_info(struct cam_req_mgr_device_info *info) +{ + struct cam_context *ctx = NULL; + + if (!info) + return -EINVAL; + + ctx = (struct cam_context *) cam_get_device_priv(info->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + info->dev_hdl); + return -EINVAL; + } + return cam_context_handle_crm_get_dev_info(ctx, info); +} + +static int __cam_node_crm_link_setup( + struct cam_req_mgr_core_dev_link_setup *setup) +{ + int rc; + struct cam_context *ctx = NULL; + + if (!setup) + return -EINVAL; + + ctx = (struct cam_context *) cam_get_device_priv(setup->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + setup->dev_hdl); + return -EINVAL; + } + + if (setup->link_enable) + rc = cam_context_handle_crm_link(ctx, setup); + else + rc = cam_context_handle_crm_unlink(ctx, setup); + + return rc; +} + +static int __cam_node_crm_apply_req(struct cam_req_mgr_apply_request *apply) +{ + struct cam_context *ctx = NULL; + + if (!apply) + return -EINVAL; + + ctx = (struct cam_context *) cam_get_device_priv(apply->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + apply->dev_hdl); + return -EINVAL; + } + + trace_cam_apply_req("Node", apply->request_id); + + return cam_context_handle_crm_apply_req(ctx, apply); +} + +static int __cam_node_crm_flush_req(struct cam_req_mgr_flush_request *flush) +{ + struct cam_context *ctx = NULL; + + if (!flush) { + CAM_ERR(CAM_CORE, "Invalid flush request payload"); + return -EINVAL; + } + + ctx = (struct cam_context *) cam_get_device_priv(flush->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + flush->dev_hdl); + return -EINVAL; + } + + return cam_context_handle_crm_flush_req(ctx, flush); +} + +static int __cam_node_crm_process_evt( + struct cam_req_mgr_link_evt_data *evt_data) +{ + struct cam_context *ctx = NULL; + + if (!evt_data) { + CAM_ERR(CAM_CORE, "Invalid process event request payload"); + return -EINVAL; + } + + ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + evt_data->dev_hdl); + return -EINVAL; + } + return cam_context_handle_crm_process_evt(ctx, evt_data); +} + +int cam_node_deinit(struct cam_node *node) +{ + if (node) + memset(node, 0, sizeof(*node)); + + CAM_DBG(CAM_CORE, "deinit complete"); + + return 0; +} + +int cam_node_shutdown(struct cam_node *node) +{ + int i = 0; + int rc = 0; + + if (!node) + return -EINVAL; + + for (i = 0; i < node->ctx_size; i++) { + if (node->ctx_list[i].dev_hdl > 0) { + CAM_DBG(CAM_CORE, + "Node [%s] invoking shutdown on context [%d]", + node->name, i); + rc = cam_context_shutdown(&(node->ctx_list[i])); + } + } + + if (node->hw_mgr_intf.hw_close) + node->hw_mgr_intf.hw_close(node->hw_mgr_intf.hw_mgr_priv, + NULL); + + return 0; +} + +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) +{ + int rc = 0; + int i; + + if (!node || !hw_mgr_intf || + sizeof(node->hw_mgr_intf) != sizeof(*hw_mgr_intf)) { + return -EINVAL; + } + + memset(node, 0, sizeof(*node)); + + strlcpy(node->name, name, sizeof(node->name)); + + memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf)); + node->crm_node_intf.apply_req = __cam_node_crm_apply_req; + node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info; + node->crm_node_intf.link_setup = __cam_node_crm_link_setup; + node->crm_node_intf.flush_req = __cam_node_crm_flush_req; + node->crm_node_intf.process_evt = __cam_node_crm_process_evt; + + mutex_init(&node->list_mutex); + INIT_LIST_HEAD(&node->free_ctx_list); + node->ctx_list = ctx_list; + node->ctx_size = ctx_size; + for (i = 0; i < ctx_size; i++) { + if (!ctx_list[i].state_machine) { + CAM_ERR(CAM_CORE, + "camera context %d is not initialized", i); + rc = -1; + goto err; + } + INIT_LIST_HEAD(&ctx_list[i].list); + list_add_tail(&ctx_list[i].list, &node->free_ctx_list); + ctx_list[i].node = node; + } + + node->state = CAM_NODE_STATE_INIT; +err: + CAM_DBG(CAM_CORE, "Exit. (rc = %d)", rc); + return rc; +} + +int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) +{ + int rc = 0; + + if (!cmd) + return -EINVAL; + + CAM_DBG(CAM_CORE, "handle cmd %d", cmd->op_code); + + switch (cmd->op_code) { + case CAM_QUERY_CAP: { + struct cam_query_cap_cmd query; + + if (copy_from_user(&query, u64_to_user_ptr(cmd->handle), + sizeof(query))) { + rc = -EFAULT; + break; + } + + rc = __cam_node_handle_query_cap(node, &query); + if (rc) { + CAM_ERR(CAM_CORE, "querycap is failed(rc = %d)", + rc); + break; + } + + if (copy_to_user(u64_to_user_ptr(cmd->handle), &query, + sizeof(query))) + rc = -EFAULT; + + break; + } + case CAM_ACQUIRE_DEV: { + struct cam_acquire_dev_cmd acquire; + + if (copy_from_user(&acquire, u64_to_user_ptr(cmd->handle), + sizeof(acquire))) { + rc = -EFAULT; + break; + } + rc = __cam_node_handle_acquire_dev(node, &acquire); + if (rc) { + CAM_ERR(CAM_CORE, "acquire device failed(rc = %d)", + rc); + break; + } + if (copy_to_user(u64_to_user_ptr(cmd->handle), &acquire, + sizeof(acquire))) + rc = -EFAULT; + break; + } + case CAM_ACQUIRE_HW: { + uint32_t api_version; + void *acquire_ptr = NULL; + size_t acquire_size; + + if (copy_from_user(&api_version, (void __user *)cmd->handle, + sizeof(api_version))) { + rc = -EFAULT; + break; + } + + if (api_version == 1) { + acquire_size = sizeof(struct cam_acquire_hw_cmd_v1); + } else if (api_version == 2) { + acquire_size = sizeof(struct cam_acquire_hw_cmd_v2); + } else { + CAM_ERR(CAM_CORE, "Unsupported api version %d", + api_version); + rc = -EINVAL; + break; + } + + acquire_ptr = kzalloc(acquire_size, GFP_KERNEL); + if (!acquire_ptr) { + CAM_ERR(CAM_CORE, "No memory for acquire HW"); + rc = -ENOMEM; + break; + } + + if (copy_from_user(acquire_ptr, (void __user *)cmd->handle, + acquire_size)) { + rc = -EFAULT; + goto acquire_kfree; + } + + if (api_version == 1) { + rc = __cam_node_handle_acquire_hw_v1(node, acquire_ptr); + if (rc) { + CAM_ERR(CAM_CORE, + "acquire device failed(rc = %d)", rc); + goto acquire_kfree; + } + CAM_INFO(CAM_CORE, "Acquire HW successful"); + } else if (api_version == 2) { + rc = __cam_node_handle_acquire_hw_v2(node, acquire_ptr); + if (rc) { + CAM_ERR(CAM_CORE, + "acquire device failed(rc = %d)", rc); + goto acquire_kfree; + } + CAM_INFO(CAM_CORE, "Acquire HW successful"); + } + + if (copy_to_user((void __user *)cmd->handle, acquire_ptr, + acquire_size)) + rc = -EFAULT; + +acquire_kfree: + kfree(acquire_ptr); + break; + } + case CAM_START_DEV: { + struct cam_start_stop_dev_cmd start; + + if (copy_from_user(&start, u64_to_user_ptr(cmd->handle), + sizeof(start))) + rc = -EFAULT; + else { + rc = __cam_node_handle_start_dev(node, &start); + if (rc) + CAM_ERR(CAM_CORE, + "start device failed(rc = %d)", rc); + } + break; + } + case CAM_STOP_DEV: { + struct cam_start_stop_dev_cmd stop; + + if (copy_from_user(&stop, u64_to_user_ptr(cmd->handle), + sizeof(stop))) + rc = -EFAULT; + else { + rc = __cam_node_handle_stop_dev(node, &stop); + if (rc) + CAM_ERR(CAM_CORE, + "stop device failed(rc = %d)", rc); + } + break; + } + case CAM_CONFIG_DEV: { + struct cam_config_dev_cmd config; + + if (copy_from_user(&config, u64_to_user_ptr(cmd->handle), + sizeof(config))) + rc = -EFAULT; + else { + rc = __cam_node_handle_config_dev(node, &config); + if (rc) + CAM_ERR(CAM_CORE, + "config device failed(rc = %d)", rc); + } + break; + } + case CAM_RELEASE_DEV: { + struct cam_release_dev_cmd release; + + if (copy_from_user(&release, u64_to_user_ptr(cmd->handle), + sizeof(release))) + rc = -EFAULT; + else { + rc = __cam_node_handle_release_dev(node, &release); + if (rc) + CAM_ERR(CAM_CORE, + "release device failed(rc = %d)", rc); + } + break; + } + case CAM_RELEASE_HW: { + uint32_t api_version; + size_t release_size; + void *release_ptr = NULL; + + if (copy_from_user(&api_version, (void __user *)cmd->handle, + sizeof(api_version))) { + rc = -EFAULT; + break; + } + + if (api_version == 1) { + release_size = sizeof(struct cam_release_hw_cmd_v1); + } else { + CAM_ERR(CAM_CORE, "Unsupported api version %d", + api_version); + rc = -EINVAL; + break; + } + + release_ptr = kzalloc(release_size, GFP_KERNEL); + if (!release_ptr) { + CAM_ERR(CAM_CORE, "No memory for release HW"); + rc = -ENOMEM; + break; + } + + if (copy_from_user(release_ptr, (void __user *)cmd->handle, + release_size)) { + rc = -EFAULT; + goto release_kfree; + } + + if (api_version == 1) { + rc = __cam_node_handle_release_hw_v1(node, release_ptr); + if (rc) + CAM_ERR(CAM_CORE, + "release device failed(rc = %d)", rc); + } + + CAM_INFO(CAM_CORE, "Release HW done(rc = %d)", rc); + +release_kfree: + kfree(release_ptr); + break; + } + case CAM_FLUSH_REQ: { + struct cam_flush_dev_cmd flush; + + if (copy_from_user(&flush, u64_to_user_ptr(cmd->handle), + sizeof(flush))) + rc = -EFAULT; + else { + rc = __cam_node_handle_flush_dev(node, &flush); + if (rc) + CAM_ERR(CAM_CORE, + "flush device failed(rc = %d)", rc); + } + break; + } + default: + CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code); + rc = -EINVAL; + } + + return rc; +} diff --git a/drivers/cam_core/cam_node.h b/drivers/cam_core/cam_node.h new file mode 100644 index 000000000000..ad49c4b619a9 --- /dev/null +++ b/drivers/cam_core/cam_node.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_NODE_H_ +#define _CAM_NODE_H_ + +#include +#include "cam_context.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_interface.h" + +#define CAM_NODE_NAME_LENGTH_MAX 256 + +#define CAM_NODE_STATE_UNINIT 0 +#define CAM_NODE_STATE_INIT 1 + +/** + * struct cam_node - Singleton Node for camera HW devices + * + * @name: Name for struct cam_node + * @state: Node state: + * 0 = uninitialized, 1 = initialized + * @list_mutex: Mutex for the context pool + * @free_ctx_list: Free context pool list + * @ctx_list: Context list + * @ctx_size: Context list size + * @hw_mgr_intf: Interface for cam_node to HW + * @crm_node_intf: Interface for the CRM to cam_node + * + */ +struct cam_node { + char name[CAM_NODE_NAME_LENGTH_MAX]; + uint32_t state; + + /* context pool */ + struct mutex list_mutex; + struct list_head free_ctx_list; + struct cam_context *ctx_list; + uint32_t ctx_size; + + /* interfaces */ + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_req_mgr_kmd_ops crm_node_intf; +}; + +/** + * cam_node_handle_ioctl() + * + * @brief: Handle ioctl commands + * + * @node: Node handle + * @cmd: IOCTL command + * + */ +int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd); + +/** + * cam_node_deinit() + * + * @brief: Deinitialization function for the Node interface + * + * @node: Node handle + * + */ +int cam_node_deinit(struct cam_node *node); + +/** + * cam_node_shutdown() + * + * @brief: Shutdowns/Closes the cam node. + * + * @node: Cam_node pointer + * + */ +int cam_node_shutdown(struct cam_node *node); + +/** + * cam_node_init() + * + * @brief: Initialization function for the Node interface. + * + * @node: Cam_node pointer + * @hw_mgr_intf: HW manager interface blob + * @ctx_list: List of cam_contexts to be added + * @ctx_size: Size of the cam_context + * @name: Name for the node + * + */ +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); + +/** + * cam_node_put_ctxt_to_free_list() + * + * @brief: Put context in node free list. + * + * @ref: Context's kref object + * + */ +void cam_node_put_ctxt_to_free_list(struct kref *ref); + +#endif /* _CAM_NODE_H_ */ diff --git a/drivers/cam_core/cam_subdev.c b/drivers/cam_core/cam_subdev.c new file mode 100644 index 000000000000..1a81a4d59e99 --- /dev/null +++ b/drivers/cam_core/cam_subdev.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_debug_util.h" + +/** + * cam_subdev_subscribe_event() + * + * @brief: function to subscribe to v4l2 events + * + * @sd: Pointer to struct v4l2_subdev. + * @fh: Pointer to struct v4l2_fh. + * @sub: Pointer to struct v4l2_event_subscription. + */ +static int cam_subdev_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, CAM_SUBDEVICE_EVENT_MAX, NULL); +} + +/** + * cam_subdev_unsubscribe_event() + * + * @brief: function to unsubscribe from v4l2 events + * + * @sd: Pointer to struct v4l2_subdev. + * @fh: Pointer to struct v4l2_fh. + * @sub: Pointer to struct v4l2_event_subscription. + */ +static int cam_subdev_unsubscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, + void *arg) +{ + long rc; + struct cam_node *node = + (struct cam_node *) v4l2_get_subdevdata(sd); + + if (!node || node->state == CAM_NODE_STATE_UNINIT) { + rc = -EINVAL; + goto end; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_node_handle_ioctl(node, + (struct cam_control *) arg); + break; + default: + CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd, + node->name); + rc = -EINVAL; + } +end: + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int rc; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_CORE, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + rc = cam_subdev_ioctl(sd, cmd, &cmd_data); + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_CORE, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +const struct v4l2_subdev_core_ops cam_subdev_core_ops = { + .ioctl = cam_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_subdev_compat_ioctl, +#endif + .subscribe_event = cam_subdev_subscribe_event, + .unsubscribe_event = cam_subdev_unsubscribe_event, +}; + +static const struct v4l2_subdev_ops cam_subdev_ops = { + .core = &cam_subdev_core_ops, +}; + +int cam_subdev_remove(struct cam_subdev *sd) +{ + if (!sd) + return -EINVAL; + + cam_unregister_subdev(sd); + cam_node_deinit((struct cam_node *)sd->token); + kfree(sd->token); + + return 0; +} + +int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev, + char *name, uint32_t dev_type) +{ + int rc; + struct cam_node *node = NULL; + + if (!sd || !pdev || !name) + return -EINVAL; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + /* Setup camera v4l2 subdevice */ + sd->pdev = pdev; + sd->name = name; + sd->ops = &cam_subdev_ops; + sd->token = node; + sd->sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->ent_function = dev_type; + + rc = cam_register_subdev(sd); + if (rc) { + CAM_ERR(CAM_CORE, "cam_register_subdev() failed for dev: %s", + sd->name); + goto err; + } + platform_set_drvdata(sd->pdev, sd); + return rc; +err: + kfree(node); + return rc; +} diff --git a/drivers/cam_cpas/Makefile b/drivers/cam_cpas/Makefile new file mode 100644 index 000000000000..e0af486932f1 --- /dev/null +++ b/drivers/cam_cpas/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +#ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/cpas_top +#ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/camss_top +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree) + +obj-$(CONFIG_SPECTRA_CAMERA) += cpas_top/ +obj-$(CONFIG_SPECTRA_CAMERA) += camss_top/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas_soc.o cam_cpas_intf.o cam_cpas_hw.o \ No newline at end of file diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c new file mode 100644 index 000000000000..f7bf5a22129f --- /dev/null +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -0,0 +1,1857 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_cpas_hw.h" +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_soc.h" + +static uint cam_min_camnoc_ib_bw; +module_param(cam_min_camnoc_ib_bw, uint, 0644); + + +int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, + enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + uint32_t value; + int reg_base_index; + + if (reg_info->enable == false) + return 0; + + reg_base_index = cpas_core->regbase_index[reg_base]; + if (reg_base_index == -1) + return -EINVAL; + + if (reg_info->masked_value) { + value = cam_io_r_mb( + soc_info->reg_map[reg_base_index].mem_base + + reg_info->offset); + value = value & (~reg_info->mask); + value = value | (reg_info->value << reg_info->shift); + } else { + value = reg_info->value; + } + + CAM_DBG(CAM_CPAS, "Base[%d] Offset[0x%8x] Value[0x%8x]", + reg_base, reg_info->offset, value); + + cam_io_w_mb(value, soc_info->reg_map[reg_base_index].mem_base + + reg_info->offset); + + return 0; +} + +static int cam_cpas_util_vote_bus_client_level( + struct cam_cpas_bus_client *bus_client, unsigned int level) +{ + if (!bus_client->valid || (bus_client->dyn_vote == true)) { + CAM_ERR(CAM_CPAS, "Invalid params %d %d", bus_client->valid, + bus_client->dyn_vote); + return -EINVAL; + } + + if (level >= bus_client->num_usecases) { + CAM_ERR(CAM_CPAS, "Invalid vote level=%d, usecases=%d", level, + bus_client->num_usecases); + return -EINVAL; + } + + if (level == bus_client->curr_vote_level) + return 0; + + CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] index[%d]", + bus_client->client_id, bus_client->name, level); + msm_bus_scale_client_update_request(bus_client->client_id, level); + bus_client->curr_vote_level = level; + + return 0; +} + +static int cam_cpas_util_vote_bus_client_bw( + struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, + bool camnoc_bw) +{ + struct msm_bus_paths *path; + struct msm_bus_scale_pdata *pdata; + int idx = 0; + uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + + if (cam_min_camnoc_ib_bw > 0) + min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L; + + CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu", + cam_min_camnoc_ib_bw, min_camnoc_ib_bw); + + if (!bus_client->valid) { + CAM_ERR(CAM_CPAS, "bus client not valid"); + return -EINVAL; + } + + if ((bus_client->num_usecases != 2) || + (bus_client->num_paths != 1) || + (bus_client->dyn_vote != true)) { + CAM_ERR(CAM_CPAS, "dynamic update not allowed %d %d %d", + bus_client->num_usecases, bus_client->num_paths, + bus_client->dyn_vote); + return -EINVAL; + } + + mutex_lock(&bus_client->lock); + + if (bus_client->curr_vote_level > 1) { + CAM_ERR(CAM_CPAS, "curr_vote_level %d cannot be greater than 1", + bus_client->curr_vote_level); + mutex_unlock(&bus_client->lock); + return -EINVAL; + } + + idx = bus_client->curr_vote_level; + idx = 1 - idx; + bus_client->curr_vote_level = idx; + mutex_unlock(&bus_client->lock); + + if (camnoc_bw == true) { + if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW)) + ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW; + + if ((ib > 0) && (ib < min_camnoc_ib_bw)) + ib = min_camnoc_ib_bw; + } else { + if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW)) + ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW; + + if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW)) + ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW; + } + + pdata = bus_client->pdata; + path = &(pdata->usecase[idx]); + path->vectors[0].ab = ab; + path->vectors[0].ib = ib; + + CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", + bus_client->client_id, bus_client->name, ab, ib, idx); + msm_bus_scale_client_update_request(bus_client->client_id, idx); + + return 0; +} + +static int cam_cpas_util_register_bus_client( + struct cam_hw_soc_info *soc_info, struct device_node *dev_node, + struct cam_cpas_bus_client *bus_client) +{ + struct msm_bus_scale_pdata *pdata = NULL; + uint32_t client_id; + int rc; + + pdata = msm_bus_pdata_from_node(soc_info->pdev, + dev_node); + if (!pdata) { + CAM_ERR(CAM_CPAS, "failed get_pdata"); + return -EINVAL; + } + + if ((pdata->num_usecases == 0) || + (pdata->usecase[0].num_paths == 0)) { + CAM_ERR(CAM_CPAS, "usecase=%d", pdata->num_usecases); + rc = -EINVAL; + goto error; + } + + client_id = msm_bus_scale_register_client(pdata); + if (!client_id) { + CAM_ERR(CAM_CPAS, "failed in register ahb bus client"); + rc = -EINVAL; + goto error; + } + + bus_client->dyn_vote = of_property_read_bool(dev_node, + "qcom,msm-bus-vector-dyn-vote"); + + if (bus_client->dyn_vote && (pdata->num_usecases != 2)) { + CAM_ERR(CAM_CPAS, "Excess or less vectors %d", + pdata->num_usecases); + rc = -EINVAL; + goto fail_unregister_client; + } + + msm_bus_scale_client_update_request(client_id, 0); + + bus_client->src = pdata->usecase[0].vectors[0].src; + bus_client->dst = pdata->usecase[0].vectors[0].dst; + bus_client->pdata = pdata; + bus_client->client_id = client_id; + bus_client->num_usecases = pdata->num_usecases; + bus_client->num_paths = pdata->usecase[0].num_paths; + bus_client->curr_vote_level = 0; + bus_client->valid = true; + bus_client->name = pdata->name; + mutex_init(&bus_client->lock); + + CAM_DBG(CAM_CPAS, "Bus Client=[%d][%s] : src=%d, dst=%d", + bus_client->client_id, bus_client->name, + bus_client->src, bus_client->dst); + + return 0; +fail_unregister_client: + msm_bus_scale_unregister_client(bus_client->client_id); +error: + return rc; + +} + +static int cam_cpas_util_unregister_bus_client( + struct cam_cpas_bus_client *bus_client) +{ + if (!bus_client->valid) + return -EINVAL; + + if (bus_client->dyn_vote) + cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); + else + cam_cpas_util_vote_bus_client_level(bus_client, 0); + + msm_bus_scale_unregister_client(bus_client->client_id); + bus_client->valid = false; + + mutex_destroy(&bus_client->lock); + + return 0; +} + +static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info) +{ + int i = 0; + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + cam_cpas_util_unregister_bus_client( + &cpas_core->axi_port[i].bus_client); + of_node_put(cpas_core->axi_port[i].axi_port_node); + cpas_core->axi_port[i].axi_port_node = NULL; + } + + return 0; +} + +static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info) +{ + int i = 0, rc = 0; + struct device_node *axi_port_mnoc_node = NULL; + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + axi_port_mnoc_node = cpas_core->axi_port[i].axi_port_node; + rc = cam_cpas_util_register_bus_client(soc_info, + axi_port_mnoc_node, &cpas_core->axi_port[i].bus_client); + if (rc) + goto bus_register_fail; + } + + return 0; +bus_register_fail: + of_node_put(cpas_core->axi_port[i].axi_port_node); + return rc; +} + +static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, + int enable) +{ + int rc, i = 0; + struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; + uint64_t ab_bw, ib_bw; + + rc = cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, + (enable == true) ? CAM_SVS_VOTE : CAM_SUSPEND_VOTE); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in AHB vote, enable=%d, rc=%d", + enable, rc); + return rc; + } + + if (enable) { + ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + } else { + ab_bw = 0; + ib_bw = 0; + } + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + rc = cam_cpas_util_vote_bus_client_bw( + &cpas_core->axi_port[i].bus_client, + ab_bw, ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote, enable=%d, rc=%d", + enable, rc); + goto remove_ahb_vote; + } + } + + return 0; +remove_ahb_vote: + cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, + CAM_SUSPEND_VOTE); + return rc; +} + +static int cam_cpas_hw_reg_write(struct cam_hw_info *cpas_hw, + uint32_t client_handle, enum cam_cpas_reg_base reg_base, + uint32_t offset, bool mb, uint32_t value) +{ + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + int reg_base_index = cpas_core->regbase_index[reg_base]; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (reg_base_index < 0 || reg_base_index >= soc_info->num_reg_map) { + CAM_ERR(CAM_CPAS, + "Invalid reg_base=%d, reg_base_index=%d, num_map=%d", + reg_base, reg_base_index, soc_info->num_reg_map); + return -EINVAL; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto unlock_client; + } + + if (mb) + cam_io_w_mb(value, + soc_info->reg_map[reg_base_index].mem_base + offset); + else + cam_io_w(value, + soc_info->reg_map[reg_base_index].mem_base + offset); + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + return rc; +} + +static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, + uint32_t client_handle, enum cam_cpas_reg_base reg_base, + uint32_t offset, bool mb, uint32_t *value) +{ + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + int reg_base_index = cpas_core->regbase_index[reg_base]; + uint32_t reg_value; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!value) + return -EINVAL; + + if (reg_base_index < 0 || reg_base_index >= soc_info->num_reg_map) { + CAM_ERR(CAM_CPAS, + "Invalid reg_base=%d, reg_base_index=%d, num_map=%d", + reg_base, reg_base_index, soc_info->num_reg_map); + return -EINVAL; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto unlock_client; + } + + if (mb) + reg_value = cam_io_r_mb( + soc_info->reg_map[reg_base_index].mem_base + offset); + else + reg_value = cam_io_r( + soc_info->reg_map[reg_base_index].mem_base + offset); + + *value = reg_value; + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + return rc; +} + +static int cam_cpas_util_set_camnoc_axi_clk_rate( + struct cam_hw_info *cpas_hw) +{ + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_tree_node *tree_node = NULL; + int rc = 0, i = 0; + + CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d", + soc_private->control_camnoc_axi_clk); + + if (soc_private->control_camnoc_axi_clk) { + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + uint64_t required_camnoc_bw = 0; + int32_t clk_rate = 0; + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + tree_node = soc_private->tree_node[i]; + if (!tree_node || + !tree_node->camnoc_max_needed) + continue; + + if (required_camnoc_bw < (tree_node->camnoc_bw * + tree_node->bus_width_factor)) { + required_camnoc_bw = tree_node->camnoc_bw * + tree_node->bus_width_factor; + } + } + + required_camnoc_bw += (required_camnoc_bw * + soc_private->camnoc_axi_clk_bw_margin) / 100; + + if ((required_camnoc_bw > 0) && + (required_camnoc_bw < + soc_private->camnoc_axi_min_ib_bw)) + required_camnoc_bw = soc_private->camnoc_axi_min_ib_bw; + + clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; + + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", + required_camnoc_bw, clk_rate); + + /* + * CPAS hw is not powered on for the first client. + * Also, clk_rate will be overwritten with default + * value while power on. So, skipping this for first + * client. + */ + if (cpas_core->streamon_clients) { + rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_CPAS, + "Failed in setting camnoc axi clk %llu %d %d", + required_camnoc_bw, clk_rate, rc); + } + } + + return rc; +} + +static int cam_cpas_util_translate_client_paths( + struct cam_axi_vote *axi_vote) +{ + int i; + uint32_t *path_data_type = NULL; + + if (!axi_vote) + return -EINVAL; + + for (i = 0; i < axi_vote->num_paths; i++) { + path_data_type = &axi_vote->axi_path[i].path_data_type; + /* Update path_data_type from UAPI value to internal value */ + if (*path_data_type >= CAM_CPAS_PATH_DATA_CONSO_OFFSET) + *path_data_type = CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT + + (*path_data_type % + CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT); + else + *path_data_type %= CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT; + + if (*path_data_type >= CAM_CPAS_PATH_DATA_MAX) { + CAM_ERR(CAM_CPAS, "index Invalid: %d", path_data_type); + return -EINVAL; + } + } + + return 0; +} + +static int cam_cpas_axi_consolidate_path_votes( + struct cam_cpas_client *cpas_client, + struct cam_axi_vote *axi_vote) +{ + int rc = 0, i, k, l; + struct cam_axi_vote *con_axi_vote = &cpas_client->axi_vote; + bool path_found = false, cons_entry_found; + struct cam_cpas_tree_node *curr_tree_node = NULL; + struct cam_cpas_tree_node *sum_tree_node = NULL; + uint32_t transac_type; + uint32_t path_data_type; + struct cam_axi_per_path_bw_vote *axi_path; + + con_axi_vote->num_paths = 0; + + for (i = 0; i < axi_vote->num_paths; i++) { + path_found = false; + path_data_type = axi_vote->axi_path[i].path_data_type; + transac_type = axi_vote->axi_path[i].transac_type; + + if ((path_data_type >= CAM_CPAS_PATH_DATA_MAX) || + (transac_type >= CAM_CPAS_TRANSACTION_MAX)) { + CAM_ERR(CAM_CPAS, "Invalid path or transac type: %d %d", + path_data_type, transac_type); + return -EINVAL; + } + + axi_path = &con_axi_vote->axi_path[con_axi_vote->num_paths]; + + curr_tree_node = + cpas_client->tree_node[path_data_type][transac_type]; + if (curr_tree_node) { + path_found = true; + memcpy(axi_path, &axi_vote->axi_path[i], + sizeof(struct cam_axi_per_path_bw_vote)); + con_axi_vote->num_paths++; + continue; + } + + for (k = 0; k < CAM_CPAS_PATH_DATA_MAX; k++) { + sum_tree_node = cpas_client->tree_node[k][transac_type]; + + if (!sum_tree_node) + continue; + + if (sum_tree_node->constituent_paths[path_data_type]) { + path_found = true; + /* + * Check if corresponding consolidated path + * entry is already added into consolidated list + */ + cons_entry_found = false; + for (l = 0; l < con_axi_vote->num_paths; l++) { + if ((con_axi_vote->axi_path[l] + .path_data_type == k) && + (con_axi_vote->axi_path[l] + .transac_type == transac_type)) { + cons_entry_found = true; + con_axi_vote->axi_path[l] + .camnoc_bw += + axi_vote->axi_path[i] + .camnoc_bw; + + con_axi_vote->axi_path[l] + .mnoc_ab_bw += + axi_vote->axi_path[i] + .mnoc_ab_bw; + + con_axi_vote->axi_path[l] + .mnoc_ib_bw += + axi_vote->axi_path[i] + .mnoc_ib_bw; + break; + } + } + + /* If not found, add a new entry */ + if (!cons_entry_found) { + axi_path->path_data_type = k; + axi_path->transac_type = transac_type; + axi_path->camnoc_bw = + axi_vote->axi_path[i].camnoc_bw; + axi_path->mnoc_ab_bw = + axi_vote->axi_path[i].mnoc_ab_bw; + axi_path->mnoc_ib_bw = + axi_vote->axi_path[i].mnoc_ib_bw; + con_axi_vote->num_paths++; + } + break; + } + } + + if (!path_found) { + CAM_ERR(CAM_CPAS, + "Client [%s][%d] Consolidated path not found for path=%d, transac=%d", + cpas_client->data.identifier, + cpas_client->data.cell_index, + path_data_type, transac_type); + return -EINVAL; + } + } + + return rc; +} + +static int cam_cpas_util_apply_client_axi_vote( + struct cam_hw_info *cpas_hw, + struct cam_cpas_client *cpas_client, + struct cam_axi_vote *axi_vote) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_axi_vote *con_axi_vote = NULL; + struct cam_cpas_axi_port *axi_port = NULL; + struct cam_cpas_tree_node *curr_tree_node = NULL; + struct cam_cpas_tree_node *par_tree_node = NULL; + uint32_t transac_type; + uint32_t path_data_type; + bool axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; + uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0, + curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, + par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; + int rc = 0, i = 0; + + mutex_lock(&cpas_core->tree_lock); + if (!cpas_client->tree_node_valid) { + /* + * This is by assuming apply_client_axi_vote is called + * for these clients from only cpas_start, cpas_stop. + * not called from hw_update_axi_vote + */ + for (i = 0; i < cpas_core->num_axi_ports; i++) { + if (axi_vote->axi_path[0].mnoc_ab_bw) { + /* start case */ + cpas_core->axi_port[i].additional_bw += + CAM_CPAS_DEFAULT_AXI_BW; + } else { + /* stop case */ + cpas_core->axi_port[i].additional_bw -= + CAM_CPAS_DEFAULT_AXI_BW; + } + axi_port_updated[i] = true; + } + goto vote_start_clients; + } + + rc = cam_cpas_axi_consolidate_path_votes(cpas_client, axi_vote); + if (rc) { + CAM_ERR(CAM_PERF, "Failed in bw consolidation, Client [%s][%d]", + cpas_client->data.identifier, + cpas_client->data.cell_index); + goto unlock_tree; + } + + con_axi_vote = &cpas_client->axi_vote; + + cam_cpas_dump_axi_vote_info(cpas_client, "Consolidated Vote", + con_axi_vote); + + /* Traverse through node tree and update bw vote values */ + for (i = 0; i < con_axi_vote->num_paths; i++) { + path_data_type = + con_axi_vote->axi_path[i].path_data_type; + transac_type = + con_axi_vote->axi_path[i].transac_type; + curr_tree_node = cpas_client->tree_node[path_data_type] + [transac_type]; + + if (con_axi_vote->axi_path[i].mnoc_ab_bw == 0) + con_axi_vote->axi_path[i].mnoc_ab_bw = + con_axi_vote->axi_path[i].camnoc_bw; + + if (con_axi_vote->axi_path[i].camnoc_bw == 0) + con_axi_vote->axi_path[i].camnoc_bw = + con_axi_vote->axi_path[i].mnoc_ab_bw; + + if ((curr_tree_node->camnoc_bw == + con_axi_vote->axi_path[i].camnoc_bw) && + (curr_tree_node->mnoc_ab_bw == + con_axi_vote->axi_path[i].mnoc_ab_bw) && + (curr_tree_node->mnoc_ib_bw == + con_axi_vote->axi_path[i].mnoc_ib_bw)) + continue; + + curr_camnoc_old = curr_tree_node->camnoc_bw; + curr_mnoc_ab_old = curr_tree_node->mnoc_ab_bw; + curr_mnoc_ib_old = curr_tree_node->mnoc_ib_bw; + curr_tree_node->camnoc_bw = + con_axi_vote->axi_path[i].camnoc_bw; + curr_tree_node->mnoc_ab_bw = + con_axi_vote->axi_path[i].mnoc_ab_bw; + curr_tree_node->mnoc_ib_bw = + con_axi_vote->axi_path[i].mnoc_ib_bw; + + while (curr_tree_node->parent_node) { + par_tree_node = curr_tree_node->parent_node; + par_camnoc_old = par_tree_node->camnoc_bw; + par_mnoc_ab_old = par_tree_node->mnoc_ab_bw; + par_mnoc_ib_old = par_tree_node->mnoc_ib_bw; + par_tree_node->mnoc_ab_bw -= curr_mnoc_ab_old; + par_tree_node->mnoc_ab_bw += curr_tree_node->mnoc_ab_bw; + par_tree_node->mnoc_ib_bw -= curr_mnoc_ib_old; + par_tree_node->mnoc_ib_bw += curr_tree_node->mnoc_ib_bw; + + if (par_tree_node->merge_type == + CAM_CPAS_TRAFFIC_MERGE_SUM) { + par_tree_node->camnoc_bw -= + curr_camnoc_old; + par_tree_node->camnoc_bw += + curr_tree_node->camnoc_bw; + } else if (par_tree_node->merge_type == + CAM_CPAS_TRAFFIC_MERGE_SUM_INTERLEAVE) { + par_tree_node->camnoc_bw -= + (curr_camnoc_old / 2); + par_tree_node->camnoc_bw += + (curr_tree_node->camnoc_bw / 2); + } else { + CAM_ERR(CAM_CPAS, "Invalid Merge type"); + rc = -EINVAL; + goto unlock_tree; + } + + if (!par_tree_node->parent_node) { + if ((par_tree_node->axi_port_idx < 0) || + (par_tree_node->axi_port_idx >= + CAM_CPAS_MAX_AXI_PORTS)) { + CAM_ERR(CAM_CPAS, + "AXI port index invalid"); + rc = -EINVAL; + goto unlock_tree; + } + + cpas_core->axi_port + [par_tree_node->axi_port_idx].ab_bw = + par_tree_node->mnoc_ab_bw; + cpas_core->axi_port + [par_tree_node->axi_port_idx].ib_bw = + par_tree_node->mnoc_ib_bw; + axi_port_updated[par_tree_node->axi_port_idx] = + true; + } + + curr_tree_node = par_tree_node; + curr_camnoc_old = par_camnoc_old; + curr_mnoc_ab_old = par_mnoc_ab_old; + curr_mnoc_ib_old = par_mnoc_ib_old; + } + } + + if (!par_tree_node) { + CAM_DBG(CAM_CPAS, "No change in BW for all paths"); + rc = 0; + goto unlock_tree; + } + +vote_start_clients: + for (i = 0; i < cpas_core->num_axi_ports; i++) { + if (axi_port_updated[i]) + axi_port = &cpas_core->axi_port[i]; + else + continue; + + CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld", + axi_port->axi_port_name, axi_port->ab_bw, + axi_port->ib_bw, axi_port->additional_bw); + + if (axi_port->ab_bw) + mnoc_ab_bw = axi_port->ab_bw; + else + mnoc_ab_bw = axi_port->additional_bw; + + if (cpas_core->axi_port[i].ib_bw_voting_needed) + mnoc_ib_bw = axi_port->ib_bw; + else + mnoc_ib_bw = 0; + + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, + mnoc_ab_bw, mnoc_ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", + mnoc_ab_bw, mnoc_ib_bw, rc); + goto unlock_tree; + } + } + + rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); + +unlock_tree: + mutex_unlock(&cpas_core->tree_lock); + return rc; +} + +static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, + uint32_t client_handle, struct cam_axi_vote *client_axi_vote) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + struct cam_axi_vote axi_vote = {0}; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!client_axi_vote) { + CAM_ERR(CAM_CPAS, "Invalid arg, client_handle=%d", + client_handle); + return -EINVAL; + } + + memcpy(&axi_vote, client_axi_vote, sizeof(struct cam_axi_vote)); + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx], + "Incoming Vote", &axi_vote); + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto unlock_client; + } + + rc = cam_cpas_util_translate_client_paths(&axi_vote); + if (rc) { + CAM_ERR(CAM_CPAS, + "Unable to translate per path votes rc: %d", rc); + goto unlock_client; + } + + cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx], + "Translated Vote", &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_core->cpas_client[client_indx], &axi_vote); + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_util_get_ahb_level(struct cam_hw_info *cpas_hw, + struct device *dev, unsigned long freq, enum cam_vote_level *req_level) +{ + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct dev_pm_opp *opp; + unsigned int corner; + enum cam_vote_level level = CAM_SVS_VOTE; + unsigned long corner_freq = freq; + int i; + + if (!dev || !req_level) { + CAM_ERR(CAM_CPAS, "Invalid params %pK, %pK", dev, req_level); + return -EINVAL; + } + + opp = dev_pm_opp_find_freq_ceil(dev, &corner_freq); + if (IS_ERR(opp)) { + CAM_DBG(CAM_CPAS, "OPP Ceil not available for freq :%ld, %pK", + corner_freq, opp); + *req_level = CAM_TURBO_VOTE; + return 0; + } + + corner = dev_pm_opp_get_voltage(opp); + + for (i = 0; i < soc_private->num_vdd_ahb_mapping; i++) + if (corner == soc_private->vdd_ahb[i].vdd_corner) + level = soc_private->vdd_ahb[i].ahb_level; + + CAM_DBG(CAM_CPAS, + "From OPP table : freq=[%ld][%ld], corner=%d, level=%d", + freq, corner_freq, corner, level); + + *req_level = level; + + return 0; +} + +static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw, + struct cam_cpas_client *cpas_client, struct cam_ahb_vote *ahb_vote, + enum cam_vote_level *applied_level) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_bus_client *ahb_bus_client = &cpas_core->ahb_bus_client; + enum cam_vote_level required_level; + enum cam_vote_level highest_level; + int i, rc = 0; + + if (!ahb_bus_client->valid) { + CAM_ERR(CAM_CPAS, "AHB Bus client not valid"); + return -EINVAL; + } + + if (ahb_vote->type == CAM_VOTE_DYNAMIC) { + rc = cam_cpas_util_get_ahb_level(cpas_hw, cpas_client->data.dev, + ahb_vote->vote.freq, &required_level); + if (rc) + return rc; + } else { + required_level = ahb_vote->vote.level; + } + + if (cpas_client->ahb_level == required_level) + return 0; + + mutex_lock(&ahb_bus_client->lock); + cpas_client->ahb_level = required_level; + + CAM_DBG(CAM_CPAS, "Client=[%d][%s] required level[%d], curr_level[%d]", + ahb_bus_client->client_id, ahb_bus_client->name, + required_level, ahb_bus_client->curr_vote_level); + + if (required_level == ahb_bus_client->curr_vote_level) + goto unlock_bus_client; + + highest_level = required_level; + for (i = 0; i < cpas_core->num_clients; i++) { + if (cpas_core->cpas_client[i] && (highest_level < + cpas_core->cpas_client[i]->ahb_level)) + highest_level = cpas_core->cpas_client[i]->ahb_level; + } + + CAM_DBG(CAM_CPAS, "Required highest_level[%d]", highest_level); + + rc = cam_cpas_util_vote_bus_client_level(ahb_bus_client, + highest_level); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in ahb vote, level=%d, rc=%d", + highest_level, rc); + goto unlock_bus_client; + } + + rc = cam_soc_util_set_clk_rate_level(&cpas_hw->soc_info, highest_level); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in scaling clock rate level %d for AHB", + highest_level); + goto unlock_bus_client; + } + + if (applied_level) + *applied_level = highest_level; + +unlock_bus_client: + mutex_unlock(&ahb_bus_client->lock); + return rc; +} + +static int cam_cpas_hw_update_ahb_vote(struct cam_hw_info *cpas_hw, + uint32_t client_handle, struct cam_ahb_vote *client_ahb_vote) +{ + struct cam_ahb_vote ahb_vote; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!client_ahb_vote) { + CAM_ERR(CAM_CPAS, "Invalid input arg"); + return -EINVAL; + } + + ahb_vote = *client_ahb_vote; + + if (ahb_vote.vote.level == 0) { + CAM_DBG(CAM_CPAS, "0 ahb vote from client %d", + client_handle); + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto unlock_client; + } + + CAM_DBG(CAM_PERF, + "client=[%d][%s][%d] : type[%d], level[%d], freq[%ld], applied[%d]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, ahb_vote.type, + ahb_vote.vote.level, ahb_vote.vote.freq, + cpas_core->cpas_client[client_indx]->ahb_level); + + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, + cpas_core->cpas_client[client_indx], &ahb_vote, NULL); + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_util_create_vote_all_paths( + struct cam_cpas_client *cpas_client, + struct cam_axi_vote *axi_vote) +{ + int i, j; + uint64_t camnoc_bw, mnoc_ab_bw, mnoc_ib_bw; + struct cam_axi_per_path_bw_vote *axi_path; + + if (!cpas_client || !axi_vote) + return -EINVAL; + + camnoc_bw = axi_vote->axi_path[0].camnoc_bw; + mnoc_ab_bw = axi_vote->axi_path[0].mnoc_ab_bw; + mnoc_ib_bw = axi_vote->axi_path[0].mnoc_ib_bw; + + axi_vote->num_paths = 0; + + for (i = 0; i < CAM_CPAS_TRANSACTION_MAX; i++) { + for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) { + if (cpas_client->tree_node[j][i]) { + axi_path = + &axi_vote->axi_path[axi_vote->num_paths]; + + axi_path->path_data_type = j; + axi_path->transac_type = i; + axi_path->camnoc_bw = camnoc_bw; + axi_path->mnoc_ab_bw = mnoc_ab_bw; + axi_path->mnoc_ib_bw = mnoc_ib_bw; + + axi_vote->num_paths++; + } + } + } + + return 0; +} + +static int cam_cpas_hw_start(void *hw_priv, void *start_args, + uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + uint32_t client_indx; + struct cam_cpas_hw_cmd_start *cmd_hw_start; + struct cam_cpas_client *cpas_client; + struct cam_ahb_vote *ahb_vote; + struct cam_axi_vote axi_vote = {0}; + enum cam_vote_level applied_level = CAM_SVS_VOTE; + int rc, i = 0; + struct cam_cpas_private_soc *soc_private = NULL; + bool invalid_start = true; + + if (!hw_priv || !start_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, start_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_cmd_start) != arg_size) { + CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d", + sizeof(struct cam_cpas_hw_cmd_start), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + soc_private = (struct cam_cpas_private_soc *) + cpas_hw->soc_info.soc_private; + cmd_hw_start = (struct cam_cpas_hw_cmd_start *)start_args; + client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_start->client_handle); + ahb_vote = cmd_hw_start->ahb_vote; + + if (!ahb_vote || !cmd_hw_start->axi_vote) + return -EINVAL; + + if (!ahb_vote->vote.level) { + CAM_ERR(CAM_CPAS, "Invalid vote ahb[%d]", + ahb_vote->vote.level); + return -EINVAL; + } + + memcpy(&axi_vote, cmd_hw_start->axi_vote, sizeof(struct cam_axi_vote)); + for (i = 0; i < axi_vote.num_paths; i++) { + if ((axi_vote.axi_path[i].camnoc_bw != 0) || + (axi_vote.axi_path[i].mnoc_ab_bw != 0) || + (axi_vote.axi_path[i].mnoc_ib_bw != 0)) { + invalid_start = false; + break; + } + } + + if (invalid_start) { + CAM_ERR(CAM_CPAS, "Zero start vote"); + return -EINVAL; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d] is not registered", + client_indx); + rc = -EPERM; + goto done; + } + + if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] is in start state", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto done; + } + + CAM_DBG(CAM_CPAS, + "AHB :client=[%d][%s][%d] type[%d], level[%d], applied[%d]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, + ahb_vote->type, ahb_vote->vote.level, cpas_client->ahb_level); + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + ahb_vote, &applied_level); + if (rc) + goto done; + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Vote", + &axi_vote); + + /* + * If client has indicated start bw to be applied on all paths + * of client, apply that otherwise apply whatever the client supplies + * for specific paths + */ + if (axi_vote.axi_path[0].path_data_type == + CAM_CPAS_API_PATH_DATA_STD_START) { + rc = cam_cpas_util_create_vote_all_paths(cpas_client, + &axi_vote); + } else { + rc = cam_cpas_util_translate_client_paths(&axi_vote); + } + + if (rc) { + CAM_ERR(CAM_CPAS, "Unable to create or translate paths rc: %d", + rc); + goto done; + } + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote", + &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, &axi_vote); + if (rc) + goto done; + + if (cpas_core->streamon_clients == 0) { + atomic_set(&cpas_core->irq_count, 1); + rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, + applied_level); + if (rc) { + atomic_set(&cpas_core->irq_count, 0); + CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc); + goto done; + } + + if (cpas_core->internal_ops.power_on) { + rc = cpas_core->internal_ops.power_on(cpas_hw); + if (rc) { + atomic_set(&cpas_core->irq_count, 0); + cam_cpas_soc_disable_resources( + &cpas_hw->soc_info, true, true); + CAM_ERR(CAM_CPAS, + "failed in power_on settings rc=%d", + rc); + goto done; + } + } + CAM_DBG(CAM_CPAS, "irq_count=%d\n", + atomic_read(&cpas_core->irq_count)); + cpas_hw->hw_state = CAM_HW_STATE_POWER_UP; + } + + cpas_client->started = true; + cpas_core->streamon_clients++; + + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d] streamon_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->streamon_clients); +done: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int _check_irq_count(struct cam_cpas *cpas_core) +{ + return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1; +} + +static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, + uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + uint32_t client_indx; + struct cam_cpas_hw_cmd_stop *cmd_hw_stop; + struct cam_cpas_client *cpas_client; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + struct cam_cpas_private_soc *soc_private = NULL; + int rc = 0; + long result; + + if (!hw_priv || !stop_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, stop_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_cmd_stop) != arg_size) { + CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d", + sizeof(struct cam_cpas_hw_cmd_stop), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + soc_private = (struct cam_cpas_private_soc *) + cpas_hw->soc_info.soc_private; + cmd_hw_stop = (struct cam_cpas_hw_cmd_stop *)stop_args; + client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_stop->client_handle); + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + CAM_DBG(CAM_CPAS, "Client=[%d][%s][%d] streamon_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->streamon_clients); + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto done; + } + + cpas_client->started = false; + cpas_core->streamon_clients--; + + if (cpas_core->streamon_clients == 0) { + if (cpas_core->internal_ops.power_off) { + rc = cpas_core->internal_ops.power_off(cpas_hw); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed in power_off settings rc=%d", + rc); + /* Do not return error, passthrough */ + } + } + + rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info); + if (rc) { + CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc); + goto done; + } + + /* Wait for any IRQs still being handled */ + atomic_dec(&cpas_core->irq_count); + result = wait_event_timeout(cpas_core->irq_count_wq, + _check_irq_count(cpas_core), HZ); + if (result == 0) { + CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d", + atomic_read(&cpas_core->irq_count)); + } + + rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, + true, false); + if (rc) { + CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc); + goto done; + } + CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n", + atomic_read(&cpas_core->irq_count)); + cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SUSPEND_VOTE; + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + &ahb_vote, NULL); + if (rc) + goto done; + + rc = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); + if (rc) { + CAM_ERR(CAM_CPAS, "Unable to create per path votes rc: %d", rc); + goto done; + } + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Stop Vote", &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, &axi_vote); +done: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_hw_init(void *hw_priv, void *init_hw_args, + uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + int rc = 0; + + if (!hw_priv || !init_hw_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, init_hw_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_caps) != arg_size) { + CAM_ERR(CAM_CPAS, "INIT HW size mismatch %zd %d", + sizeof(struct cam_cpas_hw_caps), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *)cpas_hw->core_info; + + if (cpas_core->internal_ops.init_hw_version) { + rc = cpas_core->internal_ops.init_hw_version(cpas_hw, + (struct cam_cpas_hw_caps *)init_hw_args); + } + + return rc; +} + +static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, + struct cam_cpas_register_params *register_params) +{ + int rc; + char client_name[CAM_HW_IDENTIFIER_LENGTH + 3]; + int32_t client_indx = -1; + struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + CAM_DBG(CAM_CPAS, "Register params : identifier=%s, cell_index=%d", + register_params->identifier, register_params->cell_index); + + if (soc_private->client_id_based) + snprintf(client_name, sizeof(client_name), "%s%d", + register_params->identifier, + register_params->cell_index); + else + snprintf(client_name, sizeof(client_name), "%s", + register_params->identifier); + + mutex_lock(&cpas_hw->hw_mutex); + + rc = cam_common_util_get_string_index(soc_private->client_name, + soc_private->num_clients, client_name, &client_indx); + + mutex_lock(&cpas_core->client_mutex[client_indx]); + + if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) || + CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, + "Inval client %s %d : %d %d %pK %d", + register_params->identifier, + register_params->cell_index, + CAM_CPAS_CLIENT_VALID(client_indx), + CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx), + cpas_core->cpas_client[client_indx], rc); + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return -EPERM; + } + + register_params->client_handle = + CAM_CPAS_GET_CLIENT_HANDLE(client_indx); + memcpy(&cpas_core->cpas_client[client_indx]->data, register_params, + sizeof(struct cam_cpas_register_params)); + cpas_core->registered_clients++; + cpas_core->cpas_client[client_indx]->registered = true; + + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index, + cpas_core->registered_clients); + + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + + return 0; +} + +static int cam_cpas_hw_unregister_client(struct cam_hw_info *cpas_hw, + uint32_t client_handle) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + + if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] not registered", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index); + rc = -EPERM; + goto done; + } + + if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not stopped", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index); + + rc = -EPERM; + goto done; + } + + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index, + cpas_core->registered_clients); + + cpas_core->cpas_client[client_indx]->registered = false; + cpas_core->registered_clients--; +done: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_hw_get_hw_info(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + struct cam_cpas_hw_caps *hw_caps; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, get_hw_cap_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_caps) != arg_size) { + CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d", + sizeof(struct cam_cpas_hw_caps), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + hw_caps = (struct cam_cpas_hw_caps *)get_hw_cap_args; + + *hw_caps = cpas_core->hw_caps; + + return 0; +} + + +static int cam_cpas_hw_process_cmd(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!hw_priv || !cmd_args || + (cmd_type >= CAM_CPAS_HW_CMD_INVALID)) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK %d", + hw_priv, cmd_args, cmd_type); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_CPAS_HW_CMD_REGISTER_CLIENT: { + struct cam_cpas_register_params *register_params; + + if (sizeof(struct cam_cpas_register_params) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + register_params = (struct cam_cpas_register_params *)cmd_args; + rc = cam_cpas_hw_register_client(hw_priv, register_params); + break; + } + case CAM_CPAS_HW_CMD_UNREGISTER_CLIENT: { + uint32_t *client_handle; + + if (sizeof(uint32_t) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + client_handle = (uint32_t *)cmd_args; + rc = cam_cpas_hw_unregister_client(hw_priv, *client_handle); + break; + } + case CAM_CPAS_HW_CMD_REG_WRITE: { + struct cam_cpas_hw_cmd_reg_read_write *reg_write; + + if (sizeof(struct cam_cpas_hw_cmd_reg_read_write) != + arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + reg_write = + (struct cam_cpas_hw_cmd_reg_read_write *)cmd_args; + rc = cam_cpas_hw_reg_write(hw_priv, reg_write->client_handle, + reg_write->reg_base, reg_write->offset, reg_write->mb, + reg_write->value); + break; + } + case CAM_CPAS_HW_CMD_REG_READ: { + struct cam_cpas_hw_cmd_reg_read_write *reg_read; + + if (sizeof(struct cam_cpas_hw_cmd_reg_read_write) != + arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + reg_read = + (struct cam_cpas_hw_cmd_reg_read_write *)cmd_args; + rc = cam_cpas_hw_reg_read(hw_priv, + reg_read->client_handle, reg_read->reg_base, + reg_read->offset, reg_read->mb, ®_read->value); + + break; + } + case CAM_CPAS_HW_CMD_AHB_VOTE: { + struct cam_cpas_hw_cmd_ahb_vote *cmd_ahb_vote; + + if (sizeof(struct cam_cpas_hw_cmd_ahb_vote) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + cmd_ahb_vote = (struct cam_cpas_hw_cmd_ahb_vote *)cmd_args; + rc = cam_cpas_hw_update_ahb_vote(hw_priv, + cmd_ahb_vote->client_handle, cmd_ahb_vote->ahb_vote); + break; + } + case CAM_CPAS_HW_CMD_AXI_VOTE: { + struct cam_cpas_hw_cmd_axi_vote *cmd_axi_vote; + + if (sizeof(struct cam_cpas_hw_cmd_axi_vote) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + cmd_axi_vote = (struct cam_cpas_hw_cmd_axi_vote *)cmd_args; + rc = cam_cpas_hw_update_axi_vote(hw_priv, + cmd_axi_vote->client_handle, cmd_axi_vote->axi_vote); + break; + } + default: + CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type); + break; + } + + return rc; +} + +static int cam_cpas_util_client_setup(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + int i; + + for (i = 0; i < CAM_CPAS_MAX_CLIENTS; i++) { + mutex_init(&cpas_core->client_mutex[i]); + } + + return 0; +} + +int cam_cpas_util_client_cleanup(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + int i; + + for (i = 0; i < CAM_CPAS_MAX_CLIENTS; i++) { + if (cpas_core->cpas_client[i] && + cpas_core->cpas_client[i]->registered) { + cam_cpas_hw_unregister_client(cpas_hw, i); + } + kfree(cpas_core->cpas_client[i]); + cpas_core->cpas_client[i] = NULL; + mutex_destroy(&cpas_core->client_mutex[i]); + } + + return 0; +} + +static int cam_cpas_util_get_internal_ops(struct platform_device *pdev, + struct cam_hw_intf *hw_intf, struct cam_cpas_internal_ops *internal_ops) +{ + struct device_node *of_node = pdev->dev.of_node; + int rc; + const char *compat_str = NULL; + + rc = of_property_read_string_index(of_node, "arch-compat", 0, + (const char **)&compat_str); + if (rc) { + CAM_ERR(CAM_CPAS, "failed to get arch-compat rc=%d", rc); + return -EINVAL; + } + + if (strnstr(compat_str, "camss_top", strlen(compat_str))) { + hw_intf->hw_type = CAM_HW_CAMSSTOP; + rc = cam_camsstop_get_internal_ops(internal_ops); + } else if (strnstr(compat_str, "cpas_top", strlen(compat_str))) { + hw_intf->hw_type = CAM_HW_CPASTOP; + rc = cam_cpastop_get_internal_ops(internal_ops); + } else { + CAM_ERR(CAM_CPAS, "arch-compat %s not supported", compat_str); + rc = -EINVAL; + } + + return rc; +} + +int cam_cpas_hw_probe(struct platform_device *pdev, + struct cam_hw_intf **hw_intf) +{ + int rc = 0; + int i; + struct cam_hw_info *cpas_hw = NULL; + struct cam_hw_intf *cpas_hw_intf = NULL; + struct cam_cpas *cpas_core = NULL; + struct cam_cpas_private_soc *soc_private; + struct cam_cpas_internal_ops *internal_ops; + + cpas_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!cpas_hw_intf) + return -ENOMEM; + + cpas_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!cpas_hw) { + kfree(cpas_hw_intf); + return -ENOMEM; + } + + cpas_core = kzalloc(sizeof(struct cam_cpas), GFP_KERNEL); + if (!cpas_core) { + kfree(cpas_hw); + kfree(cpas_hw_intf); + return -ENOMEM; + } + + for (i = 0; i < CAM_CPAS_REG_MAX; i++) + cpas_core->regbase_index[i] = -1; + + cpas_hw_intf->hw_priv = cpas_hw; + cpas_hw->core_info = cpas_core; + + cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + cpas_hw->soc_info.pdev = pdev; + cpas_hw->soc_info.dev = &pdev->dev; + cpas_hw->soc_info.dev_name = pdev->name; + cpas_hw->open_count = 0; + mutex_init(&cpas_hw->hw_mutex); + spin_lock_init(&cpas_hw->hw_lock); + init_completion(&cpas_hw->hw_complete); + + cpas_hw_intf->hw_ops.get_hw_caps = cam_cpas_hw_get_hw_info; + cpas_hw_intf->hw_ops.init = cam_cpas_hw_init; + cpas_hw_intf->hw_ops.deinit = NULL; + cpas_hw_intf->hw_ops.reset = NULL; + cpas_hw_intf->hw_ops.reserve = NULL; + cpas_hw_intf->hw_ops.release = NULL; + cpas_hw_intf->hw_ops.start = cam_cpas_hw_start; + cpas_hw_intf->hw_ops.stop = cam_cpas_hw_stop; + cpas_hw_intf->hw_ops.read = NULL; + cpas_hw_intf->hw_ops.write = NULL; + cpas_hw_intf->hw_ops.process_cmd = cam_cpas_hw_process_cmd; + + cpas_core->work_queue = alloc_workqueue("cam-cpas", + WQ_UNBOUND | WQ_MEM_RECLAIM, CAM_CPAS_INFLIGHT_WORKS); + if (!cpas_core->work_queue) { + rc = -ENOMEM; + goto release_mem; + } + + internal_ops = &cpas_core->internal_ops; + rc = cam_cpas_util_get_internal_ops(pdev, cpas_hw_intf, internal_ops); + if (rc) + goto release_workq; + + rc = cam_cpas_soc_init_resources(&cpas_hw->soc_info, + internal_ops->handle_irq, cpas_hw); + if (rc) + goto release_workq; + + soc_private = (struct cam_cpas_private_soc *) + cpas_hw->soc_info.soc_private; + cpas_core->num_clients = soc_private->num_clients; + atomic_set(&cpas_core->irq_count, 0); + init_waitqueue_head(&cpas_core->irq_count_wq); + + if (internal_ops->setup_regbase) { + rc = internal_ops->setup_regbase(&cpas_hw->soc_info, + cpas_core->regbase_index, CAM_CPAS_REG_MAX); + if (rc) + goto deinit_platform_res; + } + + rc = cam_cpas_util_client_setup(cpas_hw); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in client setup, rc=%d", rc); + goto deinit_platform_res; + } + + rc = cam_cpas_util_register_bus_client(&cpas_hw->soc_info, + cpas_hw->soc_info.pdev->dev.of_node, + &cpas_core->ahb_bus_client); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in ahb setup, rc=%d", rc); + goto client_cleanup; + } + + rc = cam_cpas_util_axi_setup(cpas_core, &cpas_hw->soc_info); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in axi setup, rc=%d", rc); + goto ahb_cleanup; + } + + /* Need to vote first before enabling clocks */ + rc = cam_cpas_util_vote_default_ahb_axi(cpas_hw, true); + if (rc) + goto axi_cleanup; + + rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, CAM_SVS_VOTE); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in soc_enable_resources, rc=%d", rc); + goto remove_default_vote; + } + + if (internal_ops->get_hw_info) { + rc = internal_ops->get_hw_info(cpas_hw, &cpas_core->hw_caps); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in get_hw_info, rc=%d", rc); + goto disable_soc_res; + } + } else { + CAM_ERR(CAM_CPAS, "Invalid get_hw_info"); + goto disable_soc_res; + } + + rc = cam_cpas_hw_init(cpas_hw_intf->hw_priv, + &cpas_core->hw_caps, sizeof(struct cam_cpas_hw_caps)); + if (rc) + goto disable_soc_res; + + rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc); + goto remove_default_vote; + } + + rc = cam_cpas_util_vote_default_ahb_axi(cpas_hw, false); + if (rc) + goto axi_cleanup; + + *hw_intf = cpas_hw_intf; + return 0; + +disable_soc_res: + cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); +remove_default_vote: + cam_cpas_util_vote_default_ahb_axi(cpas_hw, false); +axi_cleanup: + cam_cpas_util_axi_cleanup(cpas_core, &cpas_hw->soc_info); +ahb_cleanup: + cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client); +client_cleanup: + cam_cpas_util_client_cleanup(cpas_hw); +deinit_platform_res: + cam_cpas_soc_deinit_resources(&cpas_hw->soc_info); +release_workq: + cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); + flush_workqueue(cpas_core->work_queue); + destroy_workqueue(cpas_core->work_queue); +release_mem: + mutex_destroy(&cpas_hw->hw_mutex); + kfree(cpas_core); + kfree(cpas_hw); + kfree(cpas_hw_intf); + CAM_ERR(CAM_CPAS, "failed in hw probe"); + return rc; +} + +int cam_cpas_hw_remove(struct cam_hw_intf *cpas_hw_intf) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + + if (!cpas_hw_intf) { + CAM_ERR(CAM_CPAS, "cpas interface not initialized"); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)cpas_hw_intf->hw_priv; + cpas_core = (struct cam_cpas *)cpas_hw->core_info; + + if (cpas_hw->hw_state == CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_CPAS, "cpas hw is in power up state"); + return -EINVAL; + } + + cam_cpas_util_axi_cleanup(cpas_core, &cpas_hw->soc_info); + cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); + cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client); + cam_cpas_util_client_cleanup(cpas_hw); + cam_cpas_soc_deinit_resources(&cpas_hw->soc_info); + flush_workqueue(cpas_core->work_queue); + destroy_workqueue(cpas_core->work_queue); + mutex_destroy(&cpas_hw->hw_mutex); + kfree(cpas_core); + kfree(cpas_hw); + kfree(cpas_hw_intf); + + return 0; +} diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h new file mode 100644 index 000000000000..7b1eda841488 --- /dev/null +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_HW_H_ +#define _CAM_CPAS_HW_H_ + +#include +#include "cam_cpas_api.h" +#include "cam_cpas_hw_intf.h" +#include "cam_common_util.h" + +#define CAM_CPAS_INFLIGHT_WORKS 5 +#define CAM_CPAS_MAX_CLIENTS 40 +#define CAM_CPAS_MAX_AXI_PORTS 6 +#define CAM_CPAS_MAX_TREE_LEVELS 4 +#define CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT 32 +#define CAM_CPAS_PATH_DATA_MAX 38 +#define CAM_CPAS_TRANSACTION_MAX 2 + +#define CAM_CPAS_AXI_MIN_MNOC_AB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_MNOC_IB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000UL) + +#define CAM_CPAS_GET_CLIENT_IDX(handle) (handle) +#define CAM_CPAS_GET_CLIENT_HANDLE(indx) (indx) + +#define CAM_CPAS_CLIENT_VALID(indx) \ + ((indx >= 0) && (indx < CAM_CPAS_MAX_CLIENTS)) +#define CAM_CPAS_CLIENT_REGISTERED(cpas_core, indx) \ + ((CAM_CPAS_CLIENT_VALID(indx)) && \ + (cpas_core->cpas_client[indx]->registered)) +#define CAM_CPAS_CLIENT_STARTED(cpas_core, indx) \ + ((CAM_CPAS_CLIENT_REGISTERED(cpas_core, indx)) && \ + (cpas_core->cpas_client[indx]->started)) + +/** + * enum cam_cpas_access_type - Enum for Register access type + */ +enum cam_cpas_access_type { + CAM_REG_TYPE_READ, + CAM_REG_TYPE_WRITE, + CAM_REG_TYPE_READ_WRITE, +}; + +/** + * struct cam_cpas_internal_ops - CPAS Hardware layer internal ops + * + * @get_hw_info: Function pointer for get hw info + * @init_hw_version: Function pointer for hw init based on version + * @handle_irq: Function poniter for irq handling + * @setup_regbase: Function pointer for setup rebase indices + * @power_on: Function pointer for hw core specific power on settings + * @power_off: Function pointer for hw core specific power off settings + * + */ +struct cam_cpas_internal_ops { + int (*get_hw_info)(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps); + int (*init_hw_version)(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps); + irqreturn_t (*handle_irq)(int irq_num, void *data); + int (*setup_regbase)(struct cam_hw_soc_info *soc_info, + int32_t regbase_index[], int32_t num_reg_map); + int (*power_on)(struct cam_hw_info *cpas_hw); + int (*power_off)(struct cam_hw_info *cpas_hw); +}; + +/** + * struct cam_cpas_reg : CPAS register info + * + * @enable: Whether this reg info need to be enabled + * @access_type: Register access type + * @masked_value: Whether this register write/read is based on mask, shift + * @mask: Mask for this register value + * @shift: Shift for this register value + * @value: Register value + * + */ +struct cam_cpas_reg { + bool enable; + enum cam_cpas_access_type access_type; + bool masked_value; + uint32_t offset; + uint32_t mask; + uint32_t shift; + uint32_t value; +}; + +/** + * struct cam_cpas_client : CPAS Client structure info + * + * @data: Client register params + * @registered: Whether client has registered with cpas + * @started: Whether client has streamed on + * @tree_node_valid: Indicates whether tree node has at least one valid node + * @ahb_level: Determined/Applied ahb level for the client + * @axi_vote: Determined/Applied axi vote for the client + * @axi_port: Client's parent axi port + * @tree_node: All granular path voting nodes for the client + * + */ +struct cam_cpas_client { + struct cam_cpas_register_params data; + bool registered; + bool started; + bool tree_node_valid; + enum cam_vote_level ahb_level; + struct cam_axi_vote axi_vote; + struct cam_cpas_axi_port *axi_port; + struct cam_cpas_tree_node *tree_node[CAM_CPAS_PATH_DATA_MAX] + [CAM_CPAS_TRANSACTION_MAX]; +}; + +/** + * struct cam_cpas_bus_client : Bus client information + * + * @src: Bus master/src id + * @dst: Bus slave/dst id + * @pdata: Bus pdata information + * @client_id: Bus client id + * @num_usecases: Number of use cases for this client + * @num_paths: Number of paths for this client + * @curr_vote_level: current voted index + * @dyn_vote: Whether dynamic voting enabled + * @lock: Mutex lock used while voting on this client + * @valid: Whether bus client is valid + * @name: Name of the bus client + * + */ +struct cam_cpas_bus_client { + int src; + int dst; + struct msm_bus_scale_pdata *pdata; + uint32_t client_id; + int num_usecases; + int num_paths; + unsigned int curr_vote_level; + bool dyn_vote; + struct mutex lock; + bool valid; + const char *name; +}; + +/** + * struct cam_cpas_axi_port : AXI port information + * + * @axi_port_name: Name of this AXI port + * @bus_client: bus client info for this port + * @ib_bw_voting_needed: if this port can update ib bw dynamically + * @axi_port_node: Node representing AXI Port info in device tree + * @ab_bw: AB bw value for this port + * @ib_bw: IB bw value for this port + * @additional_bw: Additional bandwidth to cover non-hw cpas clients + */ +struct cam_cpas_axi_port { + const char *axi_port_name; + struct cam_cpas_bus_client bus_client; + bool ib_bw_voting_needed; + struct device_node *axi_port_node; + uint64_t ab_bw; + uint64_t ib_bw; + uint64_t additional_bw; +}; + +/** + * struct cam_cpas : CPAS core data structure info + * + * @hw_caps: CPAS hw capabilities + * @cpas_client: Array of pointers to CPAS clients info + * @client_mutex: Mutex for accessing client info + * @tree_lock: Mutex lock for accessing CPAS node tree + * @num_clients: Total number of clients that CPAS supports + * @num_axi_ports: Total number of axi ports found in device tree + * @registered_clients: Number of Clients registered currently + * @streamon_clients: Number of Clients that are in start state currently + * @regbase_index: Register base indices for CPAS register base IDs + * @ahb_bus_client: AHB Bus client info + * @axi_port: AXI port info for a specific axi index + * @internal_ops: CPAS HW internal ops + * @work_queue: Work queue handle + * + */ +struct cam_cpas { + struct cam_cpas_hw_caps hw_caps; + struct cam_cpas_client *cpas_client[CAM_CPAS_MAX_CLIENTS]; + struct mutex client_mutex[CAM_CPAS_MAX_CLIENTS]; + struct mutex tree_lock; + uint32_t num_clients; + uint32_t num_axi_ports; + uint32_t registered_clients; + uint32_t streamon_clients; + int32_t regbase_index[CAM_CPAS_REG_MAX]; + struct cam_cpas_bus_client ahb_bus_client; + struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS]; + struct cam_cpas_internal_ops internal_ops; + struct workqueue_struct *work_queue; + atomic_t irq_count; + wait_queue_head_t irq_count_wq; +}; + +int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); +int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); + +int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, + enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info); + +int cam_cpas_util_client_cleanup(struct cam_hw_info *cpas_hw); + +#endif /* _CAM_CPAS_HW_H_ */ diff --git a/drivers/cam_cpas/cam_cpas_hw_intf.h b/drivers/cam_cpas/cam_cpas_hw_intf.h new file mode 100644 index 000000000000..0926e6e3d8d1 --- /dev/null +++ b/drivers/cam_cpas/cam_cpas_hw_intf.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_HW_INTF_H_ +#define _CAM_CPAS_HW_INTF_H_ + +#include + +#include "cam_cpas_api.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_debug_util.h" + +/* Number of times to retry while polling */ +#define CAM_CPAS_POLL_RETRY_CNT 5 +/* Minimum usecs to sleep while polling */ +#define CAM_CPAS_POLL_MIN_USECS 200 +/* Maximum usecs to sleep while polling */ +#define CAM_CPAS_POLL_MAX_USECS 250 + +/** + * enum cam_cpas_hw_type - Enum for CPAS HW type + */ +enum cam_cpas_hw_type { + CAM_HW_CPASTOP, + CAM_HW_CAMSSTOP, +}; + +/** + * enum cam_cpas_hw_cmd_process - Enum for CPAS HW process command type + */ +enum cam_cpas_hw_cmd_process { + CAM_CPAS_HW_CMD_REGISTER_CLIENT, + CAM_CPAS_HW_CMD_UNREGISTER_CLIENT, + CAM_CPAS_HW_CMD_REG_WRITE, + CAM_CPAS_HW_CMD_REG_READ, + CAM_CPAS_HW_CMD_AHB_VOTE, + CAM_CPAS_HW_CMD_AXI_VOTE, + CAM_CPAS_HW_CMD_INVALID, +}; + +/** + * struct cam_cpas_hw_cmd_reg_read_write : CPAS cmd struct for reg read, write + * + * @client_handle: Client handle + * @reg_base: Register base type + * @offset: Register offset + * @value: Register value + * @mb: Whether to do operation with memory barrier + * + */ +struct cam_cpas_hw_cmd_reg_read_write { + uint32_t client_handle; + enum cam_cpas_reg_base reg_base; + uint32_t offset; + uint32_t value; + bool mb; +}; + +/** + * struct cam_cpas_hw_cmd_ahb_vote : CPAS cmd struct for AHB vote + * + * @client_handle: Client handle + * @ahb_vote: AHB voting info + * + */ +struct cam_cpas_hw_cmd_ahb_vote { + uint32_t client_handle; + struct cam_ahb_vote *ahb_vote; +}; + +/** + * struct cam_cpas_hw_cmd_axi_vote : CPAS cmd struct for AXI vote + * + * @client_handle: Client handle + * @axi_vote: axi bandwidth vote + * + */ +struct cam_cpas_hw_cmd_axi_vote { + uint32_t client_handle; + struct cam_axi_vote *axi_vote; +}; + +/** + * struct cam_cpas_hw_cmd_start : CPAS cmd struct for start + * + * @client_handle: Client handle + * + */ +struct cam_cpas_hw_cmd_start { + uint32_t client_handle; + struct cam_ahb_vote *ahb_vote; + struct cam_axi_vote *axi_vote; +}; + +/** + * struct cam_cpas_hw_cmd_stop : CPAS cmd struct for stop + * + * @client_handle: Client handle + * + */ +struct cam_cpas_hw_cmd_stop { + uint32_t client_handle; +}; + +/** + * struct cam_cpas_hw_caps : CPAS HW capabilities + * + * @camera_family: Camera family type + * @camera_version: Camera version + * @cpas_version: CPAS version + * @camera_capability: Camera hw capabilities + * + */ +struct cam_cpas_hw_caps { + uint32_t camera_family; + struct cam_hw_version camera_version; + struct cam_hw_version cpas_version; + uint32_t camera_capability; +}; + +int cam_cpas_hw_probe(struct platform_device *pdev, + struct cam_hw_intf **hw_intf); +int cam_cpas_hw_remove(struct cam_hw_intf *cpas_hw_intf); + +#endif /* _CAM_CPAS_HW_INTF_H_ */ diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c new file mode 100644 index 000000000000..e43d9f01ec2c --- /dev/null +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -0,0 +1,725 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_subdev.h" +#include "cam_cpas_hw_intf.h" + +#define CAM_CPAS_DEV_NAME "cam-cpas" +#define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done) + +/** + * struct cam_cpas_intf : CPAS interface + * + * @pdev: Platform device + * @subdev: Subdev info + * @hw_intf: CPAS HW interface + * @hw_caps: CPAS HW capabilities + * @intf_lock: CPAS interface mutex + * @open_cnt: CPAS subdev open count + * @probe_done: Whether CPAS prove completed + * + */ +struct cam_cpas_intf { + struct platform_device *pdev; + struct cam_subdev subdev; + struct cam_hw_intf *hw_intf; + struct cam_cpas_hw_caps hw_caps; + struct mutex intf_lock; + uint32_t open_cnt; + bool probe_done; +}; + +static struct cam_cpas_intf *g_cpas_intf; + +const char *cam_cpas_axi_util_path_type_to_string( + uint32_t path_data_type) +{ + switch (path_data_type) { + /* IFE Paths */ + case CAM_AXI_PATH_DATA_IFE_LINEAR: + return "IFE_LINEAR"; + case CAM_AXI_PATH_DATA_IFE_VID: + return "IFE_VID"; + case CAM_AXI_PATH_DATA_IFE_DISP: + return "IFE_DISP"; + case CAM_AXI_PATH_DATA_IFE_STATS: + return "IFE_STATS"; + case CAM_AXI_PATH_DATA_IFE_RDI0: + return "IFE_RDI0"; + case CAM_AXI_PATH_DATA_IFE_RDI1: + return "IFE_RDI1"; + case CAM_AXI_PATH_DATA_IFE_RDI2: + return "IFE_RDI2"; + case CAM_AXI_PATH_DATA_IFE_RDI3: + return "IFE_RDI3"; + case CAM_AXI_PATH_DATA_IFE_PDAF: + return "IFE_PDAF"; + case CAM_AXI_PATH_DATA_IFE_PIXEL_RAW: + return "IFE_PIXEL_RAW"; + + /* IPE Paths */ + case CAM_AXI_PATH_DATA_IPE_RD_IN: + return "IPE_RD_IN"; + case CAM_AXI_PATH_DATA_IPE_RD_REF: + return "IPE_RD_REF"; + case CAM_AXI_PATH_DATA_IPE_WR_VID: + return "IPE_WR_VID"; + case CAM_AXI_PATH_DATA_IPE_WR_DISP: + return "IPE_WR_DISP"; + case CAM_AXI_PATH_DATA_IPE_WR_REF: + return "IPE_WR_REF"; + + /* Common Paths */ + case CAM_AXI_PATH_DATA_ALL: + return "DATA_ALL"; + default: + return "IFE_PATH_INVALID"; + } +} +EXPORT_SYMBOL(cam_cpas_axi_util_path_type_to_string); + +const char *cam_cpas_axi_util_trans_type_to_string( + uint32_t transac_type) +{ + switch (transac_type) { + case CAM_AXI_TRANSACTION_READ: + return "TRANSAC_READ"; + case CAM_AXI_TRANSACTION_WRITE: + return "TRANSAC_WRITE"; + default: + return "TRANSAC_INVALID"; + } +} +EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string); + +int cam_cpas_get_cpas_hw_version(uint32_t *hw_version) +{ + struct cam_hw_info *cpas_hw = NULL; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!hw_version) { + CAM_ERR(CAM_CPAS, "invalid input %pK", hw_version); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv; + + *hw_version = cpas_hw->soc_info.hw_version; + + if (*hw_version == CAM_CPAS_TITAN_NONE) { + CAM_DBG(CAM_CPAS, "Didn't find a valid HW Version %d", + *hw_version); + } + + return 0; +} + +int cam_cpas_get_hw_info(uint32_t *camera_family, + struct cam_hw_version *camera_version, + struct cam_hw_version *cpas_version, + uint32_t *cam_caps) +{ + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!camera_family || !camera_version || !cpas_version || !cam_caps) { + CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK", + camera_family, camera_version, cpas_version, cam_caps); + return -EINVAL; + } + + *camera_family = g_cpas_intf->hw_caps.camera_family; + *camera_version = g_cpas_intf->hw_caps.camera_version; + *cpas_version = g_cpas_intf->hw_caps.cpas_version; + *cam_caps = g_cpas_intf->hw_caps.camera_capability; + + return 0; +} +EXPORT_SYMBOL(cam_cpas_get_hw_info); + +int cam_cpas_reg_write(uint32_t client_handle, + enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb, + uint32_t value) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_reg_read_write cmd_reg_write; + + cmd_reg_write.client_handle = client_handle; + cmd_reg_write.reg_base = reg_base; + cmd_reg_write.offset = offset; + cmd_reg_write.value = value; + cmd_reg_write.mb = mb; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_REG_WRITE, &cmd_reg_write, + sizeof(struct cam_cpas_hw_cmd_reg_read_write)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_reg_write); + +int cam_cpas_reg_read(uint32_t client_handle, + enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb, + uint32_t *value) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!value) { + CAM_ERR(CAM_CPAS, "Invalid arg value"); + return -EINVAL; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_reg_read_write cmd_reg_read; + + cmd_reg_read.client_handle = client_handle; + cmd_reg_read.reg_base = reg_base; + cmd_reg_read.offset = offset; + cmd_reg_read.mb = mb; + cmd_reg_read.value = 0; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_REG_READ, &cmd_reg_read, + sizeof(struct cam_cpas_hw_cmd_reg_read_write)); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + return rc; + } + + *value = cmd_reg_read.value; + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_reg_read); + +int cam_cpas_update_axi_vote(uint32_t client_handle, + struct cam_axi_vote *axi_vote) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!axi_vote) { + CAM_ERR(CAM_CPAS, "NULL axi vote"); + return -EINVAL; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_axi_vote cmd_axi_vote; + + cmd_axi_vote.client_handle = client_handle; + cmd_axi_vote.axi_vote = axi_vote; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_AXI_VOTE, &cmd_axi_vote, + sizeof(struct cam_cpas_hw_cmd_axi_vote)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_update_axi_vote); + +int cam_cpas_update_ahb_vote(uint32_t client_handle, + struct cam_ahb_vote *ahb_vote) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_ahb_vote cmd_ahb_vote; + + cmd_ahb_vote.client_handle = client_handle; + cmd_ahb_vote.ahb_vote = ahb_vote; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_AHB_VOTE, &cmd_ahb_vote, + sizeof(struct cam_cpas_hw_cmd_ahb_vote)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_update_ahb_vote); + +int cam_cpas_stop(uint32_t client_handle) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.stop) { + struct cam_cpas_hw_cmd_stop cmd_hw_stop; + + cmd_hw_stop.client_handle = client_handle; + + rc = g_cpas_intf->hw_intf->hw_ops.stop( + g_cpas_intf->hw_intf->hw_priv, &cmd_hw_stop, + sizeof(struct cam_cpas_hw_cmd_stop)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in stop, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid stop ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_stop); + +int cam_cpas_start(uint32_t client_handle, + struct cam_ahb_vote *ahb_vote, struct cam_axi_vote *axi_vote) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!axi_vote) { + CAM_ERR(CAM_CPAS, "NULL axi vote"); + return -EINVAL; + } + + if (g_cpas_intf->hw_intf->hw_ops.start) { + struct cam_cpas_hw_cmd_start cmd_hw_start; + + cmd_hw_start.client_handle = client_handle; + cmd_hw_start.ahb_vote = ahb_vote; + cmd_hw_start.axi_vote = axi_vote; + + rc = g_cpas_intf->hw_intf->hw_ops.start( + g_cpas_intf->hw_intf->hw_priv, &cmd_hw_start, + sizeof(struct cam_cpas_hw_cmd_start)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in start, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid start ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_start); + +int cam_cpas_unregister_client(uint32_t client_handle) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_UNREGISTER_CLIENT, + &client_handle, sizeof(uint32_t)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_unregister_client); + +int cam_cpas_register_client( + struct cam_cpas_register_params *register_params) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_REGISTER_CLIENT, register_params, + sizeof(struct cam_cpas_register_params)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_register_client); + +int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf, + struct cam_control *cmd) +{ + int rc = 0; + + if (!cmd) { + CAM_ERR(CAM_CPAS, "Invalid input cmd"); + return -EINVAL; + } + + switch (cmd->op_code) { + case CAM_QUERY_CAP: { + struct cam_cpas_query_cap query; + + rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle), + sizeof(query)); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d", + rc); + break; + } + + rc = cam_cpas_get_hw_info(&query.camera_family, + &query.camera_version, &query.cpas_version, + &query.reserved); + if (rc) + break; + + rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query, + sizeof(query)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc); + + break; + } + case CAM_SD_SHUTDOWN: + break; + default: + CAM_ERR(CAM_CPAS, "Unknown op code %d for CPAS", cmd->op_code); + rc = -EINVAL; + break; + } + + return rc; +} + +static int cam_cpas_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + mutex_lock(&cpas_intf->intf_lock); + cpas_intf->open_cnt++; + CAM_DBG(CAM_CPAS, "CPAS Subdev open count %d", cpas_intf->open_cnt); + mutex_unlock(&cpas_intf->intf_lock); + + return 0; +} + +static int cam_cpas_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + mutex_lock(&cpas_intf->intf_lock); + cpas_intf->open_cnt--; + CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt); + mutex_unlock(&cpas_intf->intf_lock); + + return 0; +} + +static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc; + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg); + break; + default: + CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd); + rc = -EINVAL; + break; + } + + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc; + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_CPAS, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data); + break; + default: + CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd); + rc = -EINVAL; + break; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_CPAS, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static struct v4l2_subdev_core_ops cpas_subdev_core_ops = { + .ioctl = cam_cpas_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_cpas_subdev_compat_ioctl, +#endif +}; + +static const struct v4l2_subdev_ops cpas_subdev_ops = { + .core = &cpas_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cpas_subdev_intern_ops = { + .open = cam_cpas_subdev_open, + .close = cam_cpas_subdev_close, +}; + +static int cam_cpas_subdev_register(struct platform_device *pdev) +{ + int rc; + struct cam_subdev *subdev; + + if (!g_cpas_intf) + return -EINVAL; + + subdev = &g_cpas_intf->subdev; + + subdev->name = CAM_CPAS_DEV_NAME; + subdev->pdev = pdev; + subdev->ops = &cpas_subdev_ops; + subdev->internal_ops = &cpas_subdev_intern_ops; + subdev->token = g_cpas_intf; + subdev->sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + subdev->ent_function = CAM_CPAS_DEVICE_TYPE; + + rc = cam_register_subdev(subdev); + if (rc) { + CAM_ERR(CAM_CPAS, "failed register subdev: %s!", + CAM_CPAS_DEV_NAME); + return rc; + } + + platform_set_drvdata(g_cpas_intf->pdev, g_cpas_intf); + return rc; +} + +static int cam_cpas_dev_probe(struct platform_device *pdev) +{ + struct cam_cpas_hw_caps *hw_caps; + struct cam_hw_intf *hw_intf; + int rc; + + if (g_cpas_intf) { + CAM_ERR(CAM_CPAS, "cpas dev proble already done"); + return -EALREADY; + } + + g_cpas_intf = kzalloc(sizeof(*g_cpas_intf), GFP_KERNEL); + if (!g_cpas_intf) + return -ENOMEM; + + mutex_init(&g_cpas_intf->intf_lock); + g_cpas_intf->pdev = pdev; + + rc = cam_cpas_hw_probe(pdev, &g_cpas_intf->hw_intf); + if (rc || (g_cpas_intf->hw_intf == NULL)) { + CAM_ERR(CAM_CPAS, "Failed in hw probe, rc=%d", rc); + goto error_destroy_mem; + } + + hw_intf = g_cpas_intf->hw_intf; + hw_caps = &g_cpas_intf->hw_caps; + if (hw_intf->hw_ops.get_hw_caps) { + rc = hw_intf->hw_ops.get_hw_caps(hw_intf->hw_priv, + hw_caps, sizeof(struct cam_cpas_hw_caps)); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in get_hw_caps, rc=%d", rc); + goto error_hw_remove; + } + } else { + CAM_ERR(CAM_CPAS, "Invalid get_hw_caps ops"); + goto error_hw_remove; + } + + rc = cam_cpas_subdev_register(pdev); + if (rc) + goto error_hw_remove; + + g_cpas_intf->probe_done = true; + CAM_DBG(CAM_CPAS, + "CPAS INTF Probe success %d, %d.%d.%d, %d.%d.%d, 0x%x", + hw_caps->camera_family, hw_caps->camera_version.major, + hw_caps->camera_version.minor, hw_caps->camera_version.incr, + hw_caps->cpas_version.major, hw_caps->cpas_version.minor, + hw_caps->cpas_version.incr, hw_caps->camera_capability); + + return rc; + +error_hw_remove: + cam_cpas_hw_remove(g_cpas_intf->hw_intf); +error_destroy_mem: + mutex_destroy(&g_cpas_intf->intf_lock); + kfree(g_cpas_intf); + g_cpas_intf = NULL; + CAM_ERR(CAM_CPAS, "CPAS probe failed"); + return rc; +} + +static int cam_cpas_dev_remove(struct platform_device *dev) +{ + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + mutex_lock(&g_cpas_intf->intf_lock); + g_cpas_intf->probe_done = false; + cam_unregister_subdev(&g_cpas_intf->subdev); + cam_cpas_hw_remove(g_cpas_intf->hw_intf); + mutex_unlock(&g_cpas_intf->intf_lock); + mutex_destroy(&g_cpas_intf->intf_lock); + kfree(g_cpas_intf); + g_cpas_intf = NULL; + + return 0; +} + +static const struct of_device_id cam_cpas_dt_match[] = { + {.compatible = "qcom,cam-cpas"}, + {} +}; + +static struct platform_driver cam_cpas_driver = { + .probe = cam_cpas_dev_probe, + .remove = cam_cpas_dev_remove, + .driver = { + .name = CAM_CPAS_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_cpas_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_cpas_dev_init_module(void) +{ + return platform_driver_register(&cam_cpas_driver); +} + +static void __exit cam_cpas_dev_exit_module(void) +{ + platform_driver_unregister(&cam_cpas_driver); +} + +module_init(cam_cpas_dev_init_module); +module_exit(cam_cpas_dev_exit_module); +MODULE_DESCRIPTION("MSM CPAS driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c new file mode 100644 index 000000000000..9dd24cdaa3d1 --- /dev/null +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -0,0 +1,614 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_cpas_api.h" +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_hw.h" +#include "cam_cpas_soc.h" + +static uint cpas_dump; +module_param(cpas_dump, uint, 0644); + + +void cam_cpas_dump_axi_vote_info( + const struct cam_cpas_client *cpas_client, + const char *identifier, + struct cam_axi_vote *axi_vote) +{ + int i; + + if (!cpas_dump) + return; + + if (!axi_vote || (axi_vote->num_paths > + CAM_CPAS_MAX_PATHS_PER_CLIENT)) { + CAM_ERR(CAM_PERF, "Invalid num_paths %d", + axi_vote ? axi_vote->num_paths : -1); + return; + } + + for (i = 0; i < axi_vote->num_paths; i++) { + CAM_INFO(CAM_PERF, + "Client [%s][%d] : [%s], Path=[%d] [%d], camnoc[%llu], mnoc_ab[%llu], mnoc_ib[%llu]", + cpas_client->data.identifier, cpas_client->data.cell_index, + identifier, + axi_vote->axi_path[i].path_data_type, + axi_vote->axi_path[i].transac_type, + axi_vote->axi_path[i].camnoc_bw, + axi_vote->axi_path[i].mnoc_ab_bw, + axi_vote->axi_path[i].mnoc_ib_bw); + } + +} + +void cam_cpas_util_debug_parse_data( + struct cam_cpas_private_soc *soc_private) +{ + int i, j; + struct cam_cpas_tree_node *curr_node = NULL; + + if (!cpas_dump) + return; + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + if (!soc_private->tree_node[i]) + break; + + curr_node = soc_private->tree_node[i]; + CAM_INFO(CAM_CPAS, + "NODE cell_idx: %d, level: %d, name: %s, axi_port_idx: %d, merge_type: %d, parent_name: %s", + curr_node->cell_idx, curr_node->level_idx, + curr_node->node_name, curr_node->axi_port_idx, + curr_node->merge_type, curr_node->parent_node ? + curr_node->parent_node->node_name : "no parent"); + + if (curr_node->level_idx) + continue; + + CAM_INFO(CAM_CPAS, "path_type: %d, transac_type: %s", + curr_node->path_data_type, + cam_cpas_axi_util_trans_type_to_string( + curr_node->path_trans_type)); + + for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) { + CAM_INFO(CAM_CPAS, "Constituent path: %d", + curr_node->constituent_paths[j] ? j : -1); + } + } + + CAM_INFO(CAM_CPAS, "NUMBER OF NODES PARSED: %d", i); +} + +int cam_cpas_node_tree_cleanup(struct cam_cpas *cpas_core, + struct cam_cpas_private_soc *soc_private) +{ + int i = 0; + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + if (soc_private->tree_node[i]) { + of_node_put(soc_private->tree_node[i]->tree_dev_node); + kfree(soc_private->tree_node[i]); + soc_private->tree_node[i] = NULL; + } + } + + for (i = 0; i < CAM_CPAS_MAX_TREE_LEVELS; i++) { + of_node_put(soc_private->level_node[i]); + soc_private->level_node[i] = NULL; + } + + of_node_put(soc_private->camera_bus_node); + soc_private->camera_bus_node = NULL; + mutex_destroy(&cpas_core->tree_lock); + + return 0; +} + +static int cam_cpas_util_path_type_to_idx(uint32_t *path_data_type) +{ + if (*path_data_type >= CAM_CPAS_PATH_DATA_CONSO_OFFSET) + *path_data_type = CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT + + (*path_data_type % CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT); + else + *path_data_type %= CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT; + + if (*path_data_type >= CAM_CPAS_PATH_DATA_MAX) { + CAM_ERR(CAM_CPAS, "index Invalid: %d", path_data_type); + return -EINVAL; + } + + return 0; +} + +static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, + struct device_node *of_node, struct cam_cpas_private_soc *soc_private) +{ + struct device_node *camera_bus_node; + struct device_node *level_node; + struct device_node *curr_node; + struct device_node *parent_node; + struct device_node *mnoc_node; + int mnoc_idx = 0; + uint32_t path_idx; + bool camnoc_max_needed = false; + struct cam_cpas_tree_node *curr_node_ptr = NULL; + struct cam_cpas_client *curr_client = NULL; + const char *client_name = NULL; + uint32_t client_idx = 0, cell_idx = 0, level_idx = 0; + int rc = 0, count = 0, i; + + camera_bus_node = of_find_node_by_name(of_node, "camera-bus-nodes"); + if (!camera_bus_node) { + CAM_ERR(CAM_CPAS, "Camera Bus node not found in cpas DT node"); + return -EINVAL; + } + + soc_private->camera_bus_node = camera_bus_node; + + for_each_available_child_of_node(camera_bus_node, level_node) { + rc = of_property_read_u32(level_node, "level-index", + &level_idx); + if (rc) { + CAM_ERR(CAM_CPAS, "Error raeding level idx rc: %d", rc); + return rc; + } + if (level_idx >= CAM_CPAS_MAX_TREE_LEVELS) { + CAM_ERR(CAM_CPAS, "Invalid level idx: %d", level_idx); + return -EINVAL; + } + + soc_private->level_node[level_idx] = level_node; + camnoc_max_needed = of_property_read_bool(level_node, + "camnoc-max-needed"); + + for_each_available_child_of_node(level_node, curr_node) { + curr_node_ptr = + kzalloc(sizeof(struct cam_cpas_tree_node), + GFP_KERNEL); + if (!curr_node_ptr) + return -ENOMEM; + + curr_node_ptr->tree_dev_node = curr_node; + rc = of_property_read_u32(curr_node, "cell-index", + &curr_node_ptr->cell_idx); + if (rc) { + CAM_ERR(CAM_CPAS, "Node index not found"); + return rc; + } + + if (curr_node_ptr->cell_idx >= + CAM_CPAS_MAX_TREE_NODES) { + CAM_ERR(CAM_CPAS, "Invalid cell idx: %d", + cell_idx); + return -EINVAL; + } + + soc_private->tree_node[curr_node_ptr->cell_idx] = + curr_node_ptr; + curr_node_ptr->level_idx = level_idx; + + rc = of_property_read_string(curr_node, "node-name", + &curr_node_ptr->node_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read node-name rc=%d", + rc); + return rc; + } + + curr_node_ptr->camnoc_max_needed = camnoc_max_needed; + rc = of_property_read_u32(curr_node, "bus-width-factor", + &curr_node_ptr->bus_width_factor); + if (rc) + curr_node_ptr->bus_width_factor = 1; + + rc = of_property_read_u32(curr_node, + "traffic-merge-type", + &curr_node_ptr->merge_type); + + curr_node_ptr->axi_port_idx = -1; + mnoc_node = of_find_node_by_name(curr_node, + "qcom,axi-port-mnoc"); + if (mnoc_node) { + if (mnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) + return -EINVAL; + + cpas_core->axi_port[mnoc_idx].axi_port_node + = mnoc_node; + rc = of_property_read_string( + curr_node, "qcom,axi-port-name", + &cpas_core->axi_port[mnoc_idx] + .axi_port_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read mnoc-port-name rc=%d", + rc); + return rc; + } + cpas_core->axi_port + [mnoc_idx].ib_bw_voting_needed + = of_property_read_bool(curr_node, + "ib-bw-voting-needed"); + curr_node_ptr->axi_port_idx = mnoc_idx; + mnoc_idx++; + cpas_core->num_axi_ports++; + } + + rc = of_property_read_string(curr_node, + "client-name", &client_name); + if (!rc) { + rc = of_property_read_u32(curr_node, + "traffic-data", &curr_node_ptr->path_data_type); + if (rc) { + CAM_ERR(CAM_CPAS, + "Path Data type not found"); + return rc; + } + + rc = cam_cpas_util_path_type_to_idx( + &curr_node_ptr->path_data_type); + if (rc) + return rc; + + rc = of_property_read_u32(curr_node, + "traffic-transaction-type", + &curr_node_ptr->path_trans_type); + if (rc) { + CAM_ERR(CAM_CPAS, + "Path Transac type not found"); + return rc; + } + + if (curr_node_ptr->path_trans_type >= + CAM_CPAS_TRANSACTION_MAX) { + CAM_ERR(CAM_CPAS, + "Invalid transac type: %d", + curr_node_ptr->path_trans_type); + return -EINVAL; + } + + count = of_property_count_u32_elems(curr_node, + "constituent-paths"); + for (i = 0; i < count; i++) { + rc = of_property_read_u32_index( + curr_node, "constituent-paths", + i, &path_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "No constituent path at %d", i); + return rc; + } + + rc = cam_cpas_util_path_type_to_idx( + &path_idx); + if (rc) + return rc; + + curr_node_ptr->constituent_paths + [path_idx] = true; + } + + rc = cam_common_util_get_string_index( + soc_private->client_name, + soc_private->num_clients, + client_name, &client_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "client name not found in list: %s", + client_name); + return rc; + } + + if (client_idx >= CAM_CPAS_MAX_CLIENTS) + return -EINVAL; + + curr_client = + cpas_core->cpas_client[client_idx]; + curr_client->tree_node_valid = true; + curr_client->tree_node + [curr_node_ptr->path_data_type] + [curr_node_ptr->path_trans_type] = + curr_node_ptr; + CAM_DBG(CAM_CPAS, + "CLIENT NODE ADDED: %d %d %s", + curr_node_ptr->path_data_type, + curr_node_ptr->path_trans_type, + client_name); + } + + parent_node = of_parse_phandle(curr_node, + "parent-node", 0); + if (parent_node) { + of_property_read_u32(parent_node, "cell-index", + &cell_idx); + curr_node_ptr->parent_node = + soc_private->tree_node[cell_idx]; + } else { + CAM_DBG(CAM_CPAS, + "no parent node at this level"); + } + } + } + mutex_init(&cpas_core->tree_lock); + cam_cpas_util_debug_parse_data(soc_private); + + return 0; +} + +int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, + struct platform_device *pdev, struct cam_cpas_private_soc *soc_private) +{ + struct device_node *of_node; + int count = 0, i = 0, rc = 0; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + + if (!soc_private || !pdev) { + CAM_ERR(CAM_CPAS, "invalid input arg %pK %pK", + soc_private, pdev); + return -EINVAL; + } + + of_node = pdev->dev.of_node; + + rc = of_property_read_string(of_node, "arch-compat", + &soc_private->arch_compat); + if (rc) { + CAM_ERR(CAM_CPAS, "device %s failed to read arch-compat", + pdev->name); + return rc; + } + + soc_private->camnoc_axi_min_ib_bw = 0; + rc = of_property_read_u64(of_node, + "camnoc-axi-min-ib-bw", + &soc_private->camnoc_axi_min_ib_bw); + if (rc == -EOVERFLOW) { + soc_private->camnoc_axi_min_ib_bw = 0; + rc = of_property_read_u32(of_node, + "camnoc-axi-min-ib-bw", + (u32 *)&soc_private->camnoc_axi_min_ib_bw); + } + + if (rc) { + CAM_DBG(CAM_CPAS, + "failed to read camnoc-axi-min-ib-bw rc:%d", rc); + soc_private->camnoc_axi_min_ib_bw = + CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + } + + CAM_DBG(CAM_CPAS, "camnoc-axi-min-ib-bw = %llu", + soc_private->camnoc_axi_min_ib_bw); + + soc_private->client_id_based = of_property_read_bool(of_node, + "client-id-based"); + + count = of_property_count_strings(of_node, "client-names"); + if (count <= 0) { + CAM_ERR(CAM_CPAS, "no client-names found"); + count = 0; + return -EINVAL; + } else if (count > CAM_CPAS_MAX_CLIENTS) { + CAM_ERR(CAM_CPAS, "Number of clients %d greater than max %d", + count, CAM_CPAS_MAX_CLIENTS); + count = 0; + return -EINVAL; + } + + soc_private->num_clients = count; + CAM_DBG(CAM_CPAS, + "arch-compat=%s, client_id_based = %d, num_clients=%d", + soc_private->arch_compat, soc_private->client_id_based, + soc_private->num_clients); + + for (i = 0; i < soc_private->num_clients; i++) { + rc = of_property_read_string_index(of_node, + "client-names", i, &soc_private->client_name[i]); + if (rc) { + CAM_ERR(CAM_CPAS, "no client-name at cnt=%d", i); + return -EINVAL; + } + + cpas_core->cpas_client[i] = + kzalloc(sizeof(struct cam_cpas_client), GFP_KERNEL); + if (!cpas_core->cpas_client[i]) { + rc = -ENOMEM; + goto cleanup_clients; + } + + CAM_DBG(CAM_CPAS, "Client[%d] : %s", i, + soc_private->client_name[i]); + } + + soc_private->control_camnoc_axi_clk = of_property_read_bool(of_node, + "control-camnoc-axi-clk"); + + if (soc_private->control_camnoc_axi_clk == true) { + rc = of_property_read_u32(of_node, "camnoc-bus-width", + &soc_private->camnoc_bus_width); + if (rc || (soc_private->camnoc_bus_width == 0)) { + CAM_ERR(CAM_CPAS, "Bus width not found rc=%d, %d", + rc, soc_private->camnoc_bus_width); + goto cleanup_clients; + } + + rc = of_property_read_u32(of_node, + "camnoc-axi-clk-bw-margin-perc", + &soc_private->camnoc_axi_clk_bw_margin); + + if (rc) { + /* this is not fatal, overwrite rc */ + rc = 0; + soc_private->camnoc_axi_clk_bw_margin = 0; + } + } + + CAM_DBG(CAM_CPAS, + "control_camnoc_axi_clk=%d, width=%d, margin=%d", + soc_private->control_camnoc_axi_clk, + soc_private->camnoc_bus_width, + soc_private->camnoc_axi_clk_bw_margin); + + count = of_property_count_u32_elems(of_node, "vdd-corners"); + if ((count > 0) && (count <= CAM_REGULATOR_LEVEL_MAX) && + (of_property_count_strings(of_node, "vdd-corner-ahb-mapping") == + count)) { + const char *ahb_string; + + for (i = 0; i < count; i++) { + rc = of_property_read_u32_index(of_node, "vdd-corners", + i, &soc_private->vdd_ahb[i].vdd_corner); + if (rc) { + CAM_ERR(CAM_CPAS, + "vdd-corners failed at index=%d", i); + rc = -ENODEV; + goto cleanup_clients; + } + + rc = of_property_read_string_index(of_node, + "vdd-corner-ahb-mapping", i, &ahb_string); + if (rc) { + CAM_ERR(CAM_CPAS, + "no ahb-mapping at index=%d", i); + rc = -ENODEV; + goto cleanup_clients; + } + + rc = cam_soc_util_get_level_from_string(ahb_string, + &soc_private->vdd_ahb[i].ahb_level); + if (rc) { + CAM_ERR(CAM_CPAS, + "invalid ahb-string at index=%d", i); + rc = -EINVAL; + goto cleanup_clients; + } + + CAM_DBG(CAM_CPAS, + "Vdd-AHB mapping [%d] : [%d] [%s] [%d]", i, + soc_private->vdd_ahb[i].vdd_corner, + ahb_string, soc_private->vdd_ahb[i].ahb_level); + } + + soc_private->num_vdd_ahb_mapping = count; + } + + rc = cam_cpas_parse_node_tree(cpas_core, of_node, soc_private); + if (rc) { + CAM_ERR(CAM_CPAS, "Node tree parsing failed rc: %d", rc); + goto cleanup_tree; + } + + return 0; + +cleanup_tree: + cam_cpas_node_tree_cleanup(cpas_core, soc_private); +cleanup_clients: + cam_cpas_util_client_cleanup(cpas_hw); + return rc; +} + +int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, struct cam_hw_info *cpas_hw) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in get_dt_properties, rc=%d", rc); + return rc; + } + + if (soc_info->irq_line && !irq_handler) { + CAM_ERR(CAM_CPAS, "Invalid IRQ handler"); + return -EINVAL; + } + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + cpas_hw); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in request_platform_resource, rc=%d", + rc); + return rc; + } + + soc_info->soc_private = kzalloc(sizeof(struct cam_cpas_private_soc), + GFP_KERNEL); + if (!soc_info->soc_private) { + rc = -ENOMEM; + goto release_res; + } + + rc = cam_cpas_get_custom_dt_info(cpas_hw, soc_info->pdev, + soc_info->soc_private); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in get_custom_info, rc=%d", rc); + goto free_soc_private; + } + + return rc; + +free_soc_private: + kfree(soc_info->soc_private); +release_res: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} + +int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_CPAS, "release platform failed, rc=%d", rc); + + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; + + return rc; +} + +int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info, + enum cam_vote_level default_level) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + default_level, true); + if (rc) + CAM_ERR(CAM_CPAS, "enable platform resource failed, rc=%d", rc); + + return rc; +} + +int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, + disable_clocks, disable_irq); + if (rc) + CAM_ERR(CAM_CPAS, "disable platform failed, rc=%d", rc); + + return rc; +} + +int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_irq_disable(soc_info); + if (rc) + CAM_ERR(CAM_CPAS, "disable irq failed, rc=%d", rc); + + return rc; +} diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h new file mode 100644 index 000000000000..7921cd4b956e --- /dev/null +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_SOC_H_ +#define _CAM_CPAS_SOC_H_ + +#include "cam_soc_util.h" +#include "cam_cpas_hw.h" + +#define CAM_REGULATOR_LEVEL_MAX 16 +#define CAM_CPAS_MAX_TREE_NODES 50 + +/** + * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping + * + * @vdd_corner : Voltage corner value + * @ahb_level : AHB vote level corresponds to this vdd_corner + * + */ +struct cam_cpas_vdd_ahb_mapping { + unsigned int vdd_corner; + enum cam_vote_level ahb_level; +}; + +/** + * struct cpas_tree_node: Generic cpas tree node for BW voting + * + * @cell_idx: Index to identify node from device tree and its parent + * @level_idx: Index to identify at what level the node is present + * @axi_port_idx: Index to identify which axi port to vote the consolidated bw + * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc) + * @path_trans_type: Transaction type info from device tree (rd, wr) + * @merge_type: Traffic merge type (calculation info) from device tree + * @bus_width_factor: Factor for accounting bus width in CAMNOC bw calculation + * @camnoc_bw: CAMNOC bw value at current node + * @mnoc_ab_bw: MNOC AB bw value at current node + * @mnoc_ib_bw: MNOC IB bw value at current node + * @ddr_ab_bw: DDR AB bw value at current node + * @ddr_ib_bw: DDR IB bw value at current node + * @camnoc_max_needed: If node is needed for CAMNOC BW calculation then true + * @constituent_paths: Constituent paths presence info from device tree + * Ex: For CAM_CPAS_PATH_DATA_IFE_UBWC_STATS, index corresponding to + * CAM_CPAS_PATH_DATA_IFE_VID, CAM_CPAS_PATH_DATA_IFE_DISP and + * CAM_CPAS_PATH_DATA_IFE_STATS + * @tree_dev_node: Device node from devicetree for current tree node + * @parent_node: Pointer to node one or more level above the current level + * (starting from end node of cpas client) + * + */ +struct cam_cpas_tree_node { + uint32_t cell_idx; + uint32_t level_idx; + int axi_port_idx; + const char *node_name; + uint32_t path_data_type; + uint32_t path_trans_type; + uint32_t merge_type; + uint32_t bus_width_factor; + uint64_t camnoc_bw; + uint64_t mnoc_ab_bw; + uint64_t mnoc_ib_bw; + uint64_t ddr_ab_bw; + uint64_t ddr_ib_bw; + bool camnoc_max_needed; + bool constituent_paths[CAM_CPAS_PATH_DATA_MAX]; + struct device_node *tree_dev_node; + struct cam_cpas_tree_node *parent_node; +}; + +/** + * struct cam_cpas_private_soc : CPAS private DT info + * + * @arch_compat: ARCH compatible string + * @client_id_based: Whether clients are id based + * @num_clients: Number of clients supported + * @client_name: Client names + * @tree_node: Array of pointers to all tree nodes required to calculate + * axi bw, arranged with help of cell index in device tree + * @camera_bus_node: Device tree node from cpas node + * @level_node: Device tree node for each level in camera_bus_node + * @num_vdd_ahb_mapping : Number of vdd to ahb level mapping supported + * @vdd_ahb : AHB level mapping info for the supported vdd levels + * @control_camnoc_axi_clk : Whether CPAS driver need to set camnoc axi clk freq + * @camnoc_bus_width : CAMNOC Bus width + * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating + * camnoc axi clock + * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target + * + */ +struct cam_cpas_private_soc { + const char *arch_compat; + bool client_id_based; + uint32_t num_clients; + const char *client_name[CAM_CPAS_MAX_CLIENTS]; + struct cam_cpas_tree_node *tree_node[CAM_CPAS_MAX_TREE_NODES]; + struct device_node *camera_bus_node; + struct device_node *level_node[CAM_CPAS_MAX_TREE_LEVELS]; + uint32_t num_vdd_ahb_mapping; + struct cam_cpas_vdd_ahb_mapping vdd_ahb[CAM_REGULATOR_LEVEL_MAX]; + bool control_camnoc_axi_clk; + uint32_t camnoc_bus_width; + uint32_t camnoc_axi_clk_bw_margin; + uint64_t camnoc_axi_min_ib_bw; +}; + +void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); +void cam_cpas_dump_axi_vote_info( + const struct cam_cpas_client *cpas_client, + const char *identifier, + struct cam_axi_vote *axi_vote); +int cam_cpas_node_tree_cleanup(struct cam_cpas *cpas_core, + struct cam_cpas_private_soc *soc_private); +int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, struct cam_hw_info *cpas_hw); +int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info); +int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info, + enum cam_vote_level default_level); +int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq); +int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info); +#endif /* _CAM_CPAS_SOC_H_ */ diff --git a/drivers/cam_cpas/camss_top/Makefile b/drivers/cam_cpas/camss_top/Makefile new file mode 100644 index 000000000000..902e74e20607 --- /dev/null +++ b/drivers/cam_cpas/camss_top/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_camsstop_hw.o diff --git a/drivers/cam_cpas/camss_top/cam_camsstop_hw.c b/drivers/cam_cpas/camss_top/cam_camsstop_hw.c new file mode 100644 index 000000000000..b7f3550bc632 --- /dev/null +++ b/drivers/cam_cpas/camss_top/cam_camsstop_hw.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_hw.h" +#include "cam_cpas_soc.h" + +int cam_camsstop_get_hw_info(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CAMSS]; + uint32_t reg_value; + + if (reg_indx == -1) + return -EINVAL; + + hw_caps->camera_family = CAM_FAMILY_CAMERA_SS; + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x0); + hw_caps->camera_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c); + hw_caps->camera_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->camera_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + CAM_DBG(CAM_FD, "Family %d, version %d.%d.%d", + hw_caps->camera_family, hw_caps->camera_version.major, + hw_caps->camera_version.minor, hw_caps->camera_version.incr); + + return 0; +} + +int cam_camsstop_setup_regbase_indices(struct cam_hw_soc_info *soc_info, + int32_t regbase_index[], int32_t num_reg_map) +{ + uint32_t index; + int rc; + + if (num_reg_map > CAM_CPAS_REG_MAX) { + CAM_ERR(CAM_CPAS, "invalid num_reg_map=%d", num_reg_map); + return -EINVAL; + } + + if (soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) { + CAM_ERR(CAM_CPAS, "invalid num_mem_block=%d", + soc_info->num_mem_block); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "cam_camss", &index); + if ((rc == 0) && (index < num_reg_map)) { + regbase_index[CAM_CPAS_REG_CAMSS] = index; + } else { + CAM_ERR(CAM_CPAS, "regbase not found for CAM_CPAS_REG_CAMSS"); + return -EINVAL; + } + + return 0; +} + +int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops) +{ + if (!internal_ops) { + CAM_ERR(CAM_CPAS, "invalid NULL param"); + return -EINVAL; + } + + internal_ops->get_hw_info = cam_camsstop_get_hw_info; + internal_ops->init_hw_version = NULL; + internal_ops->handle_irq = NULL; + internal_ops->setup_regbase = cam_camsstop_setup_regbase_indices; + internal_ops->power_on = NULL; + internal_ops->power_off = NULL; + + return 0; +} diff --git a/drivers/cam_cpas/cpas_top/Makefile b/drivers/cam_cpas/cpas_top/Makefile new file mode 100644 index 000000000000..2db4c393c65d --- /dev/null +++ b/drivers/cam_cpas/cpas_top/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpastop_hw.o diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c new file mode 100644 index 000000000000..57eb9de92be4 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include + +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_hw.h" +#include "cam_cpastop_hw.h" +#include "cam_io_util.h" +#include "cam_cpas_soc.h" +#include "cpastop100.h" +#include "cpastop_v150_100.h" +#include "cpastop_v170_110.h" +#include "cpastop_v175_100.h" +#include "cpastop_v175_101.h" +#include "cpastop_v175_120.h" +#include "cpastop_v175_130.h" +#include "cpastop_v480_100.h" + +struct cam_camnoc_info *camnoc_info; + +#define CAMNOC_SLAVE_MAX_ERR_CODE 7 +static const char * const camnoc_salve_err_code[] = { + "Target Error", /* err code 0 */ + "Address decode error", /* err code 1 */ + "Unsupported request", /* err code 2 */ + "Disconnected target", /* err code 3 */ + "Security violation", /* err code 4 */ + "Hidden security violation", /* err code 5 */ + "Timeout Error", /* err code 6 */ + "Unknown Error", /* unknown err code */ +}; + +static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP]; + uint32_t reg_value; + + if (reg_indx == -1) + return -EINVAL; + + hw_caps->camera_family = CAM_FAMILY_CPAS_SS; + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x0); + hw_caps->camera_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xff0000, 0x10); + hw_caps->camera_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xff00, 0x8); + hw_caps->camera_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x4); + hw_caps->cpas_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c); + hw_caps->cpas_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->cpas_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x8); + hw_caps->camera_capability = reg_value; + + CAM_DBG(CAM_FD, "Family %d, version %d.%d.%d, cpas %d.%d.%d, cap 0x%x", + hw_caps->camera_family, hw_caps->camera_version.major, + hw_caps->camera_version.minor, hw_caps->camera_version.incr, + hw_caps->cpas_version.major, hw_caps->cpas_version.minor, + hw_caps->cpas_version.incr, hw_caps->camera_capability); + + soc_info->hw_version = CAM_CPAS_TITAN_NONE; + + if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 1) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V110; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V120; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (hw_caps->camera_version.incr == 5)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 1)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V120; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 3) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V130; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 5) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_150_V100; + } else if ((hw_caps->camera_version.major == 4) && + (hw_caps->camera_version.minor == 8) && + (hw_caps->camera_version.incr == 0)) { + soc_info->hw_version = CAM_CPAS_TITAN_480_V100; + } + + CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); + + return 0; +} + +static int cam_cpastop_setup_regbase_indices(struct cam_hw_soc_info *soc_info, + int32_t regbase_index[], int32_t num_reg_map) +{ + uint32_t index; + int rc; + + if (num_reg_map > CAM_CPAS_REG_MAX) { + CAM_ERR(CAM_CPAS, "invalid num_reg_map=%d", num_reg_map); + return -EINVAL; + } + + if (soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) { + CAM_ERR(CAM_CPAS, "invalid num_mem_block=%d", + soc_info->num_mem_block); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "cam_cpas_top", &index); + if ((rc == 0) && (index < num_reg_map)) { + regbase_index[CAM_CPAS_REG_CPASTOP] = index; + } else { + CAM_ERR(CAM_CPAS, "regbase not found for CPASTOP, rc=%d, %d %d", + rc, index, num_reg_map); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "cam_camnoc", &index); + if ((rc == 0) && (index < num_reg_map)) { + regbase_index[CAM_CPAS_REG_CAMNOC] = index; + } else { + CAM_ERR(CAM_CPAS, "regbase not found for CAMNOC, rc=%d, %d %d", + rc, index, num_reg_map); + return -EINVAL; + } + + return 0; +} + +static int cam_cpastop_handle_errlogger(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info, + struct cam_camnoc_irq_slave_err_data *slave_err) +{ + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + int err_code_index = 0; + + if (!camnoc_info->err_logger) { + CAM_ERR_RATE_LIMIT(CAM_CPAS, "Invalid err logger info"); + return -EINVAL; + } + + slave_err->mainctrl.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->mainctrl); + + slave_err->errvld.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errvld); + + slave_err->errlog0_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog0_low); + + slave_err->errlog0_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog0_high); + + slave_err->errlog1_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog1_low); + + slave_err->errlog1_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog1_high); + + slave_err->errlog2_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog2_low); + + slave_err->errlog2_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog2_high); + + slave_err->errlog3_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog3_low); + + slave_err->errlog3_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog3_high); + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "Possible memory configuration issue, fault at SMMU raised as CAMNOC SLAVE_IRQ"); + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "mainctrl[0x%x 0x%x] errvld[0x%x 0x%x] stall_en=%d, fault_en=%d, err_vld=%d", + camnoc_info->err_logger->mainctrl, + slave_err->mainctrl.value, + camnoc_info->err_logger->errvld, + slave_err->errvld.value, + slave_err->mainctrl.stall_en, + slave_err->mainctrl.fault_en, + slave_err->errvld.err_vld); + + err_code_index = slave_err->errlog0_low.err_code; + if (err_code_index > CAMNOC_SLAVE_MAX_ERR_CODE) + err_code_index = CAMNOC_SLAVE_MAX_ERR_CODE; + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "errlog0 low[0x%x 0x%x] high[0x%x 0x%x] loginfo_vld=%d, word_error=%d, non_secure=%d, device=%d, opc=%d, err_code=%d(%s) sizef=%d, addr_space=%d, len1=%d", + camnoc_info->err_logger->errlog0_low, + slave_err->errlog0_low.value, + camnoc_info->err_logger->errlog0_high, + slave_err->errlog0_high.value, + slave_err->errlog0_low.loginfo_vld, + slave_err->errlog0_low.word_error, + slave_err->errlog0_low.non_secure, + slave_err->errlog0_low.device, + slave_err->errlog0_low.opc, + slave_err->errlog0_low.err_code, + camnoc_salve_err_code[err_code_index], + slave_err->errlog0_low.sizef, + slave_err->errlog0_low.addr_space, + slave_err->errlog0_high.len1); + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "errlog1_low[0x%x 0x%x] errlog1_high[0x%x 0x%x] errlog2_low[0x%x 0x%x] errlog2_high[0x%x 0x%x] errlog3_low[0x%x 0x%x] errlog3_high[0x%x 0x%x]", + camnoc_info->err_logger->errlog1_low, + slave_err->errlog1_low.value, + camnoc_info->err_logger->errlog1_high, + slave_err->errlog1_high.value, + camnoc_info->err_logger->errlog2_low, + slave_err->errlog2_low.value, + camnoc_info->err_logger->errlog2_high, + slave_err->errlog2_high.value, + camnoc_info->err_logger->errlog3_low, + slave_err->errlog3_low.value, + camnoc_info->err_logger->errlog3_high, + slave_err->errlog3_high.value); + + return 0; +} + +static int cam_cpastop_handle_ubwc_enc_err(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info, int i, + struct cam_camnoc_irq_ubwc_enc_data *enc_err) +{ + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + + enc_err->encerr_status.value = + cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->irq_err[i].err_status.offset); + + /* Let clients handle the UBWC errors */ + CAM_DBG(CAM_CPAS, + "ubwc enc err [%d]: offset[0x%x] value[0x%x]", + i, camnoc_info->irq_err[i].err_status.offset, + enc_err->encerr_status.value); + + return 0; +} + +static int cam_cpastop_handle_ubwc_dec_err(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info, int i, + struct cam_camnoc_irq_ubwc_dec_data *dec_err) +{ + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + + dec_err->decerr_status.value = + cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->irq_err[i].err_status.offset); + + /* Let clients handle the UBWC errors */ + CAM_DBG(CAM_CPAS, + "ubwc dec err status [%d]: offset[0x%x] value[0x%x] thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d", + i, camnoc_info->irq_err[i].err_status.offset, + dec_err->decerr_status.value, + dec_err->decerr_status.thr_err, + dec_err->decerr_status.fcl_err, + dec_err->decerr_status.len_md_err, + dec_err->decerr_status.format_err); + + return 0; +} + +static int cam_cpastop_handle_ahb_timeout_err(struct cam_hw_info *cpas_hw, + struct cam_camnoc_irq_ahb_timeout_data *ahb_err) +{ + CAM_ERR_RATE_LIMIT(CAM_CPAS, "ahb timeout error"); + + return 0; +} + +static int cam_cpastop_disable_test_irq(struct cam_hw_info *cpas_hw) +{ + camnoc_info->irq_sbm->sbm_clear.value &= ~0x4; + camnoc_info->irq_sbm->sbm_enable.value &= ~0x100; + camnoc_info->irq_err[CAM_CAMNOC_HW_IRQ_CAMNOC_TEST].enable = false; + + return 0; +} + +static int cam_cpastop_reset_irq(struct cam_hw_info *cpas_hw) +{ + int i; + + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_sbm->sbm_clear); + for (i = 0; i < camnoc_info->irq_err_size; i++) { + if (camnoc_info->irq_err[i].enable) + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_err[i].err_clear); + } + + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_sbm->sbm_enable); + for (i = 0; i < camnoc_info->irq_err_size; i++) { + if (camnoc_info->irq_err[i].enable) + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_err[i].err_enable); + } + + return 0; +} + +static void cam_cpastop_notify_clients(struct cam_cpas *cpas_core, + struct cam_cpas_irq_data *irq_data) +{ + int i; + struct cam_cpas_client *cpas_client; + bool error_handled = false; + + CAM_DBG(CAM_CPAS, + "Notify CB : num_clients=%d, registered=%d, started=%d", + cpas_core->num_clients, cpas_core->registered_clients, + cpas_core->streamon_clients); + + for (i = 0; i < cpas_core->num_clients; i++) { + if (CAM_CPAS_CLIENT_STARTED(cpas_core, i)) { + cpas_client = cpas_core->cpas_client[i]; + if (cpas_client->data.cam_cpas_client_cb) { + CAM_DBG(CAM_CPAS, + "Calling client CB %d : %d", + i, irq_data->irq_type); + error_handled = + cpas_client->data.cam_cpas_client_cb( + cpas_client->data.client_handle, + cpas_client->data.userdata, + irq_data); + if (error_handled) + break; + } + } + } +} + +static void cam_cpastop_work(struct work_struct *work) +{ + struct cam_cpas_work_payload *payload; + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + struct cam_hw_soc_info *soc_info; + int i; + enum cam_camnoc_hw_irq_type irq_type; + struct cam_cpas_irq_data irq_data; + + payload = container_of(work, struct cam_cpas_work_payload, work); + if (!payload) { + CAM_ERR(CAM_CPAS, "NULL payload"); + return; + } + + cpas_hw = payload->hw; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + soc_info = &cpas_hw->soc_info; + + if (!atomic_inc_not_zero(&cpas_core->irq_count)) { + CAM_ERR(CAM_CPAS, "CPAS off"); + return; + } + + for (i = 0; i < camnoc_info->irq_err_size; i++) { + if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) && + (camnoc_info->irq_err[i].enable)) { + irq_type = camnoc_info->irq_err[i].irq_type; + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "Error occurred, type=%d", irq_type); + memset(&irq_data, 0x0, sizeof(irq_data)); + irq_data.irq_type = (enum cam_camnoc_irq_type)irq_type; + + switch (irq_type) { + case CAM_CAMNOC_HW_IRQ_SLAVE_ERROR: + cam_cpastop_handle_errlogger( + cpas_core, soc_info, + &irq_data.u.slave_err); + break; + case CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: + cam_cpastop_handle_ubwc_enc_err( + cpas_core, soc_info, i, + &irq_data.u.enc_err); + break; + case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR: + cam_cpastop_handle_ubwc_dec_err( + cpas_core, soc_info, i, + &irq_data.u.dec_err); + break; + case CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT: + cam_cpastop_handle_ahb_timeout_err( + cpas_hw, &irq_data.u.ahb_err); + break; + case CAM_CAMNOC_HW_IRQ_CAMNOC_TEST: + CAM_DBG(CAM_CPAS, "TEST IRQ"); + break; + default: + CAM_ERR(CAM_CPAS, "Invalid IRQ type"); + break; + } + + cam_cpastop_notify_clients(cpas_core, &irq_data); + + payload->irq_status &= + ~camnoc_info->irq_err[i].sbm_port; + } + } + atomic_dec(&cpas_core->irq_count); + wake_up(&cpas_core->irq_count_wq); + CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); + + if (payload->irq_status) + CAM_ERR(CAM_CPAS, "IRQ not handled irq_status=0x%x", + payload->irq_status); + + kfree(payload); +} + +static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data) +{ + struct cam_hw_info *cpas_hw = (struct cam_hw_info *)data; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + struct cam_cpas_work_payload *payload; + + if (!atomic_inc_not_zero(&cpas_core->irq_count)) { + CAM_ERR(CAM_CPAS, "CPAS off"); + return IRQ_HANDLED; + } + + payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC); + if (!payload) + goto done; + + payload->irq_status = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->irq_sbm->sbm_status.offset); + + CAM_DBG(CAM_CPAS, "IRQ callback, irq_status=0x%x", payload->irq_status); + + payload->hw = cpas_hw; + INIT_WORK((struct work_struct *)&payload->work, cam_cpastop_work); + + if (TEST_IRQ_ENABLE) + cam_cpastop_disable_test_irq(cpas_hw); + + cam_cpastop_reset_irq(cpas_hw); + + queue_work(cpas_core->work_queue, &payload->work); +done: + atomic_dec(&cpas_core->irq_count); + wake_up(&cpas_core->irq_count_wq); + + return IRQ_HANDLED; +} + +static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) +{ + int i; + + for (i = 0; i < camnoc_info->specific_size; i++) { + if (camnoc_info->specific[i].enable) { + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].priority_lut_low); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].priority_lut_high); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].urgency); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].danger_lut); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].safe_lut); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].ubwc_ctl); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].flag_out_set0_low); + } + } + + return 0; +} + +static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + int rc = 0; + struct cam_cpas_hw_errata_wa_list *errata_wa_list = + camnoc_info->errata_wa_list; + + if (!errata_wa_list) + return 0; + + if (errata_wa_list->camnoc_flush_slave_pending_trans.enable) { + struct cam_cpas_hw_errata_wa *errata_wa = + &errata_wa_list->camnoc_flush_slave_pending_trans; + + rc = cam_io_poll_value_wmask( + soc_info->reg_map[camnoc_index].mem_base + + errata_wa->data.reg_info.offset, + errata_wa->data.reg_info.value, + errata_wa->data.reg_info.mask, + CAM_CPAS_POLL_RETRY_CNT, + CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS); + if (rc) { + CAM_DBG(CAM_CPAS, + "camnoc flush slave pending trans failed"); + /* Do not return error, passthrough */ + rc = 0; + } + } + + return rc; +} + +static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + + CAM_DBG(CAM_CPAS, + "hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d", + soc_info->hw_version, + hw_caps->camera_version.major, + hw_caps->camera_version.minor, + hw_caps->camera_version.incr, + hw_caps->cpas_version.major, + hw_caps->cpas_version.minor, + hw_caps->cpas_version.incr); + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_170_V100: + camnoc_info = &cam170_cpas100_camnoc_info; + break; + case CAM_CPAS_TITAN_170_V110: + camnoc_info = &cam170_cpas110_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V100: + camnoc_info = &cam175_cpas100_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V101: + camnoc_info = &cam175_cpas101_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V120: + camnoc_info = &cam175_cpas120_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V130: + camnoc_info = &cam175_cpas130_camnoc_info; + break; + case CAM_CPAS_TITAN_150_V100: + camnoc_info = &cam150_cpas100_camnoc_info; + break; + case CAM_CPAS_TITAN_480_V100: + camnoc_info = &cam480_cpas100_camnoc_info; + break; + default: + CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d", + hw_caps->camera_version.major, + hw_caps->camera_version.minor, + hw_caps->camera_version.incr); + rc = -EINVAL; + break; + } + + return 0; +} + +int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops) +{ + if (!internal_ops) { + CAM_ERR(CAM_CPAS, "invalid NULL param"); + return -EINVAL; + } + + internal_ops->get_hw_info = cam_cpastop_get_hw_info; + internal_ops->init_hw_version = cam_cpastop_init_hw_version; + internal_ops->handle_irq = cam_cpastop_handle_irq; + internal_ops->setup_regbase = cam_cpastop_setup_regbase_indices; + internal_ops->power_on = cam_cpastop_poweron; + internal_ops->power_off = cam_cpastop_poweroff; + + return 0; +} diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h new file mode 100644 index 000000000000..8a8c61a21914 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPASTOP_HW_H_ +#define _CAM_CPASTOP_HW_H_ + +#include "cam_cpas_api.h" +#include "cam_cpas_hw.h" + +/** + * enum cam_camnoc_hw_irq_type - Enum for camnoc error types + * + * @CAM_CAMNOC_HW_IRQ_SLAVE_ERROR: Each slave port in CAMNOC (3 QSB ports and + * 1 QHB port) has an error logger. The error + * observed at any slave port is logged into + * the error logger register and an IRQ is + * triggered + * @CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error + * detected in the IFE0 UBWC + * encoder instance + * @CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error + * detected in the IFE1 or IFE3 + * UBWC encoder instance + * @CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR: Triggered if any error + * detected in the IPE/BPS + * UBWC decoder instance + * @CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: Triggered if any error + * detected in the IPE/BPS UBWC + * encoder instance + * @CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR: Triggered if any UBWC error + * is detected in IFE0 write path + * @CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR: Triggered if any UBWC error + * is detected in IFE1 write path + * @CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT : Triggered when the QHS_ICP + * slave times out after 4000 + * AHB cycles + * @CAM_CAMNOC_HW_IRQ_RESERVED1 : Reserved + * @CAM_CAMNOC_HW_IRQ_RESERVED2 : Reserved + * @CAM_CAMNOC_HW_IRQ_CAMNOC_TEST : To test the IRQ logic + */ +enum cam_camnoc_hw_irq_type { + CAM_CAMNOC_HW_IRQ_SLAVE_ERROR = + CAM_CAMNOC_IRQ_SLAVE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR = + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT = + CAM_CAMNOC_IRQ_AHB_TIMEOUT, + CAM_CAMNOC_HW_IRQ_RESERVED1, + CAM_CAMNOC_HW_IRQ_RESERVED2, + CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, +}; + +/** + * enum cam_camnoc_port_type - Enum for different camnoc hw ports. All CAMNOC + * settings like QoS, LUT mappings need to be configured for + * each of these ports. + * + * @CAM_CAMNOC_CDM: Indicates CDM HW connection to camnoc + * @CAM_CAMNOC_IFE02: Indicates IFE0, IFE2 HW connection to camnoc + * @CAM_CAMNOC_IFE13: Indicates IFE1, IFE3 HW connection to camnoc + * @CAM_CAMNOC_IFE_LINEAR: Indicates linear data from all IFEs to cammnoc + * @CAM_CAMNOC_IFE_UBWC_STATS: Indicates ubwc+stats from all IFEs to cammnoc + * @CAM_CAMNOC_IFE_RDI_WR: Indicates RDI write data from all IFEs to cammnoc + * @CAM_CAMNOC_IFE_RDI_RD: Indicates RDI read data from all IFEs to cammnoc + * @CAM_CAMNOC_IFE0123_RDI_WRITE: RDI write only for all IFEx + * @CAM_CAMNOC_IFE0_NRDI_WRITE: IFE0 non-RDI write + * @CAM_CAMNOC_IFE01_RDI_READ: IFE0/1 RDI READ + * @CAM_CAMNOC_IFE1_NRDI_WRITE: IFE1 non-RDI write + * @CAM_CAMNOC_IPE_BPS_LRME_READ: Indicates IPE, BPS, LRME Read HW + * connection to camnoc + * @CAM_CAMNOC_IPE_BPS_LRME_WRITE: Indicates IPE, BPS, LRME Write HW + * connection to camnoc + * @CAM_CAMNOC_IPE_VID_DISP_WRITE: Indicates IPE's VID/DISP Wrire HW + * connection to camnoc + * @CAM_CAMNOC_IPE0_RD: Indicates IPE's Read0 HW connection to camnoc + * @CAM_CAMNOC_IPE1_BPS_RD: Indicates IPE's Read1 + BPS Read HW connection + * to camnoc + * @CAM_CAMNOC_IPE_BPS_WR: Indicates IPE+BPS Write HW connection to camnoc + * @CAM_CAMNOC_JPEG: Indicates JPEG HW connection to camnoc + * @CAM_CAMNOC_FD: Indicates FD HW connection to camnoc + * @CAM_CAMNOC_ICP: Indicates ICP HW connection to camnoc + */ +enum cam_camnoc_port_type { + CAM_CAMNOC_CDM, + CAM_CAMNOC_IFE02, + CAM_CAMNOC_IFE13, + CAM_CAMNOC_IFE_LINEAR, + CAM_CAMNOC_IFE_UBWC_STATS, + CAM_CAMNOC_IFE_RDI_WR, + CAM_CAMNOC_IFE_RDI_RD, + CAM_CAMNOC_IFE0123_RDI_WRITE, + CAM_CAMNOC_IFE0_NRDI_WRITE, + CAM_CAMNOC_IFE01_RDI_READ, + CAM_CAMNOC_IFE1_NRDI_WRITE, + CAM_CAMNOC_IPE_BPS_LRME_READ, + CAM_CAMNOC_IPE_BPS_LRME_WRITE, + CAM_CAMNOC_IPE_VID_DISP_WRITE, + CAM_CAMNOC_IPE0_RD, + CAM_CAMNOC_IPE1_BPS_RD, + CAM_CAMNOC_IPE_BPS_WR, + CAM_CAMNOC_JPEG, + CAM_CAMNOC_FD, + CAM_CAMNOC_ICP, +}; + +/** + * struct cam_camnoc_specific : CPAS camnoc specific settings + * + * @port_type: Port type + * @enable: Whether to enable settings for this connection + * @priority_lut_low: Priority Low LUT mapping for this connection + * @priority_lut_high: Priority High LUT mapping for this connection + * @urgency: Urgency (QoS) settings for this connection + * @danger_lut: Danger LUT mapping for this connection + * @safe_lut: Safe LUT mapping for this connection + * @ubwc_ctl: UBWC control settings for this connection + * + */ +struct cam_camnoc_specific { + enum cam_camnoc_port_type port_type; + bool enable; + struct cam_cpas_reg priority_lut_low; + struct cam_cpas_reg priority_lut_high; + struct cam_cpas_reg urgency; + struct cam_cpas_reg danger_lut; + struct cam_cpas_reg safe_lut; + struct cam_cpas_reg ubwc_ctl; + struct cam_cpas_reg flag_out_set0_low; +}; + +/** + * struct cam_camnoc_irq_sbm : Sideband manager settings for all CAMNOC IRQs + * + * @sbm_enable: SBM settings for IRQ enable + * @sbm_status: SBM settings for IRQ status + * @sbm_clear: SBM settings for IRQ clear + * + */ +struct cam_camnoc_irq_sbm { + struct cam_cpas_reg sbm_enable; + struct cam_cpas_reg sbm_status; + struct cam_cpas_reg sbm_clear; +}; + +/** + * struct cam_camnoc_irq_err : Error settings specific to each CAMNOC IRQ + * + * @irq_type: Type of IRQ + * @enable: Whether to enable error settings for this IRQ + * @sbm_port: Corresponding SBM port for this IRQ + * @err_enable: Error enable settings for this IRQ + * @err_status: Error status settings for this IRQ + * @err_clear: Error clear settings for this IRQ + * + */ +struct cam_camnoc_irq_err { + enum cam_camnoc_hw_irq_type irq_type; + bool enable; + uint32_t sbm_port; + struct cam_cpas_reg err_enable; + struct cam_cpas_reg err_status; + struct cam_cpas_reg err_clear; +}; + +/** + * struct cam_cpas_hw_errata_wa : Struct for HW errata workaround info + * + * @enable: Whether to enable this errata workround + * @data: HW Errata workaround data + * + */ +struct cam_cpas_hw_errata_wa { + bool enable; + union { + struct cam_cpas_reg reg_info; + } data; +}; + +/** + * struct cam_cpas_hw_errata_wa_list : List of HW Errata workaround info + * + * @camnoc_flush_slave_pending_trans: Errata workaround info for flushing + * camnoc slave pending transactions before turning off CPAS_TOP gdsc + * + */ +struct cam_cpas_hw_errata_wa_list { + struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans; +}; + +/** + * struct cam_camnoc_err_logger_info : CAMNOC error logger register offsets + * + * @mainctrl: Register offset for mainctrl + * @errvld: Register offset for errvld + * @errlog0_low: Register offset for errlog0_low + * @errlog0_high: Register offset for errlog0_high + * @errlog1_low: Register offset for errlog1_low + * @errlog1_high: Register offset for errlog1_high + * @errlog2_low: Register offset for errlog2_low + * @errlog2_high: Register offset for errlog2_high + * @errlog3_low: Register offset for errlog3_low + * @errlog3_high: Register offset for errlog3_high + * + */ +struct cam_camnoc_err_logger_info { + uint32_t mainctrl; + uint32_t errvld; + uint32_t errlog0_low; + uint32_t errlog0_high; + uint32_t errlog1_low; + uint32_t errlog1_high; + uint32_t errlog2_low; + uint32_t errlog2_high; + uint32_t errlog3_low; + uint32_t errlog3_high; +}; + +/** + * struct cam_camnoc_info : Overall CAMNOC settings info + * + * @specific: Pointer to CAMNOC SPECIFICTONTTPTR settings + * @specific_size: Array size of SPECIFICTONTTPTR settings + * @irq_sbm: Pointer to CAMNOC IRQ SBM settings + * @irq_err: Pointer to CAMNOC IRQ Error settings + * @irq_err_size: Array size of IRQ Error settings + * @err_logger: Pointer to CAMNOC IRQ Error logger read registers + * @errata_wa_list: HW Errata workaround info + * + */ +struct cam_camnoc_info { + struct cam_camnoc_specific *specific; + int specific_size; + struct cam_camnoc_irq_sbm *irq_sbm; + struct cam_camnoc_irq_err *irq_err; + int irq_err_size; + struct cam_camnoc_err_logger_info *err_logger; + struct cam_cpas_hw_errata_wa_list *errata_wa_list; +}; + +/** + * struct cam_cpas_work_payload : Struct for cpas work payload data + * + * @hw: Pointer to HW info + * @irq_status: IRQ status value + * @irq_data: IRQ data + * @work: Work handle + * + */ +struct cam_cpas_work_payload { + struct cam_hw_info *hw; + uint32_t irq_status; + uint32_t irq_data; + struct work_struct work; +}; + +#endif /* _CAM_CPASTOP_HW_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop100.h b/drivers/cam_cpas/cpas_top/cpastop100.h new file mode 100644 index 000000000000..2f444710e9f4 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop100.h @@ -0,0 +1,531 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP100_H_ +#define _CPASTOP100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x3, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x3, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = false, + } +}; + +static struct cam_camnoc_err_logger_info cam170_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam170_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = true, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +struct cam_camnoc_info cam170_cpas100_camnoc_info = { + .specific = &cam_cpas100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas100_camnoc_specific) / + sizeof(cam_cpas100_camnoc_specific[0]), + .irq_sbm = &cam_cpas100_irq_sbm, + .irq_err = &cam_cpas100_irq_err[0], + .irq_err_size = sizeof(cam_cpas100_irq_err) / + sizeof(cam_cpas100_irq_err[0]), + .err_logger = &cam170_cpas100_err_logger_offsets, + .errata_wa_list = &cam170_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP100_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v150_100.h b/drivers/cam_cpas/cpas_top/cpastop_v150_100.h new file mode 100644 index 000000000000..df9711e74379 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v150_100.h @@ -0,0 +1,530 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V150_100_H_ +#define _CPASTOP_V150_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v150_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v150_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v150_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0x5, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam150_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam150_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam150_cpas100_camnoc_info = { + .specific = &cam_cpas_v150_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v150_100_camnoc_specific) / + sizeof(cam_cpas_v150_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v150_100_irq_sbm, + .irq_err = &cam_cpas_v150_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v150_100_irq_err) / + sizeof(cam_cpas_v150_100_irq_err[0]), + .err_logger = &cam150_cpas100_err_logger_offsets, + .errata_wa_list = &cam150_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V150_100_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/cam_cpas/cpas_top/cpastop_v170_110.h new file mode 100644 index 000000000000..788f571a3a13 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v170_110.h @@ -0,0 +1,538 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V170_110_H_ +#define _CPASTOP_V170_110_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas110_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas110_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas110_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam170_cpas110_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam170_cpas110_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam170_cpas110_camnoc_info = { + .specific = &cam_cpas110_camnoc_specific[0], + .specific_size = sizeof(cam_cpas110_camnoc_specific) / + sizeof(cam_cpas110_camnoc_specific[0]), + .irq_sbm = &cam_cpas110_irq_sbm, + .irq_err = &cam_cpas110_irq_err[0], + .irq_err_size = sizeof(cam_cpas110_irq_err) / + sizeof(cam_cpas110_irq_err[0]), + .err_logger = &cam170_cpas110_err_logger_offsets, + .errata_wa_list = &cam170_cpas110_errata_wa_list, +}; + +#endif /* _CPASTOP_V170_110_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_100.h b/drivers/cam_cpas/cpas_top/cpastop_v175_100.h new file mode 100644 index 000000000000..aae26b5a9178 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_100.h @@ -0,0 +1,558 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_100_H_ +#define _CPASTOP_V175_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas100_camnoc_info = { + .specific = &cam_cpas_v175_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v175_100_camnoc_specific) / + sizeof(cam_cpas_v175_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v175_100_irq_sbm, + .irq_err = &cam_cpas_v175_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v175_100_irq_err) / + sizeof(cam_cpas_v175_100_irq_err[0]), + .err_logger = &cam175_cpas100_err_logger_offsets, + .errata_wa_list = &cam175_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_100_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_101.h b/drivers/cam_cpas/cpas_top/cpastop_v175_101.h new file mode 100644 index 000000000000..7ec9bec36fd1 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_101.h @@ -0,0 +1,558 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_101_H_ +#define _CPASTOP_V175_101_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_101_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_101_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_101_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas101_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas101_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas101_camnoc_info = { + .specific = &cam_cpas_v175_101_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v175_101_camnoc_specific) / + sizeof(cam_cpas_v175_101_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v175_101_irq_sbm, + .irq_err = &cam_cpas_v175_101_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v175_101_irq_err) / + sizeof(cam_cpas_v175_101_irq_err[0]), + .err_logger = &cam175_cpas101_err_logger_offsets, + .errata_wa_list = &cam175_cpas101_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_101_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_120.h b/drivers/cam_cpas/cpas_top/cpastop_v175_120.h new file mode 100644 index 000000000000..5844c38ae52c --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_120.h @@ -0,0 +1,760 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_120_H_ +#define _CPASTOP_V175_120_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_120_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2240, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2248, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2280, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_120_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x4F08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x4F10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x4F18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3BA0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3B90, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x3B98, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x55a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x5590, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x5598, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2F20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2F10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2F18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2Ba0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2B90, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2B98, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_120_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4230, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4234, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* cdm_main_SpecificToNttpTr_Urgency_Low */ + .offset = 0x4238, + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4240, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4248, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0123_RDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_LOW */ + .offset = 0x3630, + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_HIGH */ + .offset = 0x3634, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3638, /* SPECIFIC_IFE0123_URGENCY_LOW */ + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3640, /* SPECIFIC_IFE0123_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3648, /* SPECIFIC_IFE0123_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A30, /* SPECIFIC_IFE0_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A34, /* SPECIFIC_IFE0_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3A38, /* SPECIFIC_IFE0_URGENCY_LOW */ + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A40, /* SPECIFIC_IFE0_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A48, /* SPECIFIC_IFE0_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3B88, /* SPECIFIC_IFE0_ENCCTL_LOW */ + .value = 1, + }, + }, + { + /* IFE0/1 RDI READ PATH */ + .port_type = CAM_CAMNOC_IFE01_RDI_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3230, /* SPECIFIC_IFE1_PRIORITYLUT_LOW */ + .value = 0x44443333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3234, /* SPECIFIC_IFE1_PRIORITYLUT_HIGH */ + .value = 0x66665555, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3238, /* SPECIFIC_IFE1_URGENCY_LOW */ + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_MASK */ + .mask = 0x7, + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3240, /* SPECIFIC_IFE1_DANGERLUT_LOW */ + .value = 0x00000000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3248, /* SPECIFIC_IFE1_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE1_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5430, /* SPECIFIC_IFE1_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE1_WR_PRIORITYLUT_HIGH */ + .offset = 0x5434, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x5438, /* SPECIFIC_IFE1_WR_URGENCY_LOW */ + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5440, /* SPECIFIC_IFE1_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5448, /* SPECIFIC_IFE1_WR_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5588, /* SPECIFIC_IFE1_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2E38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2F08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A30, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A34, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2A38, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A40, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_VID_DISP_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_LOW */ + .offset = 0x5E30, + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_HIGH */ + .offset = 0x5E34, + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW */ + .offset = 0x5E38, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_MASK */ + .mask = 0x70, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC__IPE_VID_DISP_DANGERLUT_LOW */ + .offset = 0x5E40, + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_SAFELUT_LOW */ + .offset = 0x5E48, + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5F88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2630, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2634, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2638, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2640, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2648, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E30, /* SPECIFIC_FD_PRIORITYLUT_LOW */ + .value = 0x44444444, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E34, /* SPECIFIC_FD_PRIORITYLUT_HIGH */ + .value = 0x44444444, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E38, /* SPECIFIC_FD_URGENCY_LOW */ + .value = 0x44, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E40, /* SPECIFIC_FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E48, /* SPECIFIC_FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + + }, + { + /*SidebandManager_main_SidebandManager_FlagOutSet0_Low*/ + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2288, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas120_err_logger_offsets = { + .mainctrl = 0x4F08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x4F10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x4F20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x4F24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x4F28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x4F2c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x4F30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x4F34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x4F38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x4F3c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas120_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2300, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas120_camnoc_info = { + .specific = &cam_cpas_v175_120_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v175_120_camnoc_specific), + .irq_sbm = &cam_cpas_v175_120_irq_sbm, + .irq_err = &cam_cpas_v175_120_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v175_120_irq_err), + .err_logger = &cam175_cpas120_err_logger_offsets, + .errata_wa_list = &cam175_cpas120_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_120_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h new file mode 100644 index 000000000000..fe6e274c5668 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h @@ -0,0 +1,760 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_130_H_ +#define _CPASTOP_V175_130_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_130_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2240, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2248, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2280, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_130_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x4F08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x4F10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x4F18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3BA0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3B90, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x3B98, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x55a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x5590, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x5598, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2F20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2F10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2F18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2Ba0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2B90, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2B98, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_130_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4230, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4234, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* cdm_main_SpecificToNttpTr_Urgency_Low */ + .offset = 0x4238, + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4240, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4248, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0123_RDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_LOW */ + .offset = 0x3630, + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_HIGH */ + .offset = 0x3634, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3638, /* SPECIFIC_IFE0123_URGENCY_LOW */ + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3640, /* SPECIFIC_IFE0123_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3648, /* SPECIFIC_IFE0123_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A30, /* SPECIFIC_IFE0_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A34, /* SPECIFIC_IFE0_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3A38, /* SPECIFIC_IFE0_URGENCY_LOW */ + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A40, /* SPECIFIC_IFE0_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A48, /* SPECIFIC_IFE0_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3B88, /* SPECIFIC_IFE0_ENCCTL_LOW */ + .value = 1, + }, + }, + { + /* IFE0/1 RDI READ PATH */ + .port_type = CAM_CAMNOC_IFE01_RDI_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3230, /* SPECIFIC_IFE1_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3234, /* SPECIFIC_IFE1_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3238, /* SPECIFIC_IFE1_URGENCY_LOW */ + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_MASK */ + .mask = 0x7, + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3240, /* SPECIFIC_IFE1_DANGERLUT_LOW */ + .value = 0x00000000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3248, /* SPECIFIC_IFE1_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE1_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5430, /* SPECIFIC_IFE1_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE1_WR_PRIORITYLUT_HIGH */ + .offset = 0x5434, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x5438, /* SPECIFIC_IFE1_WR_URGENCY_LOW */ + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5440, /* SPECIFIC_IFE1_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5448, /* SPECIFIC_IFE1_WR_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5588, /* SPECIFIC_IFE1_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2E38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2F08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A30, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A34, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2A38, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A40, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_VID_DISP_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_LOW */ + .offset = 0x5E30, + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_HIGH */ + .offset = 0x5E34, + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW */ + .offset = 0x5E38, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_MASK */ + .mask = 0x70, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC__IPE_VID_DISP_DANGERLUT_LOW */ + .offset = 0x5E40, + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_SAFELUT_LOW */ + .offset = 0x5E48, + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5F88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2630, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2634, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2638, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2640, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2648, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E30, /* SPECIFIC_FD_PRIORITYLUT_LOW */ + .value = 0x44444444, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E34, /* SPECIFIC_FD_PRIORITYLUT_HIGH */ + .value = 0x44444444, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E38, /* SPECIFIC_FD_URGENCY_LOW */ + .value = 0x44, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E40, /* SPECIFIC_FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E48, /* SPECIFIC_FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + + }, + { + /*SidebandManager_main_SidebandManager_FlagOutSet0_Low*/ + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2288, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas130_err_logger_offsets = { + .mainctrl = 0x4F08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x4F10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x4F20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x4F24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x4F28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x4F2c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x4F30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x4F34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x4F38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x4F3c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas130_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2300, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas130_camnoc_info = { + .specific = &cam_cpas_v175_130_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v175_130_camnoc_specific), + .irq_sbm = &cam_cpas_v175_130_irq_sbm, + .irq_err = &cam_cpas_v175_130_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v175_130_irq_err), + .err_logger = &cam175_cpas130_err_logger_offsets, + .errata_wa_list = &cam175_cpas130_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_130_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h new file mode 100644 index 000000000000..d4782d7df110 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -0,0 +1,743 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V480_100_H_ +#define _CPASTOP_V480_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v480_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = false, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v480_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v480_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* CDM_URGENCY_LOW */ + .mask = 0x7, /* CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x630, /* FD_PRIORITYLUT_LOW */ + .value = 0x44444444, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x634, /* FD_PRIORITYLUT_HIGH */ + .value = 0x44444444, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x638, /* FD_URGENCY_LOW */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x640, /* FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x648, /* FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_LINEAR, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xA30, /* IFE_LINEAR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xA34, /* IFE_LINEAR_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xA38, /* IFE_LINEAR_URGENCY_LOW */ + /* IFE_LINEAR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* IFE_LINEAR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0xA40, /* IFE_LINEAR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0xA48, /* IFE_LINEAR_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_RDI_RD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* IFE_RDI_RD_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* IFE_RDI_RD_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* IFE_RDI_RD_URGENCY_LOW */ + /* IFE_RDI_RD_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* IFE_RDI_RD_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1040, /* IFE_RDI_RD_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1048, /* IFE_RDI_RD_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_RDI_WR, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* IFE_RDI_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* IFE_RDI_WR_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1438, /* IFE_RDI_WR_URGENCY_LOW */ + /* IFE_RDI_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* IFE_RDI_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1440, /* IFE_RDI_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1448, /* IFE_RDI_WR_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_UBWC_STATS, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1A30, /* IFE_UBWC_STATS_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1A34, /* IFE_UBWC_STATS_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1A38, /* IFE_UBWC_STATS_URGENCY_LOW */ + /* IFE_UBWC_STATS_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* IFE_UBWC_STATS_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1A40, /* IFE_UBWC_STATS_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1A48, /* IFE_UBWC_STATS_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1B88, /* IFE_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE0_RD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E30, /* IPE0_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E34, /* IPE0_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1E38, /* IPE0_RD_URGENCY_LOW */ + /* IPE0_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* IPE0_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E40, /* IPE0_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E48, /* IPE0_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1F08, /* IPE0_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE1_BPS_RD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2430, /* IPE1_BPS_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2434, /* IPE1_BPS_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2438, /* IPE1_BPS_RD_URGENCY_LOW */ + /* IPE1_BPS_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* IPE1_BPS_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2440, /* IPE1_BPS_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2448, /* IPE1_BPS_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2508, /* IPE1_BPS_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_WR, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2830, /* IPE_BPS_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2834, /* IPE_BPS_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2838, /* IPE_BPS_WR_URGENCY_LOW */ + /* IPE_BPS_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* IPE_BPS_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2840, /* IPE_BPS_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2848, /* IPE_BPS_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2988, /* IPE_BPS_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E38, /* JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam480_cpas100_err_logger_offsets = { + .mainctrl = 0x7008, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x7010, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x7020, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x7024, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x7028, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x702c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x7030, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x7034, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x7038, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x703c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam480_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam480_cpas100_camnoc_info = { + .specific = &cam_cpas_v480_100_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v480_100_camnoc_specific), + .irq_sbm = &cam_cpas_v480_100_irq_sbm, + .irq_err = &cam_cpas_v480_100_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v480_100_irq_err), + .err_logger = &cam480_cpas100_err_logger_offsets, + .errata_wa_list = &cam480_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V480_100_H_ */ diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h new file mode 100644 index 000000000000..932f4b2abf88 --- /dev/null +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -0,0 +1,543 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_API_H_ +#define _CAM_CPAS_API_H_ + +#include +#include + +#include +#include "cam_soc_util.h" + +#define CAM_HW_IDENTIFIER_LENGTH 128 + +/* Default AXI Bandwidth vote */ +#define CAM_CPAS_DEFAULT_AXI_BW 1024 + +#define CAM_CPAS_MAX_PATHS_PER_CLIENT 15 +#define CAM_CPAS_API_PATH_DATA_STD_START 512 + +/** + * enum cam_cpas_reg_base - Enum for register base identifier. These + * are the identifiers used in generic register + * write/read APIs provided by cpas driver. + */ +enum cam_cpas_reg_base { + CAM_CPAS_REG_CPASTOP, + CAM_CPAS_REG_CAMNOC, + CAM_CPAS_REG_CAMSS, + CAM_CPAS_REG_MAX +}; + +/** + * enum cam_cpas_hw_version - Enum for Titan CPAS HW Versions + */ +enum cam_cpas_hw_version { + CAM_CPAS_TITAN_NONE = 0, + CAM_CPAS_TITAN_150_V100 = 0x150100, + CAM_CPAS_TITAN_170_V100 = 0x170100, + CAM_CPAS_TITAN_170_V110 = 0x170110, + CAM_CPAS_TITAN_170_V120 = 0x170120, + CAM_CPAS_TITAN_175_V100 = 0x175100, + CAM_CPAS_TITAN_175_V101 = 0x175101, + CAM_CPAS_TITAN_175_V120 = 0x175120, + CAM_CPAS_TITAN_175_V130 = 0x175130, + CAM_CPAS_TITAN_480_V100 = 0x480100, + CAM_CPAS_TITAN_MAX +}; + +/** + * enum cam_camnoc_irq_type - Enum for camnoc irq types + * + * @CAM_CAMNOC_IRQ_SLAVE_ERROR: Each slave port in CAMNOC (3 QSB ports and + * 1 QHB port) has an error logger. The error + * observed at any slave port is logged into + * the error logger register and an IRQ is + * triggered + * @CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE0 UBWC encoder instance + * @CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE1 or IFE3 UBWC encoder + * instance + * @CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE0 UBWC encoder instance + * @CAM_CAMNOC_IRQ_IFE1_WR_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE1 UBWC encoder + * instance + * @CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR: Triggered if any error detected + * in the IPE/BPS UBWC decoder + * instance + * @CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: Triggered if any error detected + * in the IPE/BPS UBWC encoder + * instance + * @CAM_CAMNOC_IRQ_AHB_TIMEOUT : Triggered when the QHS_ICP slave + * times out after 4000 AHB cycles + */ +enum cam_camnoc_irq_type { + CAM_CAMNOC_IRQ_SLAVE_ERROR, + CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_AHB_TIMEOUT, +}; + +/** + * struct cam_camnoc_irq_slave_err_data : Data for Slave error. + * + * @mainctrl : Err logger mainctrl info + * @errvld : Err logger errvld info + * @errlog0_low : Err logger errlog0_low info + * @errlog0_high : Err logger errlog0_high info + * @errlog1_low : Err logger errlog1_low info + * @errlog1_high : Err logger errlog1_high info + * @errlog2_low : Err logger errlog2_low info + * @errlog2_high : Err logger errlog2_high info + * @errlog3_low : Err logger errlog3_low info + * @errlog3_high : Err logger errlog3_high info + * + */ +struct cam_camnoc_irq_slave_err_data { + union { + struct { + uint32_t stall_en : 1; /* bit 0 */ + uint32_t fault_en : 1; /* bit 1 */ + uint32_t rsv : 30; /* bits 2-31 */ + }; + uint32_t value; + } mainctrl; + union { + struct { + uint32_t err_vld : 1; /* bit 0 */ + uint32_t rsv : 31; /* bits 1-31 */ + }; + uint32_t value; + } errvld; + union { + struct { + uint32_t loginfo_vld : 1; /* bit 0 */ + uint32_t word_error : 1; /* bit 1 */ + uint32_t non_secure : 1; /* bit 2 */ + uint32_t device : 1; /* bit 3 */ + uint32_t opc : 3; /* bits 4 - 6 */ + uint32_t rsv0 : 1; /* bit 7 */ + uint32_t err_code : 3; /* bits 8 - 10 */ + uint32_t sizef : 3; /* bits 11 - 13 */ + uint32_t rsv1 : 2; /* bits 14 - 15 */ + uint32_t addr_space : 6; /* bits 16 - 21 */ + uint32_t rsv2 : 10; /* bits 22 - 31 */ + }; + uint32_t value; + } errlog0_low; + union { + struct { + uint32_t len1 : 10; /* bits 0 - 9 */ + uint32_t rsv : 22; /* bits 10 - 31 */ + }; + uint32_t value; + } errlog0_high; + union { + struct { + uint32_t path : 16; /* bits 0 - 15 */ + uint32_t rsv : 16; /* bits 16 - 31 */ + }; + uint32_t value; + } errlog1_low; + union { + struct { + uint32_t extid : 18; /* bits 0 - 17 */ + uint32_t rsv : 14; /* bits 18 - 31 */ + }; + uint32_t value; + } errlog1_high; + union { + struct { + uint32_t errlog2_lsb : 32; /* bits 0 - 31 */ + }; + uint32_t value; + } errlog2_low; + union { + struct { + uint32_t errlog2_msb : 16; /* bits 0 - 16 */ + uint32_t rsv : 16; /* bits 16 - 31 */ + }; + uint32_t value; + } errlog2_high; + union { + struct { + uint32_t errlog3_lsb : 32; /* bits 0 - 31 */ + }; + uint32_t value; + } errlog3_low; + union { + struct { + uint32_t errlog3_msb : 32; /* bits 0 - 31 */ + }; + uint32_t value; + } errlog3_high; +}; + +/** + * struct cam_camnoc_irq_ubwc_enc_data : Data for UBWC Encode error. + * + * @encerr_status : Encode error status + * + */ +struct cam_camnoc_irq_ubwc_enc_data { + union { + struct { + uint32_t encerrstatus : 3; /* bits 0 - 2 */ + uint32_t rsv : 29; /* bits 3 - 31 */ + }; + uint32_t value; + } encerr_status; +}; + +/** + * struct cam_camnoc_irq_ubwc_dec_data : Data for UBWC Decode error. + * + * @decerr_status : Decoder error status + * @thr_err : Set to 1 if + * At least one of the bflc_len fields in the bit steam exceeds + * its threshold value. This error is possible only for + * RGBA1010102, TP10, and RGB565 formats + * @fcl_err : Set to 1 if + * Fast clear with a legal non-RGB format + * @len_md_err : Set to 1 if + * The calculated burst length does not match burst length + * specified by the metadata value + * @format_err : Set to 1 if + * Illegal format + * 1. bad format :2,3,6 + * 2. For 32B MAL, metadata=6 + * 3. For 32B MAL RGB565, Metadata != 0,1,7 + * 4. For 64B MAL RGB565, metadata[3:1] == 1,2 + * + */ +struct cam_camnoc_irq_ubwc_dec_data { + union { + struct { + uint32_t thr_err : 1; /* bit 0 */ + uint32_t fcl_err : 1; /* bit 1 */ + uint32_t len_md_err : 1; /* bit 2 */ + uint32_t format_err : 1; /* bit 3 */ + uint32_t rsv : 28; /* bits 4 - 31 */ + }; + uint32_t value; + } decerr_status; +}; + +struct cam_camnoc_irq_ahb_timeout_data { + uint32_t data; +}; + +/** + * struct cam_cpas_irq_data : CAMNOC IRQ data + * + * @irq_type : To identify the type of IRQ + * @u : Union of irq err data information + * @slave_err : Data for Slave error. + * Valid if type is CAM_CAMNOC_IRQ_SLAVE_ERROR + * @enc_err : Data for UBWC Encode error. + * Valid if type is one of below: + * CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR + * CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR + * CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR + * @dec_err : Data for UBWC Decode error. + * Valid if type is CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR + * @ahb_err : Data for Slave error. + * Valid if type is CAM_CAMNOC_IRQ_AHB_TIMEOUT + * + */ +struct cam_cpas_irq_data { + enum cam_camnoc_irq_type irq_type; + union { + struct cam_camnoc_irq_slave_err_data slave_err; + struct cam_camnoc_irq_ubwc_enc_data enc_err; + struct cam_camnoc_irq_ubwc_dec_data dec_err; + struct cam_camnoc_irq_ahb_timeout_data ahb_err; + } u; +}; + +/** + * struct cam_cpas_register_params : Register params for cpas client + * + * @identifier : Input identifier string which is the device label + * from dt like vfe, ife, jpeg etc + * @cell_index : Input integer identifier pointing to the cell index + * from dt of the device. This can be used to form a + * unique string with @identifier like vfe0, ife1, + * jpeg0, etc + * @dev : device handle + * @userdata : Input private data which will be passed as + * an argument while callback. + * @cam_cpas_callback : Input callback pointer for triggering the + * callbacks from CPAS driver. + * @client_handle : CPAS client handle + * @userdata : User data given at the time of register + * @event_type : event type + * @event_data : event data + * @client_handle : Output Unique handle generated for this register + * + */ +struct cam_cpas_register_params { + char identifier[CAM_HW_IDENTIFIER_LENGTH]; + uint32_t cell_index; + struct device *dev; + void *userdata; + bool (*cam_cpas_client_cb)( + uint32_t client_handle, + void *userdata, + struct cam_cpas_irq_data *irq_data); + uint32_t client_handle; +}; + +/** + * enum cam_vote_type - Enum for voting type + * + * @CAM_VOTE_ABSOLUTE : Absolute vote + * @CAM_VOTE_DYNAMIC : Dynamic vote + */ +enum cam_vote_type { + CAM_VOTE_ABSOLUTE, + CAM_VOTE_DYNAMIC, +}; + +/** + * struct cam_ahb_vote : AHB vote + * + * @type : AHB voting type. + * CAM_VOTE_ABSOLUTE : vote based on the value 'level' is set + * CAM_VOTE_DYNAMIC : vote calculated dynamically using 'freq' + * and 'dev' handle is set + * @level : AHB vote level + * @freq : AHB vote dynamic frequency + * + */ +struct cam_ahb_vote { + enum cam_vote_type type; + union { + enum cam_vote_level level; + unsigned long freq; + } vote; +}; + +/** + * struct cam_axi_vote : AXI vote + * + * @num_paths: Number of paths on which BW vote is sent to CPAS + * @axi_path: Per path BW vote info + * + */ +struct cam_axi_vote { + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_CPAS_MAX_PATHS_PER_CLIENT]; +}; + +/** + * cam_cpas_register_client() + * + * @brief: API to register cpas client + * + * @register_params: Input params to register as a client to CPAS + * + * @return 0 on success. + * + */ +int cam_cpas_register_client( + struct cam_cpas_register_params *register_params); + +/** + * cam_cpas_unregister_client() + * + * @brief: API to unregister cpas client + * + * @client_handle: Client handle to be unregistered + * + * @return 0 on success. + * + */ +int cam_cpas_unregister_client(uint32_t client_handle); + +/** + * cam_cpas_start() + * + * @brief: API to start cpas client hw. Clients have to vote for minimal + * bandwidth requirements for AHB, AXI. Use cam_cpas_update_ahb_vote + * to scale bandwidth after start. + * + * @client_handle: client cpas handle + * @ahb_vote : Pointer to ahb vote info + * @axi_vote : Pointer to axi bandwidth vote info + * + * If AXI vote is not applicable to a particular client, use the value exposed + * by CAM_CPAS_DEFAULT_AXI_BW as the default vote request. + * + * @return 0 on success. + * + */ +int cam_cpas_start( + uint32_t client_handle, + struct cam_ahb_vote *ahb_vote, + struct cam_axi_vote *axi_vote); + +/** + * cam_cpas_stop() + * + * @brief: API to stop cpas client hw. Bandwidth for AHB, AXI votes + * would be removed for this client on this call. Clients should not + * use cam_cpas_update_ahb_vote or cam_cpas_update_axi_vote + * to remove their bandwidth vote. + * + * @client_handle: client cpas handle + * + * @return 0 on success. + * + */ +int cam_cpas_stop(uint32_t client_handle); + +/** + * cam_cpas_update_ahb_vote() + * + * @brief: API to update AHB vote requirement. Use this function only + * between cam_cpas_start and cam_cpas_stop in case clients wants + * to scale to different vote level. Do not use this function to de-vote, + * removing client's vote is implicit on cam_cpas_stop + * + * @client_handle : Client cpas handle + * @ahb_vote : Pointer to ahb vote info + * + * @return 0 on success. + * + */ +int cam_cpas_update_ahb_vote( + uint32_t client_handle, + struct cam_ahb_vote *ahb_vote); + +/** + * cam_cpas_update_axi_vote() + * + * @brief: API to update AXI vote requirement. Use this function only + * between cam_cpas_start and cam_cpas_stop in case clients wants + * to scale to different vote level. Do not use this function to de-vote, + * removing client's vote is implicit on cam_cpas_stop + * + * @client_handle : Client cpas handle + * @axi_vote : Pointer to axi bandwidth vote info + * + * @return 0 on success. + * + */ +int cam_cpas_update_axi_vote( + uint32_t client_handle, + struct cam_axi_vote *axi_vote); + +/** + * cam_cpas_reg_write() + * + * @brief: API to write a register value in CPAS register space + * + * @client_handle : Client cpas handle + * @reg_base : Register base identifier + * @offset : Offset from the register base address + * @mb : Whether to do reg write with memory barrier + * @value : Value to be written in register + * + * @return 0 on success. + * + */ +int cam_cpas_reg_write( + uint32_t client_handle, + enum cam_cpas_reg_base reg_base, + uint32_t offset, + bool mb, + uint32_t value); + +/** + * cam_cpas_reg_read() + * + * @brief: API to read a register value from CPAS register space + * + * @client_handle : Client cpas handle + * @reg_base : Register base identifier + * @offset : Offset from the register base address + * @mb : Whether to do reg read with memory barrier + * @value : Value to be red from register + * + * @return 0 on success. + * + */ +int cam_cpas_reg_read( + uint32_t client_handle, + enum cam_cpas_reg_base reg_base, + uint32_t offset, + bool mb, + uint32_t *value); + +/** + * cam_cpas_get_hw_info() + * + * @brief: API to get camera hw information + * + * @camera_family : Camera family type. One of + * CAM_FAMILY_CAMERA_SS + * CAM_FAMILY_CPAS_SS + * @camera_version : Camera platform version + * @cpas_version : Camera cpas version + * @cam_caps : Camera capability + * + * @return 0 on success. + * + */ +int cam_cpas_get_hw_info( + uint32_t *camera_family, + struct cam_hw_version *camera_version, + struct cam_hw_version *cpas_version, + uint32_t *cam_caps); + +/** + * cam_cpas_get_cpas_hw_version() + * + * @brief: API to get camera cpas hw version + * + * @hw_version : Camera cpas hw version + * + * @return 0 on success. + * + */ +int cam_cpas_get_cpas_hw_version( + uint32_t *hw_version); + +/** + * cam_cpas_axi_util_path_type_to_string() + * + * @brief: API to get string for given path type + * + * @path_data_type : Path type + * + * @return string. + * + */ +const char *cam_cpas_axi_util_path_type_to_string( + uint32_t path_data_type); + +/** + * cam_cpas_axi_util_trans_type_to_string() + * + * @brief: API to get string for given transaction type + * + * @path_data_type : Transaction type + * + * @return string. + * + */ +const char *cam_cpas_axi_util_trans_type_to_string( + uint32_t path_data_type); + + +#endif /* _CAM_CPAS_API_H_ */ diff --git a/drivers/cam_fd/Makefile b/drivers/cam_fd/Makefile new file mode 100644 index 000000000000..20fd941327ed --- /dev/null +++ b/drivers/cam_fd/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_dev.o cam_fd_context.o diff --git a/drivers/cam_fd/cam_fd_context.c b/drivers/cam_fd/cam_fd_context.c new file mode 100644 index 000000000000..427fcf788081 --- /dev/null +++ b/drivers/cam_fd/cam_fd_context.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include + +#include "cam_debug_util.h" +#include "cam_fd_context.h" +#include "cam_trace.h" + +static const char fd_dev_name[] = "fd"; + +/* Functions in Available state */ +static int __cam_fd_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Acquire dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("FD", ctx); + + return rc; +} + +/* Functions in Acquired state */ +static int __cam_fd_ctx_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Release dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_AVAILABLE; + trace_cam_context_state("FD", ctx); + + return rc; +} + +static int __cam_fd_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Prepare dev, rc=%d", rc); + return rc; + } + + return rc; +} + +static int __cam_fd_ctx_start_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_start_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Start dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_ACTIVATED; + trace_cam_context_state("FD", ctx); + + return rc; +} + +/* Functions in Activated state */ +static int __cam_fd_ctx_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Stop dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("FD", ctx); + + return rc; +} + +static int __cam_fd_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = __cam_fd_ctx_stop_dev_in_activated(ctx, NULL); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Stop dev, rc=%d", rc); + return rc; + } + + rc = __cam_fd_ctx_release_dev_in_acquired(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Release dev, rc=%d", rc); + return rc; + } + + return rc; +} + +static int __cam_fd_ctx_flush_dev_in_activated(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to flush device, rc=%d", rc); + + return rc; +} +static int __cam_fd_ctx_config_dev_in_activated( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Prepare dev, rc=%d", rc); + return rc; + } + + return rc; +} + +static int __cam_fd_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc; + + rc = cam_context_buf_done_from_hw(context, evt_data, evt_id); + if (rc) { + CAM_ERR(CAM_FD, "Failed in buf done, rc=%d", rc); + return rc; + } + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_fd_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_fd_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_fd_ctx_release_dev_in_acquired, + .config_dev = __cam_fd_ctx_config_dev_in_acquired, + .start_dev = __cam_fd_ctx_start_dev_in_acquired, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Ready */ + { + .ioctl_ops = { }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Activated */ + { + .ioctl_ops = { + .stop_dev = __cam_fd_ctx_stop_dev_in_activated, + .release_dev = __cam_fd_ctx_release_dev_in_activated, + .config_dev = __cam_fd_ctx_config_dev_in_activated, + .flush_dev = __cam_fd_ctx_flush_dev_in_activated, + }, + .crm_ops = {}, + .irq_ops = __cam_fd_ctx_handle_irq_in_activated, + }, +}; + + +int cam_fd_context_init(struct cam_fd_context *fd_ctx, + struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) +{ + int rc; + + if (!base_ctx || !fd_ctx) { + CAM_ERR(CAM_FD, "Invalid Context %pK %pK", base_ctx, fd_ctx); + return -EINVAL; + } + + memset(fd_ctx, 0, sizeof(*fd_ctx)); + + rc = cam_context_init(base_ctx, fd_dev_name, CAM_FD, ctx_id, + NULL, hw_intf, fd_ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_FD, "Camera Context Base init failed, rc=%d", rc); + return rc; + } + + fd_ctx->base = base_ctx; + base_ctx->ctx_priv = fd_ctx; + base_ctx->state_machine = cam_fd_ctx_state_machine; + + return rc; +} + +int cam_fd_context_deinit(struct cam_fd_context *fd_ctx) +{ + int rc = 0; + + if (!fd_ctx || !fd_ctx->base) { + CAM_ERR(CAM_FD, "Invalid inputs %pK", fd_ctx); + return -EINVAL; + } + + rc = cam_context_deinit(fd_ctx->base); + if (rc) + CAM_ERR(CAM_FD, "Error in base deinit, rc=%d", rc); + + memset(fd_ctx, 0, sizeof(*fd_ctx)); + + return rc; +} diff --git a/drivers/cam_fd/cam_fd_context.h b/drivers/cam_fd/cam_fd_context.h new file mode 100644 index 000000000000..ab0fa92b43f2 --- /dev/null +++ b/drivers/cam_fd/cam_fd_context.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_CONTEXT_H_ +#define _CAM_FD_CONTEXT_H_ + +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_interface.h" + +/** + * struct cam_fd_context - Face Detection context information + * + * @base : Base context pointer for this FD context + * @req_base : List of base requests for this FD context + */ +struct cam_fd_context { + struct cam_context *base; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; +}; + +int cam_fd_context_init(struct cam_fd_context *fd_ctx, + struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); +int cam_fd_context_deinit(struct cam_fd_context *ctx); + +#endif /* _CAM_FD_CONTEXT_H_ */ diff --git a/drivers/cam_fd/cam_fd_dev.c b/drivers/cam_fd/cam_fd_dev.c new file mode 100644 index 000000000000..c92cea8fc9e9 --- /dev/null +++ b/drivers/cam_fd/cam_fd_dev.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_fd_context.h" +#include "cam_fd_hw_mgr.h" +#include "cam_fd_hw_mgr_intf.h" + +#define CAM_FD_DEV_NAME "cam-fd" + +/** + * struct cam_fd_dev - FD device information + * + * @sd: Subdev information + * @base_ctx: List of base contexts + * @fd_ctx: List of FD contexts + * @lock: Mutex handle + * @open_cnt: FD subdev open count + * @probe_done: Whether FD probe is completed + */ +struct cam_fd_dev { + struct cam_subdev sd; + struct cam_context base_ctx[CAM_CTX_MAX]; + struct cam_fd_context fd_ctx[CAM_CTX_MAX]; + struct mutex lock; + uint32_t open_cnt; + bool probe_done; +}; + +static struct cam_fd_dev g_fd_dev; + +static int cam_fd_dev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_fd_dev *fd_dev = &g_fd_dev; + + if (!fd_dev->probe_done) { + CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev); + return -ENODEV; + } + + mutex_lock(&fd_dev->lock); + fd_dev->open_cnt++; + CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); + mutex_unlock(&fd_dev->lock); + + return 0; +} + +static int cam_fd_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_fd_dev *fd_dev = &g_fd_dev; + struct cam_node *node = v4l2_get_subdevdata(sd); + + if (!fd_dev->probe_done) { + CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev); + return -ENODEV; + } + + mutex_lock(&fd_dev->lock); + fd_dev->open_cnt--; + CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); + mutex_unlock(&fd_dev->lock); + + if (!node) { + CAM_ERR(CAM_FD, "Node ptr is NULL"); + return -EINVAL; + } + + cam_node_shutdown(node); + + return 0; +} + +static const struct v4l2_subdev_internal_ops cam_fd_subdev_internal_ops = { + .open = cam_fd_dev_open, + .close = cam_fd_dev_close, +}; + +static int cam_fd_dev_probe(struct platform_device *pdev) +{ + int rc; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + + g_fd_dev.sd.internal_ops = &cam_fd_subdev_internal_ops; + + /* Initialize the v4l2 subdevice first. (create cam_node) */ + rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME, + CAM_FD_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_FD, "FD cam_subdev_probe failed, rc=%d", rc); + return rc; + } + node = (struct cam_node *) g_fd_dev.sd.token; + + rc = cam_fd_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf); + if (rc) { + CAM_ERR(CAM_FD, "Failed in initializing FD HW manager, rc=%d", + rc); + goto unregister_subdev; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_fd_context_init(&g_fd_dev.fd_ctx[i], + &g_fd_dev.base_ctx[i], &node->hw_mgr_intf, i); + if (rc) { + CAM_ERR(CAM_FD, "FD context init failed i=%d, rc=%d", + i, rc); + goto deinit_ctx; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_fd_dev.base_ctx, CAM_CTX_MAX, + CAM_FD_DEV_NAME); + if (rc) { + CAM_ERR(CAM_FD, "FD node init failed, rc=%d", rc); + goto deinit_ctx; + } + + mutex_init(&g_fd_dev.lock); + g_fd_dev.probe_done = true; + + CAM_DBG(CAM_FD, "Camera FD probe complete"); + + return 0; + +deinit_ctx: + for (--i; i >= 0; i--) { + if (cam_fd_context_deinit(&g_fd_dev.fd_ctx[i])) + CAM_ERR(CAM_FD, "FD context %d deinit failed", i); + } +unregister_subdev: + if (cam_subdev_remove(&g_fd_dev.sd)) + CAM_ERR(CAM_FD, "Failed in subdev remove"); + + return rc; +} + +static int cam_fd_dev_remove(struct platform_device *pdev) +{ + int i, rc; + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_fd_context_deinit(&g_fd_dev.fd_ctx[i]); + if (rc) + CAM_ERR(CAM_FD, "FD context %d deinit failed, rc=%d", + i, rc); + } + + rc = cam_fd_hw_mgr_deinit(pdev->dev.of_node); + if (rc) + CAM_ERR(CAM_FD, "Failed in hw mgr deinit, rc=%d", rc); + + rc = cam_subdev_remove(&g_fd_dev.sd); + if (rc) + CAM_ERR(CAM_FD, "Unregister failed, rc=%d", rc); + + mutex_destroy(&g_fd_dev.lock); + g_fd_dev.probe_done = false; + + return rc; +} + +static const struct of_device_id cam_fd_dt_match[] = { + { + .compatible = "qcom,cam-fd" + }, + {} +}; + +static struct platform_driver cam_fd_driver = { + .probe = cam_fd_dev_probe, + .remove = cam_fd_dev_remove, + .driver = { + .name = "cam_fd", + .owner = THIS_MODULE, + .of_match_table = cam_fd_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_fd_dev_init_module(void) +{ + return platform_driver_register(&cam_fd_driver); +} + +static void __exit cam_fd_dev_exit_module(void) +{ + platform_driver_unregister(&cam_fd_driver); +} + +module_init(cam_fd_dev_init_module); +module_exit(cam_fd_dev_exit_module); +MODULE_DESCRIPTION("MSM FD driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_fd/fd_hw_mgr/Makefile b/drivers/cam_fd/fd_hw_mgr/Makefile new file mode 100644 index 000000000000..cc15876c9602 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_mgr.o diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c new file mode 100644 index 000000000000..0d7e709ad38f --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -0,0 +1,1949 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_mem_mgr_api.h" +#include "cam_smmu_api.h" +#include "cam_packet_util.h" +#include "cam_fd_context.h" +#include "cam_fd_hw_intf.h" +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" +#include "cam_fd_hw_mgr_intf.h" +#include "cam_fd_hw_mgr.h" +#include "cam_trace.h" + +static struct cam_fd_hw_mgr g_fd_hw_mgr; + +static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + int i, rc; + + if (!packet) + return -EINVAL; + + CAM_DBG(CAM_FD, "Packet request=%d, op_code=0x%x, size=%d, flags=%d", + packet->header.request_id, packet->header.op_code, + packet->header.size, packet->header.flags); + CAM_DBG(CAM_FD, + "Packet cmdbuf(offset=%d, num=%d) io(offset=%d, num=%d)", + packet->cmd_buf_offset, packet->num_cmd_buf, + packet->io_configs_offset, packet->num_io_configs); + CAM_DBG(CAM_FD, + "Packet Patch(offset=%d, num=%d) kmd(offset=%d, num=%d)", + packet->patch_offset, packet->num_patches, + packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); + + if (cam_packet_util_validate_packet(packet, remain_len)) { + CAM_ERR(CAM_FD, "invalid packet:%d %d %d %d %d", + packet->kmd_cmd_buf_index, + packet->num_cmd_buf, packet->cmd_buf_offset, + packet->io_configs_offset, packet->header.size); + return -EINVAL; + } + + /* All buffers must come through io config, do not support patching */ + if (packet->num_patches || !packet->num_io_configs) { + CAM_ERR(CAM_FD, "wrong number of cmd/patch info: %u %u", + packet->num_cmd_buf, packet->num_patches); + return -EINVAL; + } + + /* KMD Buf index can never be greater than or equal to num cmd bufs */ + if (packet->kmd_cmd_buf_index >= packet->num_cmd_buf) { + CAM_ERR(CAM_FD, "Invalid kmd index %d (%d)", + packet->kmd_cmd_buf_index, packet->num_cmd_buf); + return -EINVAL; + } + + if ((packet->header.op_code & 0xff) != + CAM_PACKET_OPCODES_FD_FRAME_UPDATE) { + CAM_ERR(CAM_FD, "Invalid op_code %u", + packet->header.op_code & 0xff); + return -EINVAL; + } + + cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *)&packet->payload + + packet->cmd_buf_offset); + + for (i = 0; i < packet->num_cmd_buf; i++) { + /* + * We can allow 0 length cmd buffer. This can happen in case + * umd gives an empty cmd buffer as kmd buffer + */ + if (!cmd_desc[i].length) + continue; + + if ((cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_GENERIC) && + (cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_CDM)) { + CAM_ERR(CAM_FD, "Invalid meta_data [%d] %u", i, + cmd_desc[i].meta_data); + return -EINVAL; + } + + CAM_DBG(CAM_FD, + "CmdBuf[%d] hdl=%d, offset=%d, size=%d, len=%d, type=%d, meta_data=%d", + i, + cmd_desc[i].mem_handle, cmd_desc[i].offset, + cmd_desc[i].size, cmd_desc[i].length, cmd_desc[i].type, + cmd_desc[i].meta_data); + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) { + CAM_ERR(CAM_FD, "Invalid cmd buffer %d", i); + return rc; + } + } + + return 0; +} + +static int cam_fd_mgr_util_put_ctx( + struct list_head *src_list, + struct cam_fd_hw_mgr_ctx **fd_ctx) +{ + int rc = 0; + struct cam_fd_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.ctx_mutex); + ctx_ptr = *fd_ctx; + if (ctx_ptr) + list_add_tail(&ctx_ptr->list, src_list); + *fd_ctx = NULL; + mutex_unlock(&g_fd_hw_mgr.ctx_mutex); + + return rc; +} + +static int cam_fd_mgr_util_get_ctx( + struct list_head *src_list, + struct cam_fd_hw_mgr_ctx **fd_ctx) +{ + int rc = 0; + struct cam_fd_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.ctx_mutex); + if (!list_empty(src_list)) { + ctx_ptr = list_first_entry(src_list, + struct cam_fd_hw_mgr_ctx, list); + list_del_init(&ctx_ptr->list); + } else { + CAM_ERR(CAM_FD, "No more free fd hw mgr ctx"); + rc = -1; + } + *fd_ctx = ctx_ptr; + mutex_unlock(&g_fd_hw_mgr.ctx_mutex); + + return rc; +} + +static int cam_fd_mgr_util_put_frame_req( + struct list_head *src_list, + struct cam_fd_mgr_frame_request **frame_req) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *req_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.frame_req_mutex); + req_ptr = *frame_req; + if (req_ptr) { + list_del_init(&req_ptr->list); + list_add_tail(&req_ptr->list, src_list); + } + *frame_req = NULL; + mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); + + return rc; +} + +static int cam_fd_mgr_util_get_frame_req( + struct list_head *src_list, + struct cam_fd_mgr_frame_request **frame_req) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *req_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.frame_req_mutex); + if (!list_empty(src_list)) { + req_ptr = list_first_entry(src_list, + struct cam_fd_mgr_frame_request, list); + list_del_init(&req_ptr->list); + } else { + CAM_DBG(CAM_FD, "Frame req not available"); + rc = -EPERM; + } + *frame_req = req_ptr; + mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); + + return rc; +} + +static int cam_fd_mgr_util_get_device(struct cam_fd_hw_mgr *hw_mgr, + struct cam_fd_hw_mgr_ctx *hw_ctx, struct cam_fd_device **hw_device) +{ + if (!hw_mgr || !hw_ctx || !hw_device) { + CAM_ERR(CAM_FD, "Invalid input %pK %pK %pK", hw_mgr, hw_ctx, + hw_device); + return -EINVAL; + } + + if ((hw_ctx->device_index < 0) || + (hw_ctx->device_index >= CAM_FD_HW_MAX)) { + CAM_ERR(CAM_FD, "Invalid device indx %d", hw_ctx->device_index); + return -EINVAL; + } + + CAM_DBG(CAM_FD, "ctx_index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + *hw_device = &hw_mgr->hw_device[hw_ctx->device_index]; + + return 0; +} + +static int cam_fd_mgr_util_release_device(struct cam_fd_hw_mgr *hw_mgr, + struct cam_fd_hw_mgr_ctx *hw_ctx) +{ + struct cam_fd_device *hw_device; + struct cam_fd_hw_release_args hw_release_args; + int rc; + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + if (hw_device->hw_intf->hw_ops.release) { + hw_release_args.hw_ctx = hw_ctx; + hw_release_args.ctx_hw_private = hw_ctx->ctx_hw_private; + rc = hw_device->hw_intf->hw_ops.release( + hw_device->hw_intf->hw_priv, &hw_release_args, + sizeof(hw_release_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW release %d", rc); + return rc; + } + } else { + CAM_ERR(CAM_FD, "Invalid release function"); + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + hw_device->num_ctxts--; + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + hw_ctx->device_index = -1; + + return rc; +} + +static int cam_fd_mgr_util_select_device(struct cam_fd_hw_mgr *hw_mgr, + struct cam_fd_hw_mgr_ctx *hw_ctx, + struct cam_fd_acquire_dev_info *fd_acquire_args) +{ + int i, rc; + struct cam_fd_hw_reserve_args hw_reserve_args; + struct cam_fd_device *hw_device = NULL; + + if (!hw_mgr || !hw_ctx || !fd_acquire_args) { + CAM_ERR(CAM_FD, "Invalid input %pK %pK %pK", hw_mgr, hw_ctx, + fd_acquire_args); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + /* Check if a device is free which can satisfy the requirements */ + for (i = 0; i < hw_mgr->num_devices; i++) { + hw_device = &hw_mgr->hw_device[i]; + CAM_DBG(CAM_FD, + "[%d] : num_ctxts=%d, modes=%d, raw_results=%d", + i, hw_device->num_ctxts, + hw_device->hw_caps.supported_modes, + hw_device->hw_caps.raw_results_available); + if ((hw_device->num_ctxts == 0) && + (fd_acquire_args->mode & + hw_device->hw_caps.supported_modes) && + (!fd_acquire_args->get_raw_results || + hw_device->hw_caps.raw_results_available)) { + CAM_DBG(CAM_FD, "Found dedicated HW Index=%d", i); + hw_device->num_ctxts++; + break; + } + } + + /* + * We couldn't find a free HW which meets requirement, now check if + * there is a HW which meets acquire requirements + */ + if (i == hw_mgr->num_devices) { + for (i = 0; i < hw_mgr->num_devices; i++) { + hw_device = &hw_mgr->hw_device[i]; + if ((fd_acquire_args->mode & + hw_device->hw_caps.supported_modes) && + (!fd_acquire_args->get_raw_results || + hw_device->hw_caps.raw_results_available)) { + hw_device->num_ctxts++; + CAM_DBG(CAM_FD, "Found sharing HW Index=%d", i); + break; + } + } + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + if ((i == hw_mgr->num_devices) || !hw_device) { + CAM_ERR(CAM_FD, "Couldn't acquire HW %d %d", + fd_acquire_args->mode, + fd_acquire_args->get_raw_results); + return -EBUSY; + } + + CAM_DBG(CAM_FD, "Device index %d selected for this acquire", i); + + /* Check if we can reserve this HW */ + if (hw_device->hw_intf->hw_ops.reserve) { + hw_reserve_args.hw_ctx = hw_ctx; + hw_reserve_args.mode = fd_acquire_args->mode; + rc = hw_device->hw_intf->hw_ops.reserve( + hw_device->hw_intf->hw_priv, &hw_reserve_args, + sizeof(hw_reserve_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW reserve %d", rc); + return rc; + } + hw_ctx->ctx_hw_private = hw_reserve_args.ctx_hw_private; + } else { + CAM_ERR(CAM_FD, "Invalid reserve function"); + return -EPERM; + } + + /* Update required info in hw context */ + hw_ctx->device_index = i; + + CAM_DBG(CAM_FD, "ctx index=%u, device_index=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + return 0; +} + +static int cam_fd_mgr_util_pdev_get_hw_intf(struct device_node *of_node, + int i, struct cam_hw_intf **device_hw_intf) +{ + struct device_node *device_node = NULL; + struct platform_device *child_pdev = NULL; + struct cam_hw_intf *hw_intf = NULL; + const char *name = NULL; + int rc; + + rc = of_property_read_string_index(of_node, "compat-hw-name", i, &name); + if (rc) { + CAM_ERR(CAM_FD, "Getting dev object name failed %d %d", i, rc); + goto put_node; + } + + device_node = of_find_node_by_name(NULL, name); + if (!device_node) { + CAM_ERR(CAM_FD, "Cannot find node in dtsi %s", name); + return -ENODEV; + } + + child_pdev = of_find_device_by_node(device_node); + if (!child_pdev) { + CAM_ERR(CAM_FD, "Failed to find device on bus %s", + device_node->name); + rc = -ENODEV; + goto put_node; + } + + hw_intf = (struct cam_hw_intf *)platform_get_drvdata(child_pdev); + if (!hw_intf) { + CAM_ERR(CAM_FD, "No driver data for child device"); + rc = -ENODEV; + goto put_node; + } + + CAM_DBG(CAM_FD, "child type %d index %d child_intf %pK", + hw_intf->hw_type, hw_intf->hw_idx, hw_intf); + + if (hw_intf->hw_idx >= CAM_FD_HW_MAX) { + CAM_ERR(CAM_FD, "hw_idx invalid %d", hw_intf->hw_idx); + rc = -ENODEV; + goto put_node; + } + + rc = 0; + *device_hw_intf = hw_intf; + +put_node: + of_node_put(device_node); + + return rc; +} + +static int cam_fd_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + struct cam_fd_hw_cmd_prestart_args *prestart_args = + (struct cam_fd_hw_cmd_prestart_args *)user_data; + + if (!blob_data || (blob_size == 0)) { + CAM_ERR(CAM_FD, "Invalid blob info %pK %u", blob_data, + blob_size); + return -EINVAL; + } + + if (!prestart_args) { + CAM_ERR(CAM_FD, "Invalid user data"); + return -EINVAL; + } + + switch (blob_type) { + case CAM_FD_BLOB_TYPE_RAW_RESULTS_REQUIRED: { + uint32_t *get_raw_results = (uint32_t *)blob_data; + + if (sizeof(uint32_t) != blob_size) { + CAM_ERR(CAM_FD, "Invalid blob size %zu %u", + sizeof(uint32_t), blob_size); + return -EINVAL; + } + + prestart_args->get_raw_results = *get_raw_results; + break; + } + case CAM_FD_BLOB_TYPE_SOC_CLOCK_BW_REQUEST: { + struct cam_fd_soc_clock_bw_request *clk_req = + (struct cam_fd_soc_clock_bw_request *)blob_data; + + if (sizeof(struct cam_fd_soc_clock_bw_request) != blob_size) { + CAM_ERR(CAM_FD, "Invalid blob size %zu %u", + sizeof(struct cam_fd_soc_clock_bw_request), + blob_size); + return -EINVAL; + } + + CAM_DBG(CAM_FD, "SOC Clk Request clock=%lld, bw=%lld", + clk_req->clock_rate, clk_req->bandwidth); + + break; + } + default: + CAM_WARN(CAM_FD, "Unknown blob type %d", blob_type); + break; + } + + return 0; +} + +static int cam_fd_mgr_util_parse_generic_cmd_buffer( + struct cam_fd_hw_mgr_ctx *hw_ctx, struct cam_packet *packet, + struct cam_fd_hw_cmd_prestart_args *prestart_args) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + int i, rc = 0; + + cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *)&packet->payload + + packet->cmd_buf_offset); + + for (i = 0; i < packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if (cmd_desc[i].meta_data == CAM_FD_CMD_BUFFER_ID_CDM) + continue; + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) + return rc; + + rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[i], + cam_fd_packet_generic_blob_handler, prestart_args); + if (rc) + CAM_ERR(CAM_FD, "Failed in processing blobs %d", rc); + + break; + } + + return rc; +} + +static int cam_fd_mgr_util_get_buf_map_requirement(uint32_t direction, + uint32_t resource_type, bool *need_io_map, bool *need_cpu_map) +{ + if (!need_io_map || !need_cpu_map) { + CAM_ERR(CAM_FD, "Invalid input pointers %pK %pK", need_io_map, + need_cpu_map); + return -EINVAL; + } + + if (direction == CAM_BUF_INPUT) { + switch (resource_type) { + case CAM_FD_INPUT_PORT_ID_IMAGE: + *need_io_map = true; + *need_cpu_map = false; + break; + default: + CAM_WARN(CAM_FD, "Invalid port: dir %d, id %d", + direction, resource_type); + return -EINVAL; + } + } else if (direction == CAM_BUF_OUTPUT) { + switch (resource_type) { + case CAM_FD_OUTPUT_PORT_ID_RESULTS: + *need_io_map = true; + *need_cpu_map = true; + break; + case CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS: + *need_io_map = true; + *need_cpu_map = true; + break; + case CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER: + *need_io_map = true; + *need_cpu_map = false; + break; + default: + CAM_WARN(CAM_FD, "Invalid port: dir %d, id %d", + direction, resource_type); + return -EINVAL; + } + } else { + CAM_WARN(CAM_FD, "Invalid direction %d", direction); + return -EINVAL; + } + + return 0; +} + +static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + struct cam_fd_hw_io_buffer *input_buf, + struct cam_fd_hw_io_buffer *output_buf, uint32_t io_buf_size) +{ + int rc = -EINVAL; + uint32_t plane, num_out_buf, num_in_buf; + int i, j; + struct cam_buf_io_cfg *io_cfg; + dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; + uintptr_t cpu_addr[CAM_PACKET_MAX_PLANES]; + size_t size; + bool need_io_map, need_cpu_map; + + /* Get IO Buf information */ + num_out_buf = 0; + num_in_buf = 0; + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &prepare->packet->payload + prepare->packet->io_configs_offset); + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_FD, + "IOConfig[%d] : handle[%d] Dir[%d] Res[%d] Fence[%d], Format[%d]", + i, io_cfg[i].mem_handle[0], io_cfg[i].direction, + io_cfg[i].resource_type, + io_cfg[i].fence, io_cfg[i].format); + + if ((num_in_buf >= io_buf_size) || + (num_out_buf >= io_buf_size)) { + CAM_ERR(CAM_FD, "Invalid number of buffers %d %d %d", + num_in_buf, num_out_buf, io_buf_size); + return -EINVAL; + } + + rc = cam_fd_mgr_util_get_buf_map_requirement( + io_cfg[i].direction, io_cfg[i].resource_type, + &need_io_map, &need_cpu_map); + if (rc) { + CAM_WARN(CAM_FD, "Invalid io buff [%d] : %d %d %d", + i, io_cfg[i].direction, + io_cfg[i].resource_type, rc); + continue; + } + + memset(io_addr, 0x0, sizeof(io_addr)); + for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) { + if (!io_cfg[i].mem_handle[plane]) + break; + + io_addr[plane] = 0x0; + cpu_addr[plane] = 0x0; + + if (need_io_map) { + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane], + iommu_hdl, &io_addr[plane], &size); + if (rc) { + CAM_ERR(CAM_FD, + "Invalid io buf %d %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + rc); + return -ENOMEM; + } + + io_addr[plane] += io_cfg[i].offsets[plane]; + } + + if (need_cpu_map) { + rc = cam_mem_get_cpu_buf( + io_cfg[i].mem_handle[plane], + &cpu_addr[plane], &size); + if (rc || ((io_addr[plane] & 0xFFFFFFFF) + != io_addr[plane])) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + rc); + return rc; + } + if (io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane); + rc = -EINVAL; + return rc; + } + cpu_addr[plane] += io_cfg[i].offsets[plane]; + } + + CAM_DBG(CAM_FD, "IO Address[%d][%d] : %pK, %pK", + io_cfg[i].direction, plane, io_addr[plane], + cpu_addr[plane]); + } + + switch (io_cfg[i].direction) { + case CAM_BUF_INPUT: { + prepare->in_map_entries[num_in_buf].resource_handle = + io_cfg[i].resource_type; + prepare->in_map_entries[num_in_buf].sync_id = + io_cfg[i].fence; + + input_buf[num_in_buf].valid = true; + for (j = 0; j < plane; j++) { + input_buf[num_in_buf].io_addr[j] = io_addr[j]; + input_buf[num_in_buf].cpu_addr[j] = cpu_addr[j]; + } + input_buf[num_in_buf].num_buf = plane; + input_buf[num_in_buf].io_cfg = &io_cfg[i]; + + num_in_buf++; + break; + } + case CAM_BUF_OUTPUT: { + prepare->out_map_entries[num_out_buf].resource_handle = + io_cfg[i].resource_type; + prepare->out_map_entries[num_out_buf].sync_id = + io_cfg[i].fence; + + output_buf[num_out_buf].valid = true; + for (j = 0; j < plane; j++) { + output_buf[num_out_buf].io_addr[j] = io_addr[j]; + output_buf[num_out_buf].cpu_addr[j] = + cpu_addr[j]; + } + output_buf[num_out_buf].num_buf = plane; + output_buf[num_out_buf].io_cfg = &io_cfg[i]; + + num_out_buf++; + break; + } + default: + CAM_ERR(CAM_FD, "Unsupported io direction %d", + io_cfg[i].direction); + rc = -EINVAL; + break; + } + } + + prepare->num_in_map_entries = num_in_buf; + prepare->num_out_map_entries = num_out_buf; + return rc; +} + +static int cam_fd_mgr_util_prepare_hw_update_entries( + struct cam_fd_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare, + struct cam_fd_hw_cmd_prestart_args *prestart_args, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int i, rc; + struct cam_hw_update_entry *hw_entry; + uint32_t num_ent; + struct cam_fd_hw_mgr_ctx *hw_ctx = + (struct cam_fd_hw_mgr_ctx *)prepare->ctxt_to_hw_map; + struct cam_fd_device *hw_device; + uint32_t kmd_buf_max_size, kmd_buf_used_bytes = 0; + uint32_t *kmd_buf_addr; + struct cam_cmd_buf_desc *cmd_desc = NULL; + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + kmd_buf_addr = (uint32_t *)((uint8_t *)kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes); + kmd_buf_max_size = kmd_buf_info->size - kmd_buf_info->used_bytes; + + prestart_args->cmd_buf_addr = kmd_buf_addr; + prestart_args->size = kmd_buf_max_size; + prestart_args->pre_config_buf_size = 0; + prestart_args->post_config_buf_size = 0; + + if (hw_device->hw_intf->hw_ops.process_cmd) { + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, CAM_FD_HW_CMD_PRESTART, + prestart_args, + sizeof(struct cam_fd_hw_cmd_prestart_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in CMD_PRESTART %d", rc); + return rc; + } + } + + kmd_buf_used_bytes += prestart_args->pre_config_buf_size; + kmd_buf_used_bytes += prestart_args->post_config_buf_size; + + /* HW layer is expected to add commands */ + if (!kmd_buf_used_bytes || (kmd_buf_used_bytes > kmd_buf_max_size)) { + CAM_ERR(CAM_FD, "Invalid kmd used bytes %d (%d)", + kmd_buf_used_bytes, kmd_buf_max_size); + return -ENOMEM; + } + + hw_entry = prepare->hw_update_entries; + num_ent = 0; + + if (prestart_args->pre_config_buf_size) { + if ((num_ent + 1) >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_FD, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_ent].handle = kmd_buf_info->handle; + hw_entry[num_ent].len = prestart_args->pre_config_buf_size; + hw_entry[num_ent].offset = kmd_buf_info->offset; + + kmd_buf_info->used_bytes += prestart_args->pre_config_buf_size; + kmd_buf_info->offset += prestart_args->pre_config_buf_size; + num_ent++; + } + + /* + * set the cmd_desc to point the first command descriptor in the + * packet and update hw entries with CDM command buffers + */ + cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *) + &prepare->packet->payload + prepare->packet->cmd_buf_offset); + + for (i = 0; i < prepare->packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if (cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_CDM) + continue; + + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_FD, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_ent].handle = cmd_desc[i].mem_handle; + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].offset = cmd_desc[i].offset; + num_ent++; + } + + if (prestart_args->post_config_buf_size) { + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_FD, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_ent].handle = kmd_buf_info->handle; + hw_entry[num_ent].len = prestart_args->post_config_buf_size; + hw_entry[num_ent].offset = kmd_buf_info->offset; + + kmd_buf_info->used_bytes += prestart_args->post_config_buf_size; + kmd_buf_info->offset += prestart_args->post_config_buf_size; + + num_ent++; + } + + prepare->num_hw_update_entries = num_ent; + + CAM_DBG(CAM_FD, "FinalConfig : hw_entries=%d, Sync(in=%d, out=%d)", + prepare->num_hw_update_entries, prepare->num_in_map_entries, + prepare->num_out_map_entries); + + return rc; +} + +static int cam_fd_mgr_util_submit_frame(void *priv, void *data) +{ + struct cam_fd_device *hw_device; + struct cam_fd_hw_mgr *hw_mgr; + struct cam_fd_mgr_frame_request *frame_req; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_hw_cmd_start_args start_args; + int rc; + + if (!priv) { + CAM_ERR(CAM_FD, "Invalid data"); + return -EINVAL; + } + + hw_mgr = (struct cam_fd_hw_mgr *)priv; + mutex_lock(&hw_mgr->frame_req_mutex); + + /* Check if we have any frames pending in high priority list */ + if (!list_empty(&hw_mgr->frame_pending_list_high)) { + CAM_DBG(CAM_FD, "Pending frames in high priority list"); + frame_req = list_first_entry(&hw_mgr->frame_pending_list_high, + struct cam_fd_mgr_frame_request, list); + } else if (!list_empty(&hw_mgr->frame_pending_list_normal)) { + CAM_DBG(CAM_FD, "Pending frames in normal priority list"); + frame_req = list_first_entry(&hw_mgr->frame_pending_list_normal, + struct cam_fd_mgr_frame_request, list); + } else { + mutex_unlock(&hw_mgr->frame_req_mutex); + CAM_DBG(CAM_FD, "No pending frames"); + return 0; + } + + CAM_DBG(CAM_FD, "FrameSubmit : Frame[%lld]", frame_req->request_id); + hw_ctx = frame_req->hw_ctx; + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + mutex_unlock(&hw_mgr->frame_req_mutex); + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_device->lock); + if (hw_device->ready_to_process == false) { + mutex_unlock(&hw_device->lock); + mutex_unlock(&hw_mgr->frame_req_mutex); + return -EBUSY; + } + + trace_cam_submit_to_hw("FD", frame_req->request_id); + + list_del_init(&frame_req->list); + mutex_unlock(&hw_mgr->frame_req_mutex); + + if (hw_device->hw_intf->hw_ops.start) { + start_args.hw_ctx = hw_ctx; + start_args.ctx_hw_private = hw_ctx->ctx_hw_private; + start_args.hw_req_private = &frame_req->hw_req_private; + start_args.hw_update_entries = frame_req->hw_update_entries; + start_args.num_hw_update_entries = + frame_req->num_hw_update_entries; + + rc = hw_device->hw_intf->hw_ops.start( + hw_device->hw_intf->hw_priv, &start_args, + sizeof(start_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW Start %d", rc); + mutex_unlock(&hw_device->lock); + goto put_req_into_free_list; + } + } else { + CAM_ERR(CAM_FD, "Invalid hw_ops.start"); + mutex_unlock(&hw_device->lock); + rc = -EPERM; + goto put_req_into_free_list; + } + + hw_device->ready_to_process = false; + hw_device->cur_hw_ctx = hw_ctx; + hw_device->req_id = frame_req->request_id; + mutex_unlock(&hw_device->lock); + + rc = cam_fd_mgr_util_put_frame_req( + &hw_mgr->frame_processing_list, &frame_req); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in putting frame req in processing list"); + goto stop_unlock; + } + + return rc; + +stop_unlock: + if (hw_device->hw_intf->hw_ops.stop) { + struct cam_fd_hw_stop_args stop_args; + + stop_args.hw_ctx = hw_ctx; + stop_args.ctx_hw_private = hw_ctx->ctx_hw_private; + stop_args.hw_req_private = &frame_req->hw_req_private; + if (hw_device->hw_intf->hw_ops.stop( + hw_device->hw_intf->hw_priv, &stop_args, + sizeof(stop_args))) + CAM_ERR(CAM_FD, "Failed in HW Stop %d", rc); + } +put_req_into_free_list: + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, &frame_req); + + return rc; +} + +static int cam_fd_mgr_util_schedule_frame_worker_task( + struct cam_fd_hw_mgr *hw_mgr) +{ + int32_t rc = 0; + struct crm_workq_task *task; + struct cam_fd_mgr_work_data *work_data; + + task = cam_req_mgr_workq_get_task(hw_mgr->work); + if (!task) { + CAM_ERR(CAM_FD, "no empty task available"); + return -ENOMEM; + } + + work_data = (struct cam_fd_mgr_work_data *)task->payload; + work_data->type = CAM_FD_WORK_FRAME; + + task->process_cb = cam_fd_mgr_util_submit_frame; + rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0); + + return rc; +} + +static int32_t cam_fd_mgr_workq_irq_cb(void *priv, void *data) +{ + struct cam_fd_device *hw_device = NULL; + struct cam_fd_hw_mgr *hw_mgr; + struct cam_fd_mgr_work_data *work_data; + struct cam_fd_mgr_frame_request *frame_req = NULL; + enum cam_fd_hw_irq_type irq_type; + bool frame_abort = true; + int rc; + + if (!data || !priv) { + CAM_ERR(CAM_FD, "Invalid data %pK %pK", data, priv); + return -EINVAL; + } + + hw_mgr = (struct cam_fd_hw_mgr *)priv; + work_data = (struct cam_fd_mgr_work_data *)data; + irq_type = work_data->irq_type; + + CAM_DBG(CAM_FD, "FD IRQ type=%d", irq_type); + + if (irq_type == CAM_FD_IRQ_HALT_DONE) { + /* HALT would be followed by a RESET, ignore this */ + CAM_DBG(CAM_FD, "HALT IRQ callback"); + return 0; + } + + /* Get the frame from processing list */ + rc = cam_fd_mgr_util_get_frame_req(&hw_mgr->frame_processing_list, + &frame_req); + if (rc || !frame_req) { + /* + * This can happen if reset is triggered while no frames + * were pending, so not an error, just continue to check if + * there are any pending frames and submit + */ + CAM_DBG(CAM_FD, "No Frame in processing list, rc=%d", rc); + goto submit_next_frame; + } + + if (!frame_req->hw_ctx) { + CAM_ERR(CAM_FD, "Invalid Frame request %lld", + frame_req->request_id); + goto put_req_in_free_list; + } + + rc = cam_fd_mgr_util_get_device(hw_mgr, frame_req->hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + goto put_req_in_free_list; + } + + /* Read frame results first */ + if (irq_type == CAM_FD_IRQ_FRAME_DONE) { + struct cam_fd_hw_frame_done_args frame_done_args; + + CAM_DBG(CAM_FD, "FrameDone : Frame[%lld]", + frame_req->request_id); + + frame_done_args.hw_ctx = frame_req->hw_ctx; + frame_done_args.ctx_hw_private = + frame_req->hw_ctx->ctx_hw_private; + frame_done_args.request_id = frame_req->request_id; + frame_done_args.hw_req_private = &frame_req->hw_req_private; + + if (hw_device->hw_intf->hw_ops.process_cmd) { + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, + CAM_FD_HW_CMD_FRAME_DONE, + &frame_done_args, sizeof(frame_done_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in CMD_PRESTART %d", + rc); + frame_abort = true; + goto notify_context; + } + } + + frame_abort = false; + } + + trace_cam_irq_handled("FD", irq_type); + +notify_context: + /* Do a callback to inform frame done or stop done */ + if (frame_req->hw_ctx->event_cb) { + struct cam_hw_done_event_data buf_data; + + CAM_DBG(CAM_FD, "FrameHALT : Frame[%lld]", + frame_req->request_id); + + buf_data.num_handles = frame_req->num_hw_update_entries; + buf_data.request_id = frame_req->request_id; + + rc = frame_req->hw_ctx->event_cb(frame_req->hw_ctx->cb_priv, + frame_abort, &buf_data); + if (rc) + CAM_ERR(CAM_FD, "Error in event cb handling %d", rc); + } + + /* + * Now we can set hw device is free to process further frames. + * Note - Do not change state to IDLE until we read the frame results, + * Otherwise, other thread may schedule frame processing before + * reading current frame's results. Also, we need to set to IDLE state + * in case some error happens after getting this irq callback + */ + mutex_lock(&hw_device->lock); + hw_device->ready_to_process = true; + hw_device->req_id = -1; + hw_device->cur_hw_ctx = NULL; + CAM_DBG(CAM_FD, "ready_to_process=%d", hw_device->ready_to_process); + mutex_unlock(&hw_device->lock); + +put_req_in_free_list: + rc = cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req); + if (rc) { + CAM_ERR(CAM_FD, "Failed in putting frame req in free list"); + /* continue */ + } + +submit_next_frame: + /* Check if there are any frames pending for processing and submit */ + rc = cam_fd_mgr_util_submit_frame(hw_mgr, NULL); + if (rc) { + CAM_ERR(CAM_FD, "Error while submit frame, rc=%d", rc); + return rc; + } + + return rc; +} + +static int cam_fd_mgr_irq_cb(void *data, enum cam_fd_hw_irq_type irq_type) +{ + struct cam_fd_hw_mgr *hw_mgr = &g_fd_hw_mgr; + int rc = 0; + unsigned long flags; + struct crm_workq_task *task; + struct cam_fd_mgr_work_data *work_data; + + spin_lock_irqsave(&hw_mgr->hw_mgr_slock, flags); + task = cam_req_mgr_workq_get_task(hw_mgr->work); + if (!task) { + CAM_ERR(CAM_FD, "no empty task available"); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_slock, flags); + return -ENOMEM; + } + + work_data = (struct cam_fd_mgr_work_data *)task->payload; + work_data->type = CAM_FD_WORK_IRQ; + work_data->irq_type = irq_type; + + task->process_cb = cam_fd_mgr_workq_irq_cb; + rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0); + if (rc) + CAM_ERR(CAM_FD, "Failed in enqueue work task, rc=%d", rc); + + spin_unlock_irqrestore(&hw_mgr->hw_mgr_slock, flags); + + return rc; +} + +static int cam_fd_mgr_hw_get_caps(void *hw_mgr_priv, void *hw_get_caps_args) +{ + int rc = 0; + struct cam_fd_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query = hw_get_caps_args; + struct cam_fd_query_cap_cmd query_fd; + void __user *caps_handle = + u64_to_user_ptr(query->caps_handle); + + if (copy_from_user(&query_fd, caps_handle, + sizeof(struct cam_fd_query_cap_cmd))) { + CAM_ERR(CAM_FD, "Failed in copy from user, rc=%d", rc); + return -EFAULT; + } + + query_fd = hw_mgr->fd_caps; + + CAM_DBG(CAM_FD, + "IOMMU device(%d, %d), CDM(%d, %d), versions %d.%d, %d.%d", + query_fd.device_iommu.secure, query_fd.device_iommu.non_secure, + query_fd.cdm_iommu.secure, query_fd.cdm_iommu.non_secure, + query_fd.hw_caps.core_version.major, + query_fd.hw_caps.core_version.minor, + query_fd.hw_caps.wrapper_version.major, + query_fd.hw_caps.wrapper_version.minor); + + if (copy_to_user(caps_handle, &query_fd, + sizeof(struct cam_fd_query_cap_cmd))) + rc = -EFAULT; + + return rc; +} + +static int cam_fd_mgr_hw_acquire(void *hw_mgr_priv, void *hw_acquire_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = + (struct cam_hw_acquire_args *)hw_acquire_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_acquire_dev_info fd_acquire_args; + int rc; + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_FD, "Invalid acquire args %pK", acquire_args); + return -EINVAL; + } + + if (copy_from_user(&fd_acquire_args, + (void __user *)acquire_args->acquire_info, + sizeof(struct cam_fd_acquire_dev_info))) { + CAM_ERR(CAM_FD, "Copy from user failed"); + return -EFAULT; + } + + CAM_DBG(CAM_FD, "Acquire : mode=%d, get_raw_results=%d, priority=%d", + fd_acquire_args.mode, fd_acquire_args.get_raw_results, + fd_acquire_args.priority); + + /* get a free fd hw mgr ctx */ + rc = cam_fd_mgr_util_get_ctx(&hw_mgr->free_ctx_list, &hw_ctx); + if (rc || !hw_ctx) { + CAM_ERR(CAM_FD, "Get hw context failed, rc=%d, hw_ctx=%pK", + rc, hw_ctx); + return -EINVAL; + } + + if (fd_acquire_args.get_raw_results && !hw_mgr->raw_results_available) { + CAM_ERR(CAM_FD, "HW cannot support raw results %d (%d)", + fd_acquire_args.get_raw_results, + hw_mgr->raw_results_available); + goto put_ctx; + } + + if (!(fd_acquire_args.mode & hw_mgr->supported_modes)) { + CAM_ERR(CAM_FD, "HW cannot support requested mode 0x%x (0x%x)", + fd_acquire_args.mode, hw_mgr->supported_modes); + rc = -EPERM; + goto put_ctx; + } + + rc = cam_fd_mgr_util_select_device(hw_mgr, hw_ctx, &fd_acquire_args); + if (rc) { + CAM_ERR(CAM_FD, "Failed in selecting device, rc=%d", rc); + goto put_ctx; + } + + hw_ctx->ctx_in_use = true; + hw_ctx->hw_mgr = hw_mgr; + hw_ctx->get_raw_results = fd_acquire_args.get_raw_results; + hw_ctx->mode = fd_acquire_args.mode; + + /* Save incoming cam core info into hw ctx*/ + hw_ctx->cb_priv = acquire_args->context_data; + hw_ctx->event_cb = acquire_args->event_cb; + + /* Update out args */ + acquire_args->ctxt_to_hw_map = hw_ctx; + + cam_fd_mgr_util_put_ctx(&hw_mgr->used_ctx_list, &hw_ctx); + + return 0; +put_ctx: + list_del_init(&hw_ctx->list); + cam_fd_mgr_util_put_ctx(&hw_mgr->free_ctx_list, &hw_ctx); + return rc; +} + +static int cam_fd_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_release_args *release_args = hw_release_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + int rc; + + if (!hw_mgr_priv || !hw_release_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK, %pK", + hw_mgr_priv, hw_release_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)release_args->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + rc = cam_fd_mgr_util_release_device(hw_mgr, hw_ctx); + if (rc) + CAM_ERR(CAM_FD, "Failed in release device, rc=%d", rc); + + hw_ctx->ctx_in_use = false; + list_del_init(&hw_ctx->list); + cam_fd_mgr_util_put_ctx(&hw_mgr->free_ctx_list, &hw_ctx); + + return 0; +} + +static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) +{ + int rc = 0; + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_start_args *hw_mgr_start_args = + (struct cam_hw_start_args *)mgr_start_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_hw_init_args hw_init_args; + + if (!hw_mgr_priv || !hw_mgr_start_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", + hw_mgr_priv, hw_mgr_start_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)hw_mgr_start_args->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + CAM_DBG(CAM_FD, "ctx index=%u, device_index=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + if (hw_device->hw_intf->hw_ops.init) { + hw_init_args.hw_ctx = hw_ctx; + hw_init_args.ctx_hw_private = hw_ctx->ctx_hw_private; + rc = hw_device->hw_intf->hw_ops.init( + hw_device->hw_intf->hw_priv, &hw_init_args, + sizeof(hw_init_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW Init %d", rc); + return rc; + } + } else { + CAM_ERR(CAM_FD, "Invalid init function"); + return -EINVAL; + } + + return rc; +} + +static int cam_fd_mgr_hw_flush_req(void *hw_mgr_priv, + struct cam_hw_flush_args *flush_args) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *frame_req, *req_temp, *flush_req; + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_fd_device *hw_device; + struct cam_fd_hw_stop_args hw_stop_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + uint32_t i = 0; + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)flush_args->ctxt_to_hw_map; + + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + CAM_DBG(CAM_FD, "ctx index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_mgr->frame_req_mutex); + for (i = 0; i < flush_args->num_req_active; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_active[i]; + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_high, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + if (frame_req->request_id != flush_req->request_id) + continue; + + list_del_init(&frame_req->list); + break; + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_normal, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + if (frame_req->request_id != flush_req->request_id) + continue; + + list_del_init(&frame_req->list); + break; + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_processing_list, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + if (frame_req->request_id != flush_req->request_id) + continue; + + list_del_init(&frame_req->list); + + mutex_lock(&hw_device->lock); + if ((hw_device->ready_to_process == true) || + (hw_device->cur_hw_ctx != hw_ctx)) + goto unlock_dev_flush_req; + + if (hw_device->hw_intf->hw_ops.stop) { + hw_stop_args.hw_ctx = hw_ctx; + rc = hw_device->hw_intf->hw_ops.stop( + hw_device->hw_intf->hw_priv, + &hw_stop_args, + sizeof(hw_stop_args)); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in HW Stop %d", rc); + goto unlock_dev_flush_req; + } + hw_device->ready_to_process = true; + } + +unlock_dev_flush_req: + mutex_unlock(&hw_device->lock); + break; + } + } + mutex_unlock(&hw_mgr->frame_req_mutex); + + for (i = 0; i < flush_args->num_req_pending; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_pending[i]; + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + return rc; +} + +static int cam_fd_mgr_hw_flush_ctx(void *hw_mgr_priv, + struct cam_hw_flush_args *flush_args) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *frame_req, *req_temp, *flush_req; + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_fd_device *hw_device; + struct cam_fd_hw_stop_args hw_stop_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + uint32_t i = 0; + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)flush_args->ctxt_to_hw_map; + + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + CAM_DBG(CAM_FD, "ctx index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_mgr->frame_req_mutex); + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_high, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + list_del_init(&frame_req->list); + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_normal, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + list_del_init(&frame_req->list); + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_processing_list, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + list_del_init(&frame_req->list); + mutex_lock(&hw_device->lock); + if ((hw_device->ready_to_process == true) || + (hw_device->cur_hw_ctx != hw_ctx)) + goto unlock_dev_flush_ctx; + + if (hw_device->hw_intf->hw_ops.stop) { + hw_stop_args.hw_ctx = hw_ctx; + rc = hw_device->hw_intf->hw_ops.stop( + hw_device->hw_intf->hw_priv, &hw_stop_args, + sizeof(hw_stop_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW Stop %d", rc); + goto unlock_dev_flush_ctx; + } + hw_device->ready_to_process = true; + } + +unlock_dev_flush_ctx: + mutex_unlock(&hw_device->lock); + } + mutex_unlock(&hw_mgr->frame_req_mutex); + + for (i = 0; i < flush_args->num_req_pending; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_pending[i]; + CAM_DBG(CAM_FD, "flush pending req %llu", + flush_req->request_id); + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + for (i = 0; i < flush_args->num_req_active; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_active[i]; + CAM_DBG(CAM_FD, "flush active req %llu", flush_req->request_id); + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + return rc; +} + +static int cam_fd_mgr_hw_flush(void *hw_mgr_priv, + void *hw_flush_args) +{ + int rc = 0; + struct cam_hw_flush_args *flush_args = + (struct cam_hw_flush_args *)hw_flush_args; + + if (!hw_mgr_priv || !hw_flush_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", + hw_mgr_priv, hw_flush_args); + return -EINVAL; + } + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_REQ: + rc = cam_fd_mgr_hw_flush_req(hw_mgr_priv, flush_args); + break; + case CAM_FLUSH_TYPE_ALL: + rc = cam_fd_mgr_hw_flush_ctx(hw_mgr_priv, flush_args); + break; + default: + rc = -EINVAL; + CAM_ERR(CAM_FD, "Invalid flush type %d", + flush_args->flush_type); + break; + } + return rc; +} + +static int cam_fd_mgr_hw_stop(void *hw_mgr_priv, void *mgr_stop_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_stop_args *hw_mgr_stop_args = + (struct cam_hw_stop_args *)mgr_stop_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_hw_deinit_args hw_deinit_args; + int rc = 0; + + if (!hw_mgr_priv || !hw_mgr_stop_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", + hw_mgr_priv, hw_mgr_stop_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)hw_mgr_stop_args->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + CAM_DBG(CAM_FD, "ctx index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + CAM_DBG(CAM_FD, "FD Device ready_to_process = %d", + hw_device->ready_to_process); + + if (hw_device->hw_intf->hw_ops.deinit) { + hw_deinit_args.hw_ctx = hw_ctx; + hw_deinit_args.ctx_hw_private = hw_ctx->ctx_hw_private; + rc = hw_device->hw_intf->hw_ops.deinit( + hw_device->hw_intf->hw_priv, &hw_deinit_args, + sizeof(hw_deinit_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW DeInit %d", rc); + return rc; + } + } + + return rc; +} + +static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv, + void *hw_prepare_update_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_prepare_update_args *prepare = + (struct cam_hw_prepare_update_args *) hw_prepare_update_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_kmd_buf_info kmd_buf; + int rc; + struct cam_fd_hw_cmd_prestart_args prestart_args; + struct cam_fd_mgr_frame_request *frame_req; + + if (!hw_mgr_priv || !hw_prepare_update_args) { + CAM_ERR(CAM_FD, "Invalid args %pK %pK", + hw_mgr_priv, hw_prepare_update_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)prepare->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + goto error; + } + + rc = cam_fd_mgr_util_packet_validate(prepare->packet, + prepare->remain_len); + if (rc) { + CAM_ERR(CAM_FD, "Error in packet validation %d", rc); + goto error; + } + + rc = cam_packet_util_get_kmd_buffer(prepare->packet, &kmd_buf); + if (rc) { + CAM_ERR(CAM_FD, "Error in get kmd buf buffer %d", rc); + goto error; + } + + CAM_DBG(CAM_FD, + "KMD Buf : hdl=%d, cpu_addr=%pK, offset=%d, size=%d, used=%d", + kmd_buf.handle, kmd_buf.cpu_addr, kmd_buf.offset, + kmd_buf.size, kmd_buf.used_bytes); + + /* We do not expect any patching, but just do it anyway */ + rc = cam_packet_util_process_patches(prepare->packet, + hw_mgr->device_iommu.non_secure, -1); + if (rc) { + CAM_ERR(CAM_FD, "Patch FD packet failed, rc=%d", rc); + return rc; + } + + memset(&prestart_args, 0x0, sizeof(prestart_args)); + prestart_args.ctx_hw_private = hw_ctx->ctx_hw_private; + prestart_args.hw_ctx = hw_ctx; + prestart_args.request_id = prepare->packet->header.request_id; + + rc = cam_fd_mgr_util_parse_generic_cmd_buffer(hw_ctx, prepare->packet, + &prestart_args); + if (rc) { + CAM_ERR(CAM_FD, "Error in parsing gerneric cmd buffer %d", rc); + goto error; + } + + rc = cam_fd_mgr_util_prepare_io_buf_info( + hw_mgr->device_iommu.non_secure, prepare, + prestart_args.input_buf, prestart_args.output_buf, + CAM_FD_MAX_IO_BUFFERS); + if (rc) { + CAM_ERR(CAM_FD, "Error in prepare IO Buf %d", rc); + goto error; + } + + rc = cam_fd_mgr_util_prepare_hw_update_entries(hw_mgr, prepare, + &prestart_args, &kmd_buf); + if (rc) { + CAM_ERR(CAM_FD, "Error in hw update entries %d", rc); + goto error; + } + + /* get a free frame req from free list */ + rc = cam_fd_mgr_util_get_frame_req(&hw_mgr->frame_free_list, + &frame_req); + if (rc || !frame_req) { + CAM_ERR(CAM_FD, "Get frame_req failed, rc=%d, hw_ctx=%pK", + rc, hw_ctx); + return -ENOMEM; + } + + /* Setup frame request info and queue to pending list */ + frame_req->hw_ctx = hw_ctx; + frame_req->request_id = prepare->packet->header.request_id; + /* This has to be passed to HW while calling hw_ops->start */ + frame_req->hw_req_private = prestart_args.hw_req_private; + + /* + * Save the current frame_req into priv, + * this will come as priv while hw_config + */ + prepare->priv = frame_req; + + CAM_DBG(CAM_FD, "FramePrepare : Frame[%lld]", frame_req->request_id); + + return 0; +error: + return rc; +} + +static int cam_fd_mgr_hw_config(void *hw_mgr_priv, void *hw_config_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_config_args *config = + (struct cam_hw_config_args *) hw_config_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_mgr_frame_request *frame_req; + int rc; + int i; + + if (!hw_mgr || !config) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", hw_mgr, config); + return -EINVAL; + } + + if (!config->num_hw_update_entries) { + CAM_ERR(CAM_FD, "No hw update enteries are available"); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)config->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + frame_req = config->priv; + + trace_cam_apply_req("FD", frame_req->request_id); + CAM_DBG(CAM_FD, "FrameHWConfig : Frame[%lld]", frame_req->request_id); + + frame_req->num_hw_update_entries = config->num_hw_update_entries; + for (i = 0; i < config->num_hw_update_entries; i++) { + frame_req->hw_update_entries[i] = config->hw_update_entries[i]; + CAM_DBG(CAM_FD, "PreStart HWEntry[%d] : %d %d %d %d %pK", + frame_req->hw_update_entries[i].handle, + frame_req->hw_update_entries[i].offset, + frame_req->hw_update_entries[i].len, + frame_req->hw_update_entries[i].flags, + frame_req->hw_update_entries[i].addr); + } + + if (hw_ctx->priority == CAM_FD_PRIORITY_HIGH) { + CAM_DBG(CAM_FD, "Insert frame into prio0 queue"); + rc = cam_fd_mgr_util_put_frame_req( + &hw_mgr->frame_pending_list_high, &frame_req); + } else { + CAM_DBG(CAM_FD, "Insert frame into prio1 queue"); + rc = cam_fd_mgr_util_put_frame_req( + &hw_mgr->frame_pending_list_normal, &frame_req); + } + if (rc) { + CAM_ERR(CAM_FD, "Failed in queuing frame req, rc=%d", rc); + goto put_free_list; + } + + rc = cam_fd_mgr_util_schedule_frame_worker_task(hw_mgr); + if (rc) { + CAM_ERR(CAM_FD, "Worker task scheduling failed %d", rc); + goto remove_and_put_free_list; + } + + return 0; + +remove_and_put_free_list: + + if (hw_ctx->priority == CAM_FD_PRIORITY_HIGH) { + CAM_DBG(CAM_FD, "Removing frame into prio0 queue"); + cam_fd_mgr_util_get_frame_req( + &hw_mgr->frame_pending_list_high, &frame_req); + } else { + CAM_DBG(CAM_FD, "Removing frame into prio1 queue"); + cam_fd_mgr_util_get_frame_req( + &hw_mgr->frame_pending_list_normal, &frame_req); + } +put_free_list: + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req); + + return rc; +} + +int cam_fd_hw_mgr_deinit(struct device_node *of_node) +{ + CAM_DBG(CAM_FD, "HW Mgr Deinit"); + + cam_req_mgr_workq_destroy(&g_fd_hw_mgr.work); + + cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure); + g_fd_hw_mgr.device_iommu.non_secure = -1; + + mutex_destroy(&g_fd_hw_mgr.ctx_mutex); + mutex_destroy(&g_fd_hw_mgr.frame_req_mutex); + mutex_destroy(&g_fd_hw_mgr.hw_mgr_mutex); + + return 0; +} + +int cam_fd_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf) +{ + int count, i, rc = 0; + struct cam_hw_intf *hw_intf = NULL; + struct cam_fd_hw_mgr_ctx *hw_mgr_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_mgr_frame_request *frame_req; + + if (!of_node || !hw_mgr_intf) { + CAM_ERR(CAM_FD, "Invalid args of_node %pK hw_mgr_intf %pK", + of_node, hw_mgr_intf); + return -EINVAL; + } + + memset(&g_fd_hw_mgr, 0x0, sizeof(g_fd_hw_mgr)); + memset(hw_mgr_intf, 0x0, sizeof(*hw_mgr_intf)); + + mutex_init(&g_fd_hw_mgr.ctx_mutex); + mutex_init(&g_fd_hw_mgr.frame_req_mutex); + mutex_init(&g_fd_hw_mgr.hw_mgr_mutex); + spin_lock_init(&g_fd_hw_mgr.hw_mgr_slock); + + count = of_property_count_strings(of_node, "compat-hw-name"); + if (!count || (count > CAM_FD_HW_MAX)) { + CAM_ERR(CAM_FD, "Invalid compat names in dev tree %d", count); + return -EINVAL; + } + g_fd_hw_mgr.num_devices = count; + + g_fd_hw_mgr.raw_results_available = false; + g_fd_hw_mgr.supported_modes = 0; + + for (i = 0; i < count; i++) { + hw_device = &g_fd_hw_mgr.hw_device[i]; + + rc = cam_fd_mgr_util_pdev_get_hw_intf(of_node, i, &hw_intf); + if (rc) { + CAM_ERR(CAM_FD, "hw intf from pdev failed, rc=%d", rc); + return rc; + } + + mutex_init(&hw_device->lock); + + hw_device->valid = true; + hw_device->hw_intf = hw_intf; + hw_device->ready_to_process = true; + + if (hw_device->hw_intf->hw_ops.process_cmd) { + struct cam_fd_hw_cmd_set_irq_cb irq_cb_args; + + irq_cb_args.cam_fd_hw_mgr_cb = cam_fd_mgr_irq_cb; + irq_cb_args.data = hw_device; + + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, + CAM_FD_HW_CMD_REGISTER_CALLBACK, + &irq_cb_args, sizeof(irq_cb_args)); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in REGISTER_CALLBACK %d", rc); + return rc; + } + } + + if (hw_device->hw_intf->hw_ops.get_hw_caps) { + rc = hw_device->hw_intf->hw_ops.get_hw_caps( + hw_intf->hw_priv, &hw_device->hw_caps, + sizeof(hw_device->hw_caps)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in get_hw_caps %d", rc); + return rc; + } + + g_fd_hw_mgr.raw_results_available |= + hw_device->hw_caps.raw_results_available; + g_fd_hw_mgr.supported_modes |= + hw_device->hw_caps.supported_modes; + + CAM_DBG(CAM_FD, + "Device[mode=%d, raw=%d], Mgr[mode=%d, raw=%d]", + hw_device->hw_caps.supported_modes, + hw_device->hw_caps.raw_results_available, + g_fd_hw_mgr.supported_modes, + g_fd_hw_mgr.raw_results_available); + } + } + + INIT_LIST_HEAD(&g_fd_hw_mgr.free_ctx_list); + INIT_LIST_HEAD(&g_fd_hw_mgr.used_ctx_list); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_free_list); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_pending_list_high); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_pending_list_normal); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_processing_list); + + g_fd_hw_mgr.device_iommu.non_secure = -1; + g_fd_hw_mgr.device_iommu.secure = -1; + g_fd_hw_mgr.cdm_iommu.non_secure = -1; + g_fd_hw_mgr.cdm_iommu.secure = -1; + + rc = cam_smmu_get_handle("fd", + &g_fd_hw_mgr.device_iommu.non_secure); + if (rc) { + CAM_ERR(CAM_FD, "Get iommu handle failed, rc=%d", rc); + goto destroy_mutex; + } + + rc = cam_cdm_get_iommu_handle("fd", &g_fd_hw_mgr.cdm_iommu); + if (rc) + CAM_DBG(CAM_FD, "Failed to acquire the CDM iommu handles"); + + CAM_DBG(CAM_FD, "iommu handles : device(%d, %d), cdm(%d, %d)", + g_fd_hw_mgr.device_iommu.non_secure, + g_fd_hw_mgr.device_iommu.secure, + g_fd_hw_mgr.cdm_iommu.non_secure, + g_fd_hw_mgr.cdm_iommu.secure); + + /* Init hw mgr contexts and add to free list */ + for (i = 0; i < CAM_CTX_MAX; i++) { + hw_mgr_ctx = &g_fd_hw_mgr.ctx_pool[i]; + + memset(hw_mgr_ctx, 0x0, sizeof(*hw_mgr_ctx)); + INIT_LIST_HEAD(&hw_mgr_ctx->list); + + hw_mgr_ctx->ctx_index = i; + hw_mgr_ctx->device_index = -1; + hw_mgr_ctx->hw_mgr = &g_fd_hw_mgr; + + list_add_tail(&hw_mgr_ctx->list, &g_fd_hw_mgr.free_ctx_list); + } + + /* Init hw mgr frame requests and add to free list */ + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + frame_req = &g_fd_hw_mgr.frame_req[i]; + + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->list); + + list_add_tail(&frame_req->list, &g_fd_hw_mgr.frame_free_list); + } + + rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK, + &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc); + goto detach_smmu; + } + + for (i = 0; i < CAM_FD_WORKQ_NUM_TASK; i++) + g_fd_hw_mgr.work->task.pool[i].payload = + &g_fd_hw_mgr.work_data[i]; + + /* Setup hw cap so that we can just return the info when requested */ + memset(&g_fd_hw_mgr.fd_caps, 0, sizeof(g_fd_hw_mgr.fd_caps)); + g_fd_hw_mgr.fd_caps.device_iommu = g_fd_hw_mgr.device_iommu; + g_fd_hw_mgr.fd_caps.cdm_iommu = g_fd_hw_mgr.cdm_iommu; + g_fd_hw_mgr.fd_caps.hw_caps = g_fd_hw_mgr.hw_device[0].hw_caps; + + CAM_DBG(CAM_FD, + "IOMMU device(%d, %d), CDM(%d, %d) versions core[%d.%d], wrapper[%d.%d]", + g_fd_hw_mgr.fd_caps.device_iommu.secure, + g_fd_hw_mgr.fd_caps.device_iommu.non_secure, + g_fd_hw_mgr.fd_caps.cdm_iommu.secure, + g_fd_hw_mgr.fd_caps.cdm_iommu.non_secure, + g_fd_hw_mgr.fd_caps.hw_caps.core_version.major, + g_fd_hw_mgr.fd_caps.hw_caps.core_version.minor, + g_fd_hw_mgr.fd_caps.hw_caps.wrapper_version.major, + g_fd_hw_mgr.fd_caps.hw_caps.wrapper_version.minor); + + hw_mgr_intf->hw_mgr_priv = &g_fd_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_fd_mgr_hw_get_caps; + hw_mgr_intf->hw_acquire = cam_fd_mgr_hw_acquire; + hw_mgr_intf->hw_release = cam_fd_mgr_hw_release; + hw_mgr_intf->hw_start = cam_fd_mgr_hw_start; + hw_mgr_intf->hw_stop = cam_fd_mgr_hw_stop; + hw_mgr_intf->hw_prepare_update = cam_fd_mgr_hw_prepare_update; + hw_mgr_intf->hw_config = cam_fd_mgr_hw_config; + hw_mgr_intf->hw_read = NULL; + hw_mgr_intf->hw_write = NULL; + hw_mgr_intf->hw_close = NULL; + hw_mgr_intf->hw_flush = cam_fd_mgr_hw_flush; + + return rc; + +detach_smmu: + cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure); + g_fd_hw_mgr.device_iommu.non_secure = -1; +destroy_mutex: + mutex_destroy(&g_fd_hw_mgr.ctx_mutex); + mutex_destroy(&g_fd_hw_mgr.frame_req_mutex); + mutex_destroy(&g_fd_hw_mgr.hw_mgr_mutex); + + return rc; +} diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h new file mode 100644 index 000000000000..351cae971a42 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_MGR_H_ +#define _CAM_FD_HW_MGR_H_ + +#include +#include + +#include +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_workq.h" +#include "cam_fd_hw_intf.h" + +#define CAM_FD_HW_MAX 1 +#define CAM_FD_WORKQ_NUM_TASK 10 + +struct cam_fd_hw_mgr; + +/** + * enum cam_fd_mgr_work_type - Type of worker task + * + * @CAM_FD_WORK_FRAME : Work type indicating frame task + * @CAM_FD_WORK_IRQ : Work type indicating irq task + */ +enum cam_fd_mgr_work_type { + CAM_FD_WORK_FRAME, + CAM_FD_WORK_IRQ, +}; + +/** + * struct cam_fd_hw_mgr_ctx : FD HW Mgr context + * + * @list : List pointer used to maintain this context + * in free, used list + * @ctx_index : Index of this context + * @ctx_in_use : Whether this context is in use + * @event_cb : Event callback pointer to notify cam core context + * @cb_priv : Event callback private pointer + * @hw_mgr : Pointer to hw manager + * @get_raw_results : Whether this context needs raw results + * @mode : Mode in which this context runs + * @device_index : HW Device used by this context + * @ctx_hw_private : HW layer's private context pointer for this context + * @priority : Priority of this context + */ +struct cam_fd_hw_mgr_ctx { + struct list_head list; + uint32_t ctx_index; + bool ctx_in_use; + cam_hw_event_cb_func event_cb; + void *cb_priv; + struct cam_fd_hw_mgr *hw_mgr; + bool get_raw_results; + enum cam_fd_hw_mode mode; + int32_t device_index; + void *ctx_hw_private; + uint32_t priority; +}; + +/** + * struct cam_fd_device : FD HW Device + * + * @hw_caps : This FD device's capabilities + * @hw_intf : FD device's interface information + * @ready_to_process : Whether this device is ready to process next frame + * @num_ctxts : Number of context currently running on this device + * @valid : Whether this device is valid + * @lock : Lock used for protectin + * @cur_hw_ctx : current hw context running in the device + * @req_id : current processing req id + */ +struct cam_fd_device { + struct cam_fd_hw_caps hw_caps; + struct cam_hw_intf *hw_intf; + bool ready_to_process; + uint32_t num_ctxts; + bool valid; + struct mutex lock; + struct cam_fd_hw_mgr_ctx *cur_hw_ctx; + int64_t req_id; +}; + +/** + * struct cam_fd_mgr_frame_request : Frame request information maintained + * in HW Mgr layer + * + * @list : List pointer used to maintain this request in + * free, pending, processing request lists + * @request_id : Request ID corresponding to this request + * @hw_ctx : HW context from which this request is coming + * @hw_req_private : HW layer's private information specific to + * this request + * @hw_update_entries : HW update entries corresponding to this request + * which needs to be submitted to HW through CDM + * @num_hw_update_entries : Number of HW update entries + */ +struct cam_fd_mgr_frame_request { + struct list_head list; + uint64_t request_id; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_hw_req_private hw_req_private; + struct cam_hw_update_entry hw_update_entries[CAM_FD_MAX_HW_ENTRIES]; + uint32_t num_hw_update_entries; +}; + +/** + * struct cam_fd_mgr_work_data : HW Mgr work data information + * + * @type : Type of work + * @irq_type : IRQ type when this work is queued because of irq callback + */ +struct cam_fd_mgr_work_data { + enum cam_fd_mgr_work_type type; + enum cam_fd_hw_irq_type irq_type; +}; + +/** + * struct cam_fd_hw_mgr : FD HW Mgr information + * + * @free_ctx_list : List of free contexts available for acquire + * @used_ctx_list : List of contexts that are acquired + * @frame_free_list : List of free frame requests available + * @frame_pending_list_high : List of high priority frame requests pending + * for processing + * @frame_pending_list_normal : List of normal priority frame requests pending + * for processing + * @frame_processing_list : List of frame requests currently being + * processed currently. Generally maximum one + * request would be present in this list + * @hw_mgr_mutex : Mutex to protect hw mgr data when accessed + * from multiple threads + * @hw_mgr_slock : Spin lock to protect hw mgr data when accessed + * from multiple threads + * @ctx_mutex : Mutex to protect context list + * @frame_req_mutex : Mutex to protect frame request list + * @device_iommu : Device IOMMU information + * @cdm_iommu : CDM IOMMU information + * @hw_device : Underlying HW device information + * @num_devices : Number of HW devices available + * @raw_results_available : Whether raw results available in this driver + * @supported_modes : Supported modes by this driver + * @ctx_pool : List of context + * @frame_req : List of frame requests + * @work : Worker handle + * @work_data : Worker data + * @fd_caps : FD driver capabilities + */ +struct cam_fd_hw_mgr { + struct list_head free_ctx_list; + struct list_head used_ctx_list; + struct list_head frame_free_list; + struct list_head frame_pending_list_high; + struct list_head frame_pending_list_normal; + struct list_head frame_processing_list; + struct mutex hw_mgr_mutex; + spinlock_t hw_mgr_slock; + struct mutex ctx_mutex; + struct mutex frame_req_mutex; + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_fd_device hw_device[CAM_FD_HW_MAX]; + uint32_t num_devices; + bool raw_results_available; + uint32_t supported_modes; + struct cam_fd_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; + struct cam_fd_mgr_frame_request frame_req[CAM_CTX_REQ_MAX]; + struct cam_req_mgr_core_workq *work; + struct cam_fd_mgr_work_data work_data[CAM_FD_WORKQ_NUM_TASK]; + struct cam_fd_query_cap_cmd fd_caps; +}; + +#endif /* _CAM_FD_HW_MGR_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h new file mode 100644 index 000000000000..81ed464e400a --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_MGR_INTF_H_ +#define _CAM_FD_HW_MGR_INTF_H_ + +#include + +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" + +int cam_fd_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf); +int cam_fd_hw_mgr_deinit(struct device_node *of_node); + +#endif /* _CAM_FD_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile b/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile new file mode 100644 index 000000000000..fd43ca7a4546 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -I$(srctree)/techpack/camera +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_dev.o cam_fd_hw_core.o cam_fd_hw_soc.o diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c new file mode 100644 index 000000000000..c28fcdf3efc6 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -0,0 +1,1164 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" +#include "cam_trace.h" + +#define CAM_FD_REG_VAL_PAIR_SIZE 256 + +static uint32_t cam_fd_cdm_write_reg_val_pair(uint32_t *buffer, + uint32_t index, uint32_t reg_offset, uint32_t reg_value) +{ + buffer[index++] = reg_offset; + buffer[index++] = reg_value; + + CAM_DBG(CAM_FD, "FD_CDM_CMD: Base[FD_CORE] Offset[0x%8x] Value[0x%8x]", + reg_offset, reg_value); + + return index; +} + +static void cam_fd_hw_util_cdm_callback(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie) +{ + trace_cam_cdm_cb("FD", status); + CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); +} + +static void cam_fd_hw_util_enable_power_on_settings(struct cam_hw_info *fd_hw) +{ + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + struct cam_fd_hw_static_info *hw_static_info = + ((struct cam_fd_core *)fd_hw->core_info)->hw_static_info; + + if (hw_static_info->enable_errata_wa.single_irq_only == false) { + /* Enable IRQs here */ + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + hw_static_info->irq_mask); + } + + /* QoS settings */ + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.vbif_req_priority, + hw_static_info->qos_priority); + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.vbif_priority_level, + hw_static_info->qos_priority_level); +} + +int cam_fd_hw_util_get_hw_caps(struct cam_hw_info *fd_hw, + struct cam_fd_hw_caps *hw_caps) +{ + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + struct cam_fd_hw_static_info *hw_static_info = + ((struct cam_fd_core *)fd_hw->core_info)->hw_static_info; + uint32_t reg_value; + + if (!hw_static_info) { + CAM_ERR(CAM_FD, "Invalid hw info data"); + return -EINVAL; + } + + reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_CORE, + hw_static_info->core_regs.version); + hw_caps->core_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf00, 0x8); + hw_caps->core_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0, 0x4); + hw_caps->core_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xf, 0x0); + + reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.wrapper_version); + hw_caps->wrapper_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c); + hw_caps->wrapper_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->wrapper_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + hw_caps->raw_results_available = + hw_static_info->results.raw_results_available; + hw_caps->supported_modes = hw_static_info->supported_modes; + + CAM_DBG(CAM_FD, "core:%d.%d.%d wrapper:%d.%d.%d intermediate:%d", + hw_caps->core_version.major, hw_caps->core_version.minor, + hw_caps->core_version.incr, hw_caps->wrapper_version.major, + hw_caps->wrapper_version.minor, hw_caps->wrapper_version.incr, + hw_caps->raw_results_available); + + return 0; +} + +static int cam_fd_hw_util_fdwrapper_sync_reset(struct cam_hw_info *fd_hw) +{ + struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info; + struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info; + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + long time_left; + + /* Before triggering reset to HW, clear the reset complete */ + reinit_completion(&fd_core->reset_complete); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE, + hw_static_info->core_regs.control, 0x1); + + if (hw_static_info->enable_errata_wa.single_irq_only) { + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE)); + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.sw_reset, 0x1); + + time_left = wait_for_completion_timeout(&fd_core->reset_complete, + msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT)); + if (time_left <= 0) + CAM_WARN(CAM_FD, "HW reset timeout time_left=%ld", time_left); + + CAM_DBG(CAM_FD, "FD Wrapper SW Sync Reset complete"); + + return 0; +} + + +static int cam_fd_hw_util_fdwrapper_halt(struct cam_hw_info *fd_hw) +{ + struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info; + struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info; + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + long time_left; + + /* Before triggering halt to HW, clear halt complete */ + reinit_completion(&fd_core->halt_complete); + + if (hw_static_info->enable_errata_wa.single_irq_only) { + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE)); + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.hw_stop, 0x1); + + time_left = wait_for_completion_timeout(&fd_core->halt_complete, + msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT)); + if (time_left <= 0) + CAM_WARN(CAM_FD, "HW halt timeout time_left=%ld", time_left); + + CAM_DBG(CAM_FD, "FD Wrapper Halt complete"); + + return 0; +} + +static int cam_fd_hw_util_processcmd_prestart(struct cam_hw_info *fd_hw, + struct cam_fd_hw_cmd_prestart_args *prestart_args) +{ + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + struct cam_fd_hw_static_info *hw_static_info = + ((struct cam_fd_core *)fd_hw->core_info)->hw_static_info; + struct cam_fd_ctx_hw_private *ctx_hw_private = + prestart_args->ctx_hw_private; + uint32_t size, size_required = 0; + uint32_t mem_base; + uint32_t *cmd_buf_addr = prestart_args->cmd_buf_addr; + uint32_t reg_val_pair[CAM_FD_REG_VAL_PAIR_SIZE]; + uint32_t num_cmds = 0; + int i; + struct cam_fd_hw_io_buffer *io_buf; + struct cam_fd_hw_req_private *req_private; + uint32_t available_size = prestart_args->size; + bool work_buffer_configured = false; + + if (!ctx_hw_private || !cmd_buf_addr) { + CAM_ERR(CAM_FD, "Invalid input prestart args %pK %pK", + ctx_hw_private, cmd_buf_addr); + return -EINVAL; + } + + if (prestart_args->get_raw_results && + !hw_static_info->results.raw_results_available) { + CAM_ERR(CAM_FD, "Raw results not supported %d %d", + prestart_args->get_raw_results, + hw_static_info->results.raw_results_available); + return -EINVAL; + } + + req_private = &prestart_args->hw_req_private; + req_private->ctx_hw_private = prestart_args->ctx_hw_private; + req_private->request_id = prestart_args->request_id; + req_private->get_raw_results = prestart_args->get_raw_results; + req_private->fd_results = NULL; + req_private->raw_results = NULL; + + /* Start preparing CDM register values that KMD has to insert */ + num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, num_cmds, + hw_static_info->core_regs.control, 0x1); + num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, num_cmds, + hw_static_info->core_regs.control, 0x0); + + for (i = 0; i < CAM_FD_MAX_IO_BUFFERS; i++) { + io_buf = &prestart_args->input_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_INPUT) { + CAM_ERR(CAM_FD, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + + switch (io_buf->io_cfg->resource_type) { + case CAM_FD_INPUT_PORT_ID_IMAGE: { + if ((num_cmds + 2) > CAM_FD_REG_VAL_PAIR_SIZE) { + CAM_ERR(CAM_FD, + "Invalid reg_val pair size %d, %d", + num_cmds, CAM_FD_REG_VAL_PAIR_SIZE); + return -EINVAL; + } + + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.image_addr, + io_buf->io_addr[0]); + break; + } + default: + CAM_ERR(CAM_FD, "Invalid resource type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + for (i = 0; i < CAM_FD_MAX_IO_BUFFERS; i++) { + io_buf = &prestart_args->output_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) { + CAM_ERR(CAM_FD, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + + switch (io_buf->io_cfg->resource_type) { + case CAM_FD_OUTPUT_PORT_ID_RESULTS: { + uint32_t face_results_offset; + + size_required = hw_static_info->results.max_faces * + hw_static_info->results.per_face_entries * 4; + + if (io_buf->io_cfg->planes[0].plane_stride < + size_required) { + CAM_ERR(CAM_FD, "Invalid results size %d %d", + io_buf->io_cfg->planes[0].plane_stride, + size_required); + return -EINVAL; + } + + req_private->fd_results = + (struct cam_fd_results *)io_buf->cpu_addr[0]; + + face_results_offset = + (uint8_t *)&req_private->fd_results->faces[0] - + (uint8_t *)req_private->fd_results; + + if (hw_static_info->ro_mode_supported) { + if ((num_cmds + 4) > CAM_FD_REG_VAL_PAIR_SIZE) { + CAM_ERR(CAM_FD, + "Invalid reg_val size %d, %d", + num_cmds, + CAM_FD_REG_VAL_PAIR_SIZE); + return -EINVAL; + } + /* + * Face data actually starts 16bytes later in + * the io buffer Check cam_fd_results. + */ + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.result_addr, + io_buf->io_addr[0] + + face_results_offset); + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.ro_mode, + 0x1); + + req_private->ro_mode_enabled = true; + } else { + req_private->ro_mode_enabled = false; + } + break; + } + case CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS: { + size_required = + hw_static_info->results.raw_results_entries * + sizeof(uint32_t); + + if (io_buf->io_cfg->planes[0].plane_stride < + size_required) { + CAM_ERR(CAM_FD, "Invalid results size %d %d", + io_buf->io_cfg->planes[0].plane_stride, + size_required); + return -EINVAL; + } + + req_private->raw_results = + (uint32_t *)io_buf->cpu_addr[0]; + break; + } + case CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER: { + if ((num_cmds + 2) > CAM_FD_REG_VAL_PAIR_SIZE) { + CAM_ERR(CAM_FD, + "Invalid reg_val pair size %d, %d", + num_cmds, CAM_FD_REG_VAL_PAIR_SIZE); + return -EINVAL; + } + + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.work_addr, + io_buf->io_addr[0]); + + work_buffer_configured = true; + break; + } + default: + CAM_ERR(CAM_FD, "Invalid resource type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + if (!req_private->fd_results || !work_buffer_configured) { + CAM_ERR(CAM_FD, "Invalid IO Buffers results=%pK work=%d", + req_private->fd_results, work_buffer_configured); + return -EINVAL; + } + + /* First insert CHANGE_BASE command */ + size = ctx_hw_private->cdm_ops->cdm_required_size_changebase(); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > available_size) { + CAM_ERR(CAM_FD, "buf size:%d is not sufficient, expected: %d", + prestart_args->size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, + ((struct cam_fd_soc_private *)soc_info->soc_private)-> + regbase_index[CAM_FD_REG_CORE]); + + ctx_hw_private->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base); + cmd_buf_addr += size; + available_size -= (size * 4); + + size = ctx_hw_private->cdm_ops->cdm_required_size_reg_random( + num_cmds/2); + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > available_size) { + CAM_ERR(CAM_FD, "Insufficient size:%d , expected size:%d", + available_size, size); + return -ENOMEM; + } + ctx_hw_private->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmds/2, + reg_val_pair); + cmd_buf_addr += size; + available_size -= (size * 4); + + /* Update pre_config_buf_size in bytes */ + prestart_args->pre_config_buf_size = + prestart_args->size - available_size; + + /* Insert start trigger command into CDM as post config commands. */ + num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, 0, + hw_static_info->core_regs.control, 0x2); + size = ctx_hw_private->cdm_ops->cdm_required_size_reg_random( + num_cmds/2); + if ((size * 4) > available_size) { + CAM_ERR(CAM_FD, "Insufficient size:%d , expected size:%d", + available_size, size); + return -ENOMEM; + } + ctx_hw_private->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmds/2, + reg_val_pair); + cmd_buf_addr += size; + available_size -= (size * 4); + + prestart_args->post_config_buf_size = size * 4; + + CAM_DBG(CAM_FD, "PreConfig [%pK %d], PostConfig[%pK %d]", + prestart_args->cmd_buf_addr, prestart_args->pre_config_buf_size, + cmd_buf_addr, prestart_args->post_config_buf_size); + + for (i = 0; i < (prestart_args->pre_config_buf_size + + prestart_args->post_config_buf_size) / 4; i++) + CAM_DBG(CAM_FD, "CDM KMD Commands [%d] : [%pK] [0x%x]", i, + &prestart_args->cmd_buf_addr[i], + prestart_args->cmd_buf_addr[i]); + + return 0; +} + +static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, + struct cam_fd_hw_frame_done_args *frame_done_args) +{ + struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info; + struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info; + struct cam_fd_hw_req_private *req_private; + uint32_t base, face_cnt; + uint32_t *buffer; + unsigned long flags; + int i; + + mutex_lock(&fd_hw->hw_mutex); + spin_lock_irqsave(&fd_core->spin_lock, flags); + if ((fd_core->core_state != CAM_FD_CORE_STATE_IDLE) || + (fd_core->results_valid == false) || + !fd_core->hw_req_private) { + CAM_ERR(CAM_FD, + "Invalid state for results state=%d, results=%d %pK", + fd_core->core_state, fd_core->results_valid, + fd_core->hw_req_private); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); + return -EINVAL; + } + fd_core->core_state = CAM_FD_CORE_STATE_READING_RESULTS; + req_private = fd_core->hw_req_private; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + /* + * Copy the register value as is into output buffers. + * Wehter we are copying the output data by reading registers or + * programming output buffer directly to HW must be transparent to UMD. + * In case HW supports writing face count value directly into + * DDR memory in future, these values should match. + */ + req_private->fd_results->face_count = + cam_fd_soc_register_read(&fd_hw->soc_info, CAM_FD_REG_CORE, + hw_static_info->core_regs.result_cnt); + + face_cnt = req_private->fd_results->face_count & 0x3F; + + if (face_cnt > hw_static_info->results.max_faces) { + CAM_WARN(CAM_FD, "Face count greater than max %d %d", + face_cnt, hw_static_info->results.max_faces); + face_cnt = hw_static_info->results.max_faces; + } + + CAM_DBG(CAM_FD, "ReqID[%lld] Faces Detected = %d", + req_private->request_id, face_cnt); + + /* + * We need to read the face data information from registers only + * if one of below is true + * 1. RO mode is not set. i.e FD HW doesn't write face data into + * DDR memory + * 2. On the current chipset, results written into DDR memory by FD HW + * are not gauranteed to be correct + */ + if (!req_private->ro_mode_enabled || + hw_static_info->enable_errata_wa.ro_mode_results_invalid) { + buffer = (uint32_t *)&req_private->fd_results->faces[0]; + base = hw_static_info->core_regs.results_reg_base; + + /* + * Write register values as is into face data buffer. Its UMD + * driver responsibility to interpret the data and extract face + * properties from output buffer. Think in case output buffer + * is directly programmed to HW, then KMD has no control to + * extract the face properties and UMD anyway has to extract + * face properties. So we follow the same approach and keep + * this transparent to UMD. + */ + for (i = 0; + i < (face_cnt * + hw_static_info->results.per_face_entries); i++) { + *buffer = cam_fd_soc_register_read(&fd_hw->soc_info, + CAM_FD_REG_CORE, base + (i * 0x4)); + CAM_DBG(CAM_FD, "FaceData[%d] : 0x%x", i / 4, *buffer); + buffer++; + } + } + + if (req_private->get_raw_results && + req_private->raw_results && + hw_static_info->results.raw_results_available) { + buffer = req_private->raw_results; + base = hw_static_info->core_regs.raw_results_reg_base; + + for (i = 0; + i < hw_static_info->results.raw_results_entries; + i++) { + *buffer = cam_fd_soc_register_read(&fd_hw->soc_info, + CAM_FD_REG_CORE, base + (i * 0x4)); + CAM_DBG(CAM_FD, "RawData[%d] : 0x%x", i, *buffer); + buffer++; + } + } + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->hw_req_private = NULL; + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); + + return 0; +} + +irqreturn_t cam_fd_hw_irq(int irq_num, void *data) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)data; + struct cam_fd_core *fd_core; + struct cam_hw_soc_info *soc_info; + struct cam_fd_hw_static_info *hw_static_info; + uint32_t reg_value; + enum cam_fd_hw_irq_type irq_type = CAM_FD_IRQ_FRAME_DONE; + uint32_t num_irqs = 0; + + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid data in IRQ callback"); + return IRQ_NONE; + } + + fd_core = (struct cam_fd_core *) fd_hw->core_info; + soc_info = &fd_hw->soc_info; + hw_static_info = fd_core->hw_static_info; + + reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_status); + + CAM_DBG(CAM_FD, "FD IRQ status 0x%x", reg_value); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_clear, + reg_value); + + if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE)) { + complete_all(&fd_core->halt_complete); + irq_type = CAM_FD_IRQ_HALT_DONE; + num_irqs++; + } + + if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE)) { + complete_all(&fd_core->reset_complete); + irq_type = CAM_FD_IRQ_RESET_DONE; + num_irqs++; + } + + if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE)) { + complete_all(&fd_core->processing_complete); + irq_type = CAM_FD_IRQ_FRAME_DONE; + num_irqs++; + } + + /* + * We should never get an IRQ callback with no or more than one mask. + * Validate first to make sure nothing going wrong. + */ + if (num_irqs != 1) { + CAM_ERR(CAM_FD, + "Invalid number of IRQs, value=0x%x, num_irqs=%d", + reg_value, num_irqs); + return IRQ_NONE; + } + + trace_cam_irq_activated("FD", irq_type); + + if (irq_type == CAM_FD_IRQ_HALT_DONE) { + /* + * Do not send HALT IRQ callback to Hw Mgr, + * a reset would always follow + */ + return IRQ_HANDLED; + } + + spin_lock(&fd_core->spin_lock); + /* Do not change state to IDLE on HALT IRQ. Reset must follow halt */ + if ((irq_type == CAM_FD_IRQ_RESET_DONE) || + (irq_type == CAM_FD_IRQ_FRAME_DONE)) { + + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + if (irq_type == CAM_FD_IRQ_FRAME_DONE) + fd_core->results_valid = true; + + CAM_DBG(CAM_FD, "FD IRQ type %d, state=%d", + irq_type, fd_core->core_state); + } + spin_unlock(&fd_core->spin_lock); + + if (fd_core->irq_cb.cam_fd_hw_mgr_cb) + fd_core->irq_cb.cam_fd_hw_mgr_cb(fd_core->irq_cb.data, + irq_type); + + return IRQ_HANDLED; +} + +int cam_fd_hw_get_hw_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_caps *fd_hw_caps = + (struct cam_fd_hw_caps *)get_hw_cap_args; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_FD, "Invalid input pointers %pK %pK", + hw_priv, get_hw_cap_args); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + *fd_hw_caps = fd_core->hw_caps; + + CAM_DBG(CAM_FD, "core:%d.%d wrapper:%d.%d mode:%d, raw:%d", + fd_hw_caps->core_version.major, + fd_hw_caps->core_version.minor, + fd_hw_caps->wrapper_version.major, + fd_hw_caps->wrapper_version.minor, + fd_hw_caps->supported_modes, + fd_hw_caps->raw_results_available); + + return 0; +} + +int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_init_args *init_args = + (struct cam_fd_hw_init_args *)init_hw_args; + int rc = 0; + unsigned long flags; + + if (!fd_hw || !init_args) { + CAM_ERR(CAM_FD, "Invalid argument %pK %pK", fd_hw, init_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_init_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_init_args)); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + + mutex_lock(&fd_hw->hw_mutex); + CAM_DBG(CAM_FD, "FD HW Init ref count before %d", fd_hw->open_count); + + if (fd_hw->open_count > 0) { + rc = 0; + goto cdm_streamon; + } + + rc = cam_fd_soc_enable_resources(&fd_hw->soc_info); + if (rc) { + CAM_ERR(CAM_FD, "Enable SOC failed, rc=%d", rc); + goto unlock_return; + } + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_hw->hw_state = CAM_HW_STATE_POWER_UP; + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + rc = cam_fd_hw_reset(hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc); + goto disable_soc; + } + + cam_fd_hw_util_enable_power_on_settings(fd_hw); + +cdm_streamon: + fd_hw->open_count++; + CAM_DBG(CAM_FD, "FD HW Init ref count after %d", fd_hw->open_count); + + if (init_args->ctx_hw_private) { + struct cam_fd_ctx_hw_private *ctx_hw_private = + init_args->ctx_hw_private; + + rc = cam_cdm_stream_on(ctx_hw_private->cdm_handle); + if (rc) { + CAM_ERR(CAM_FD, "CDM StreamOn fail :handle=0x%x, rc=%d", + ctx_hw_private->cdm_handle, rc); + fd_hw->open_count--; + if (!fd_hw->open_count) + goto disable_soc; + } + } + + mutex_unlock(&fd_hw->hw_mutex); + + return rc; + +disable_soc: + if (cam_fd_soc_disable_resources(&fd_hw->soc_info)) + CAM_ERR(CAM_FD, "Error in disable soc resources"); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + fd_core->core_state = CAM_FD_CORE_STATE_POWERDOWN; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); +unlock_return: + mutex_unlock(&fd_hw->hw_mutex); + return rc; +} + +int cam_fd_hw_deinit(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = hw_priv; + struct cam_fd_core *fd_core = NULL; + struct cam_fd_hw_deinit_args *deinit_args = + (struct cam_fd_hw_deinit_args *)deinit_hw_args; + int rc = 0; + unsigned long flags; + + if (!fd_hw || !deinit_hw_args) { + CAM_ERR(CAM_FD, "Invalid argument"); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_deinit_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_deinit_args)); + return -EINVAL; + } + + mutex_lock(&fd_hw->hw_mutex); + if (fd_hw->open_count == 0) { + mutex_unlock(&fd_hw->hw_mutex); + CAM_ERR(CAM_FD, "Error Unbalanced deinit"); + return -EFAULT; + } + + fd_hw->open_count--; + CAM_DBG(CAM_FD, "FD HW ref count=%d", fd_hw->open_count); + + if (fd_hw->open_count > 0) { + rc = 0; + goto positive_ref_cnt; + } + + rc = cam_fd_soc_disable_resources(&fd_hw->soc_info); + if (rc) + CAM_ERR(CAM_FD, "Failed in Disable SOC, rc=%d", rc); + + fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + fd_core = (struct cam_fd_core *)fd_hw->core_info; + + /* With the ref_cnt correct, this should never happen */ + WARN_ON(!fd_core); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_POWERDOWN; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); +positive_ref_cnt: + if (deinit_args->ctx_hw_private) { + struct cam_fd_ctx_hw_private *ctx_hw_private = + deinit_args->ctx_hw_private; + + rc = cam_cdm_stream_off(ctx_hw_private->cdm_handle); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in CDM StreamOff, handle=0x%x, rc=%d", + ctx_hw_private->cdm_handle, rc); + } + } + + mutex_unlock(&fd_hw->hw_mutex); + return rc; +} + +int cam_fd_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_static_info *hw_static_info; + struct cam_hw_soc_info *soc_info; + unsigned long flags; + int rc; + + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid input handle"); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + hw_static_info = fd_core->hw_static_info; + soc_info = &fd_hw->soc_info; + + spin_lock_irqsave(&fd_core->spin_lock, flags); + if ((fd_core->core_state == CAM_FD_CORE_STATE_POWERDOWN) || + (fd_core->core_state == CAM_FD_CORE_STATE_RESET_PROGRESS)) { + CAM_ERR(CAM_FD, "Reset not allowed in %d state", + fd_core->core_state); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + return -EINVAL; + } + + fd_core->results_valid = false; + fd_core->core_state = CAM_FD_CORE_STATE_RESET_PROGRESS; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x1); + + rc = cam_fd_hw_util_fdwrapper_halt(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HALT rc=%d", rc); + return rc; + } + + rc = cam_fd_hw_util_fdwrapper_sync_reset(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in RESET rc=%d", rc); + return rc; + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x0); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + return rc; +} + +int cam_fd_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_static_info *hw_static_info; + struct cam_fd_hw_cmd_start_args *start_args = + (struct cam_fd_hw_cmd_start_args *)hw_start_args; + struct cam_fd_ctx_hw_private *ctx_hw_private; + unsigned long flags; + int rc; + + if (!hw_priv || !start_args) { + CAM_ERR(CAM_FD, "Invalid input args %pK %pK", hw_priv, + start_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_cmd_start_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_cmd_start_args)); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + hw_static_info = fd_core->hw_static_info; + + spin_lock_irqsave(&fd_core->spin_lock, flags); + if (fd_core->core_state != CAM_FD_CORE_STATE_IDLE) { + CAM_ERR(CAM_FD, "Cannot start in %d state", + fd_core->core_state); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + return -EINVAL; + } + + /* + * We are about to start FD HW processing, save the request + * private data which is being processed by HW. Once the frame + * processing is finished, process_cmd(FRAME_DONE) should be called + * with same hw_req_private as input. + */ + fd_core->hw_req_private = start_args->hw_req_private; + fd_core->core_state = CAM_FD_CORE_STATE_PROCESSING; + fd_core->results_valid = false; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + ctx_hw_private = start_args->ctx_hw_private; + + /* Before starting HW process, clear processing complete */ + reinit_completion(&fd_core->processing_complete); + + if (hw_static_info->enable_errata_wa.single_irq_only) { + cam_fd_soc_register_write(&fd_hw->soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE)); + } + + if (start_args->num_hw_update_entries > 0) { + struct cam_cdm_bl_request *cdm_cmd = ctx_hw_private->cdm_cmd; + struct cam_hw_update_entry *cmd; + int i; + + cdm_cmd->cmd_arrary_count = start_args->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = false; + cdm_cmd->userdata = NULL; + cdm_cmd->cookie = 0; + + for (i = 0 ; i <= start_args->num_hw_update_entries; i++) { + cmd = (start_args->hw_update_entries + i); + cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i].offset = cmd->offset; + cdm_cmd->cmd[i].len = cmd->len; + } + + rc = cam_cdm_submit_bls(ctx_hw_private->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_FD, + "Failed to submit cdm commands, rc=%d", rc); + goto error; + } + } else { + CAM_ERR(CAM_FD, "Invalid number of hw update entries"); + rc = -EINVAL; + goto error; + } + + return 0; +error: + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + return rc; +} + +int cam_fd_hw_halt_reset(void *hw_priv, void *stop_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_static_info *hw_static_info; + struct cam_hw_soc_info *soc_info; + unsigned long flags; + int rc; + + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid input handle"); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + hw_static_info = fd_core->hw_static_info; + soc_info = &fd_hw->soc_info; + + spin_lock_irqsave(&fd_core->spin_lock, flags); + if ((fd_core->core_state == CAM_FD_CORE_STATE_POWERDOWN) || + (fd_core->core_state == CAM_FD_CORE_STATE_RESET_PROGRESS)) { + CAM_ERR(CAM_FD, "Reset not allowed in %d state", + fd_core->core_state); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + return -EINVAL; + } + + fd_core->results_valid = false; + fd_core->core_state = CAM_FD_CORE_STATE_RESET_PROGRESS; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x1); + + rc = cam_fd_hw_util_fdwrapper_halt(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HALT rc=%d", rc); + return rc; + } + + /* HALT must be followed by RESET */ + rc = cam_fd_hw_util_fdwrapper_sync_reset(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in RESET rc=%d", rc); + return rc; + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x0); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + return rc; +} + +int cam_fd_hw_reserve(void *hw_priv, void *hw_reserve_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + int rc = -EINVAL; + struct cam_fd_ctx_hw_private *ctx_hw_private; + struct cam_fd_hw_reserve_args *reserve_args = + (struct cam_fd_hw_reserve_args *)hw_reserve_args; + struct cam_cdm_acquire_data cdm_acquire; + struct cam_cdm_bl_request *cdm_cmd; + int i; + + if (!fd_hw || !reserve_args) { + CAM_ERR(CAM_FD, "Invalid input %pK, %pK", fd_hw, reserve_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_reserve_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_reserve_args)); + return -EINVAL; + } + + cdm_cmd = kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((CAM_FD_MAX_HW_ENTRIES - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!cdm_cmd) + return -ENOMEM; + + ctx_hw_private = kzalloc(sizeof(struct cam_fd_ctx_hw_private), + GFP_KERNEL); + if (!ctx_hw_private) { + kfree(cdm_cmd); + return -ENOMEM; + } + + memset(&cdm_acquire, 0, sizeof(cdm_acquire)); + strlcpy(cdm_acquire.identifier, "fd", sizeof("fd")); + cdm_acquire.cell_index = fd_hw->soc_info.index; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ctx_hw_private; + cdm_acquire.cam_cdm_callback = cam_fd_hw_util_cdm_callback; + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.base_array_cnt = fd_hw->soc_info.num_reg_map; + for (i = 0; i < fd_hw->soc_info.num_reg_map; i++) + cdm_acquire.base_array[i] = &fd_hw->soc_info.reg_map[i]; + + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_FD, "Failed to acquire the CDM HW"); + goto error; + } + + ctx_hw_private->hw_ctx = reserve_args->hw_ctx; + ctx_hw_private->fd_hw = fd_hw; + ctx_hw_private->mode = reserve_args->mode; + ctx_hw_private->cdm_handle = cdm_acquire.handle; + ctx_hw_private->cdm_ops = cdm_acquire.ops; + ctx_hw_private->cdm_cmd = cdm_cmd; + + reserve_args->ctx_hw_private = ctx_hw_private; + + CAM_DBG(CAM_FD, "private=%pK, hw_ctx=%pK, mode=%d, cdm_handle=0x%x", + ctx_hw_private, ctx_hw_private->hw_ctx, ctx_hw_private->mode, + ctx_hw_private->cdm_handle); + + return 0; +error: + kfree(ctx_hw_private); + kfree(cdm_cmd); + return rc; +} + +int cam_fd_hw_release(void *hw_priv, void *hw_release_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + int rc = -EINVAL; + struct cam_fd_ctx_hw_private *ctx_hw_private; + struct cam_fd_hw_release_args *release_args = + (struct cam_fd_hw_release_args *)hw_release_args; + + if (!fd_hw || !release_args) { + CAM_ERR(CAM_FD, "Invalid input %pK, %pK", fd_hw, release_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_release_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_release_args)); + return -EINVAL; + } + + ctx_hw_private = + (struct cam_fd_ctx_hw_private *)release_args->ctx_hw_private; + + rc = cam_cdm_release(ctx_hw_private->cdm_handle); + if (rc) + CAM_ERR(CAM_FD, "Release cdm handle failed, handle=0x%x, rc=%d", + ctx_hw_private->cdm_handle, rc); + + kfree(ctx_hw_private->cdm_cmd); + kfree(ctx_hw_private); + release_args->ctx_hw_private = NULL; + + return 0; +} + +int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + int rc = -EINVAL; + + if (!hw_priv || !cmd_args || + (cmd_type >= CAM_FD_HW_CMD_MAX)) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK %d", hw_priv, + cmd_args, cmd_type); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_FD_HW_CMD_REGISTER_CALLBACK: { + struct cam_fd_hw_cmd_set_irq_cb *irq_cb_args; + struct cam_fd_core *fd_core = + (struct cam_fd_core *)fd_hw->core_info; + + if (sizeof(struct cam_fd_hw_cmd_set_irq_cb) != arg_size) { + CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + irq_cb_args = (struct cam_fd_hw_cmd_set_irq_cb *)cmd_args; + fd_core->irq_cb.cam_fd_hw_mgr_cb = + irq_cb_args->cam_fd_hw_mgr_cb; + fd_core->irq_cb.data = irq_cb_args->data; + rc = 0; + break; + } + case CAM_FD_HW_CMD_PRESTART: { + struct cam_fd_hw_cmd_prestart_args *prestart_args; + + if (sizeof(struct cam_fd_hw_cmd_prestart_args) != arg_size) { + CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + prestart_args = (struct cam_fd_hw_cmd_prestart_args *)cmd_args; + rc = cam_fd_hw_util_processcmd_prestart(fd_hw, prestart_args); + break; + } + case CAM_FD_HW_CMD_FRAME_DONE: { + struct cam_fd_hw_frame_done_args *cmd_frame_results; + + if (sizeof(struct cam_fd_hw_frame_done_args) != + arg_size) { + CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + cmd_frame_results = + (struct cam_fd_hw_frame_done_args *)cmd_args; + rc = cam_fd_hw_util_processcmd_frame_done(fd_hw, + cmd_frame_results); + break; + } + default: + break; + } + + return rc; +} diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h new file mode 100644 index 000000000000..22f9130d9cd1 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_CORE_H_ +#define _CAM_FD_HW_CORE_H_ + +#include +#include +#include +#include +#include + +#include "cam_common_util.h" +#include "cam_debug_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_fd_hw_intf.h" +#include "cam_fd_hw_soc.h" + +#define CAM_FD_IRQ_TO_MASK(irq) (1 << (irq)) +#define CAM_FD_MASK_TO_IRQ(mask, irq) ((mask) >> (irq)) + +#define CAM_FD_HW_HALT_RESET_TIMEOUT 750 + +/** + * enum cam_fd_core_state - FD Core internal states + * + * @CAM_FD_CORE_STATE_POWERDOWN : Indicates FD core is powered down + * @CAM_FD_CORE_STATE_IDLE : Indicates FD HW is in idle state. + * Core can be in this state when it is + * ready to process frames or when + * processing is finished and results are + * available + * @CAM_FD_CORE_STATE_PROCESSING : Indicates FD core is processing frame + * @CAM_FD_CORE_STATE_READING_RESULTS : Indicates results are being read from + * FD core + * @CAM_FD_CORE_STATE_RESET_PROGRESS : Indicates FD Core is in reset state + */ +enum cam_fd_core_state { + CAM_FD_CORE_STATE_POWERDOWN, + CAM_FD_CORE_STATE_IDLE, + CAM_FD_CORE_STATE_PROCESSING, + CAM_FD_CORE_STATE_READING_RESULTS, + CAM_FD_CORE_STATE_RESET_PROGRESS, +}; + +/** + * struct cam_fd_ctx_hw_private : HW private information for a specific hw ctx. + * This information is populated by HW layer on + * reserve() and given back to HW Mgr as private + * data for the hw context. This private_data + * has to be passed by HW Mgr layer while + * further HW layer calls + * + * @hw_ctx : Corresponding hw_ctx pointer + * @fd_hw : FD HW info pointer + * @cdm_handle : CDM Handle for this context + * @cdm_ops : CDM Ops + * @cdm_cmd : CDM command pointer + * @mode : Mode this context is running + * @curr_req_private : Current Request information + * + */ +struct cam_fd_ctx_hw_private { + void *hw_ctx; + struct cam_hw_info *fd_hw; + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; + struct cam_cdm_bl_request *cdm_cmd; + enum cam_fd_hw_mode mode; + struct cam_fd_hw_req_private *curr_req_private; +}; + +/** + * struct cam_fd_core_regs : FD HW Core register offsets info + * + * @version : Offset of version register + * @control : Offset of control register + * @result_cnt : Offset of result count register + * @result_addr : Offset of results address register + * @image_addr : Offset of image address register + * @work_addr : Offset of work address register + * @ro_mode : Offset of ro_mode register + * @results_reg_base : Offset of results_reg_base register + * @raw_results_reg_base : Offset of raw_results_reg_base register + * + */ +struct cam_fd_core_regs { + uint32_t version; + uint32_t control; + uint32_t result_cnt; + uint32_t result_addr; + uint32_t image_addr; + uint32_t work_addr; + uint32_t ro_mode; + uint32_t results_reg_base; + uint32_t raw_results_reg_base; +}; + +/** + * struct cam_fd_core_regs : FD HW Wrapper register offsets info + * + * @wrapper_version : Offset of wrapper_version register + * @cgc_disable : Offset of cgc_disable register + * @hw_stop : Offset of hw_stop register + * @sw_reset : Offset of sw_reset register + * @vbif_req_priority : Offset of vbif_req_priority register + * @vbif_priority_level : Offset of vbif_priority_level register + * @vbif_done_status : Offset of vbif_done_status register + * @irq_mask : Offset of irq mask register + * @irq_status : Offset of irq status register + * @irq_clear : Offset of irq clear register + * + */ +struct cam_fd_wrapper_regs { + uint32_t wrapper_version; + uint32_t cgc_disable; + uint32_t hw_stop; + uint32_t sw_reset; + uint32_t vbif_req_priority; + uint32_t vbif_priority_level; + uint32_t vbif_done_status; + uint32_t irq_mask; + uint32_t irq_status; + uint32_t irq_clear; +}; + +/** + * struct cam_fd_hw_errata_wa : FD HW Errata workaround enable/dsiable info + * + * @single_irq_only : Whether to enable only one irq at any time + * @ro_mode_enable_always : Whether to enable ro mode always + * @ro_mode_results_invalid : Whether results written directly into output + * memory by HW are valid or not + */ +struct cam_fd_hw_errata_wa { + bool single_irq_only; + bool ro_mode_enable_always; + bool ro_mode_results_invalid; +}; + +/** + * struct cam_fd_hw_results_prop : FD HW Results properties + * + * @max_faces : Maximum number of faces supported + * @per_face_entries : Number of register with properties for each face + * @raw_results_entries : Number of raw results entries for the full search + * @raw_results_available : Whether raw results available on this HW + * + */ +struct cam_fd_hw_results_prop { + uint32_t max_faces; + uint32_t per_face_entries; + uint32_t raw_results_entries; + bool raw_results_available; +}; + +/** + * struct cam_fd_hw_static_info : FD HW information based on HW version + * + * @core_version : Core version of FD HW + * @wrapper_version : Wrapper version of FD HW + * @core_regs : Register offset information for core registers + * @wrapper_regs : Register offset information for wrapper registers + * @results : Information about results available on this HW + * @enable_errata_wa : Errata workaround information + * @irq_mask : IRQ mask to enable + * @qos_priority : QoS priority setting for this chipset + * @qos_priority_level : QoS priority level setting for this chipset + * @supported_modes : Supported HW modes on this HW version + * @ro_mode_supported : Whether RO mode is supported on this HW + * + */ +struct cam_fd_hw_static_info { + struct cam_hw_version core_version; + struct cam_hw_version wrapper_version; + struct cam_fd_core_regs core_regs; + struct cam_fd_wrapper_regs wrapper_regs; + struct cam_fd_hw_results_prop results; + struct cam_fd_hw_errata_wa enable_errata_wa; + uint32_t irq_mask; + uint32_t qos_priority; + uint32_t qos_priority_level; + uint32_t supported_modes; + bool ro_mode_supported; +}; + +/** + * struct cam_fd_core : FD HW core data structure + * + * @hw_static_info : HW information specific to version + * @hw_caps : HW capabilities + * @core_state : Current HW state + * @processing_complete : Whether processing is complete + * @reset_complete : Whether reset is complete + * @halt_complete : Whether halt is complete + * @hw_req_private : Request that is being currently processed by HW + * @results_valid : Whether HW frame results are available to get + * @spin_lock : Mutex to protect shared data in hw layer + * @irq_cb : HW Manager callback information + * + */ +struct cam_fd_core { + struct cam_fd_hw_static_info *hw_static_info; + struct cam_fd_hw_caps hw_caps; + enum cam_fd_core_state core_state; + struct completion processing_complete; + struct completion reset_complete; + struct completion halt_complete; + struct cam_fd_hw_req_private *hw_req_private; + bool results_valid; + spinlock_t spin_lock; + struct cam_fd_hw_cmd_set_irq_cb irq_cb; +}; + +int cam_fd_hw_util_get_hw_caps(struct cam_hw_info *fd_hw, + struct cam_fd_hw_caps *hw_caps); +irqreturn_t cam_fd_hw_irq(int irq_num, void *data); + +int cam_fd_hw_get_hw_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size); +int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size); +int cam_fd_hw_deinit(void *hw_priv, void *deinit_hw_args, uint32_t arg_size); +int cam_fd_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size); +int cam_fd_hw_reserve(void *hw_priv, void *hw_reserve_args, uint32_t arg_size); +int cam_fd_hw_release(void *hw_priv, void *hw_release_args, uint32_t arg_size); +int cam_fd_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size); +int cam_fd_hw_halt_reset(void *hw_priv, void *stop_args, uint32_t arg_size); +int cam_fd_hw_read(void *hw_priv, void *read_args, uint32_t arg_size); +int cam_fd_hw_write(void *hw_priv, void *write_args, uint32_t arg_size); +int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +#endif /* _CAM_FD_HW_CORE_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c new file mode 100644 index 000000000000..3498e6235279 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_subdev.h" +#include "cam_fd_hw_intf.h" +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" +#include "cam_fd_hw_v41.h" +#include "cam_fd_hw_v501.h" +#include "cam_fd_hw_v600.h" + +static char fd_dev_name[8]; + +static int cam_fd_hw_dev_probe(struct platform_device *pdev) +{ + struct cam_hw_info *fd_hw; + struct cam_hw_intf *fd_hw_intf; + struct cam_fd_core *fd_core; + const struct of_device_id *match_dev = NULL; + struct cam_fd_hw_static_info *hw_static_info = NULL; + int rc = 0; + uint32_t hw_idx; + struct cam_fd_hw_init_args init_args; + struct cam_fd_hw_deinit_args deinit_args; + + fd_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!fd_hw_intf) + return -ENOMEM; + + fd_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!fd_hw) { + kfree(fd_hw_intf); + return -ENOMEM; + } + + fd_core = kzalloc(sizeof(struct cam_fd_core), GFP_KERNEL); + if (!fd_core) { + kfree(fd_hw); + kfree(fd_hw_intf); + return -ENOMEM; + } + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_idx); + + fd_hw_intf->hw_priv = fd_hw; + fd_hw->core_info = fd_core; + fd_hw_intf->hw_idx = hw_idx; + + memset(fd_dev_name, 0, sizeof(fd_dev_name)); + snprintf(fd_dev_name, sizeof(fd_dev_name), + "fd%1u", fd_hw_intf->hw_idx); + + fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + fd_hw->soc_info.pdev = pdev; + fd_hw->soc_info.dev = &pdev->dev; + fd_hw->soc_info.dev_name = fd_dev_name; + fd_hw->open_count = 0; + mutex_init(&fd_hw->hw_mutex); + spin_lock_init(&fd_hw->hw_lock); + init_completion(&fd_hw->hw_complete); + + spin_lock_init(&fd_core->spin_lock); + init_completion(&fd_core->processing_complete); + init_completion(&fd_core->halt_complete); + init_completion(&fd_core->reset_complete); + + fd_hw_intf->hw_ops.get_hw_caps = cam_fd_hw_get_hw_caps; + fd_hw_intf->hw_ops.init = cam_fd_hw_init; + fd_hw_intf->hw_ops.deinit = cam_fd_hw_deinit; + fd_hw_intf->hw_ops.reset = cam_fd_hw_reset; + fd_hw_intf->hw_ops.reserve = cam_fd_hw_reserve; + fd_hw_intf->hw_ops.release = cam_fd_hw_release; + fd_hw_intf->hw_ops.start = cam_fd_hw_start; + fd_hw_intf->hw_ops.stop = cam_fd_hw_halt_reset; + fd_hw_intf->hw_ops.read = NULL; + fd_hw_intf->hw_ops.write = NULL; + fd_hw_intf->hw_ops.process_cmd = cam_fd_hw_process_cmd; + fd_hw_intf->hw_type = CAM_HW_FD; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev || !match_dev->data) { + CAM_ERR(CAM_FD, "No Of_match data, %pK", match_dev); + rc = -EINVAL; + goto free_memory; + } + hw_static_info = (struct cam_fd_hw_static_info *)match_dev->data; + fd_core->hw_static_info = hw_static_info; + + CAM_DBG(CAM_FD, "HW Static Info : version core[%d.%d] wrapper[%d.%d]", + hw_static_info->core_version.major, + hw_static_info->core_version.minor, + hw_static_info->wrapper_version.major, + hw_static_info->wrapper_version.minor); + + rc = cam_fd_soc_init_resources(&fd_hw->soc_info, cam_fd_hw_irq, fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed to init soc, rc=%d", rc); + goto free_memory; + } + + memset(&init_args, 0x0, sizeof(init_args)); + memset(&deinit_args, 0x0, sizeof(deinit_args)); + rc = cam_fd_hw_init(fd_hw, &init_args, sizeof(init_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed to hw init, rc=%d", rc); + goto deinit_platform_res; + } + + rc = cam_fd_hw_util_get_hw_caps(fd_hw, &fd_core->hw_caps); + if (rc) { + CAM_ERR(CAM_FD, "Failed to get hw caps, rc=%d", rc); + goto deinit_hw; + } + + rc = cam_fd_hw_deinit(fd_hw, &deinit_args, sizeof(deinit_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed to deinit hw, rc=%d", rc); + goto deinit_platform_res; + } + + platform_set_drvdata(pdev, fd_hw_intf); + CAM_DBG(CAM_FD, "FD-%d probe successful", fd_hw_intf->hw_idx); + + return rc; + +deinit_hw: + if (cam_fd_hw_deinit(fd_hw, &deinit_args, sizeof(deinit_args))) + CAM_ERR(CAM_FD, "Failed in hw deinit"); +deinit_platform_res: + if (cam_fd_soc_deinit_resources(&fd_hw->soc_info)) + CAM_ERR(CAM_FD, "Failed in soc deinit"); + mutex_destroy(&fd_hw->hw_mutex); +free_memory: + kfree(fd_hw); + kfree(fd_hw_intf); + kfree(fd_core); + + return rc; +} + +static int cam_fd_hw_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + struct cam_hw_intf *fd_hw_intf; + struct cam_hw_info *fd_hw; + struct cam_fd_core *fd_core; + + fd_hw_intf = platform_get_drvdata(pdev); + if (!fd_hw_intf) { + CAM_ERR(CAM_FD, "Invalid fd_hw_intf from pdev"); + return -EINVAL; + } + + fd_hw = fd_hw_intf->hw_priv; + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid fd_hw from fd_hw_intf"); + rc = -ENODEV; + goto free_fd_hw_intf; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + if (!fd_core) { + CAM_ERR(CAM_FD, "Invalid fd_core from fd_hw"); + rc = -EINVAL; + goto deinit_platform_res; + } + + kfree(fd_core); + +deinit_platform_res: + rc = cam_fd_soc_deinit_resources(&fd_hw->soc_info); + if (rc) + CAM_ERR(CAM_FD, "Error in FD soc deinit, rc=%d", rc); + + mutex_destroy(&fd_hw->hw_mutex); + kfree(fd_hw); + +free_fd_hw_intf: + kfree(fd_hw_intf); + + return rc; +} + +static const struct of_device_id cam_fd_hw_dt_match[] = { + { + .compatible = "qcom,fd41", + .data = &cam_fd_wrapper120_core410_info, + }, + { + .compatible = "qcom,fd501", + .data = &cam_fd_wrapper200_core501_info, + }, + { + .compatible = "qcom,fd600", + .data = &cam_fd_wrapper200_core600_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match); + +static struct platform_driver cam_fd_hw_driver = { + .probe = cam_fd_hw_dev_probe, + .remove = cam_fd_hw_dev_remove, + .driver = { + .name = "cam_fd_hw", + .owner = THIS_MODULE, + .of_match_table = cam_fd_hw_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_fd_hw_init_module(void) +{ + return platform_driver_register(&cam_fd_hw_driver); +} + +static void __exit cam_fd_hw_exit_module(void) +{ + platform_driver_unregister(&cam_fd_hw_driver); +} + +module_init(cam_fd_hw_init_module); +module_exit(cam_fd_hw_exit_module); +MODULE_DESCRIPTION("CAM FD HW driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h new file mode 100644 index 000000000000..040bd161e006 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -0,0 +1,282 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_INTF_H_ +#define _CAM_FD_HW_INTF_H_ + +#include +#include +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_subdev.h" +#include "cam_cpas_api.h" +#include "cam_hw_mgr_intf.h" +#include "cam_debug_util.h" + +#define CAM_FD_MAX_IO_BUFFERS 5 +#define CAM_FD_MAX_HW_ENTRIES 5 + +/** + * enum cam_fd_hw_type - Enum for FD HW type + * + * @CAM_HW_FD : FaceDetection HW type + */ +enum cam_fd_hw_type { + CAM_HW_FD, +}; + +/** + * enum cam_fd_hw_mode - Mode in which HW can run + * + * @CAM_FD_MODE_FACEDETECTION : Face Detection mode in which face search + * is done on the given frame + * @CAM_FD_MODE_PYRAMID : Pyramid mode where a pyramid image is generated + * from an input image + */ +enum cam_fd_hw_mode { + CAM_FD_MODE_FACEDETECTION = 0x1, + CAM_FD_MODE_PYRAMID = 0x2, +}; + +/** + * enum cam_fd_priority - FD priority levels + * + * @CAM_FD_PRIORITY_HIGH : Indicates high priority client, driver prioritizes + * frame requests coming from contexts with HIGH + * priority compared to context with normal priority + * @CAM_FD_PRIORITY_NORMAL : Indicates normal priority client + */ +enum cam_fd_priority { + CAM_FD_PRIORITY_HIGH = 0x0, + CAM_FD_PRIORITY_NORMAL, +}; + +/** + * enum cam_fd_hw_irq_type - FD HW IRQ types + * + * @CAM_FD_IRQ_FRAME_DONE : Indicates frame processing is finished + * @CAM_FD_IRQ_HALT_DONE : Indicates HW halt is finished + * @CAM_FD_IRQ_RESET_DONE : Indicates HW reset is finished + */ +enum cam_fd_hw_irq_type { + CAM_FD_IRQ_FRAME_DONE, + CAM_FD_IRQ_HALT_DONE, + CAM_FD_IRQ_RESET_DONE, +}; + +/** + * enum cam_fd_hw_cmd_type - FD HW layer custom commands + * + * @CAM_FD_HW_CMD_PRESTART : Command to process pre-start settings + * @CAM_FD_HW_CMD_FRAME_DONE : Command to process frame done settings + * @CAM_FD_HW_CMD_UPDATE_SOC : Command to process soc update + * @CAM_FD_HW_CMD_REGISTER_CALLBACK : Command to set hw mgr callback + * @CAM_FD_HW_CMD_MAX : Indicates max cmd + */ +enum cam_fd_hw_cmd_type { + CAM_FD_HW_CMD_PRESTART, + CAM_FD_HW_CMD_FRAME_DONE, + CAM_FD_HW_CMD_UPDATE_SOC, + CAM_FD_HW_CMD_REGISTER_CALLBACK, + CAM_FD_HW_CMD_MAX, +}; + +/** + * struct cam_fd_hw_io_buffer : FD HW IO Buffer information + * + * @valid : Whether this IO Buf configuration is valid + * @io_cfg : IO Configuration information + * @num_buf : Number planes in io_addr, cpu_addr array + * @io_addr : Array of IO address information for planes + * @cpu_addr : Array of CPU address information for planes + */ +struct cam_fd_hw_io_buffer { + bool valid; + struct cam_buf_io_cfg *io_cfg; + uint32_t num_buf; + uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + uintptr_t cpu_addr[CAM_PACKET_MAX_PLANES]; +}; + +/** + * struct cam_fd_hw_req_private : FD HW layer's private information + * specific to a request + * + * @ctx_hw_private : FD HW layer's ctx specific private data + * @request_id : Request ID corresponding to this private information + * @get_raw_results : Whether to get raw results for this request + * @ro_mode_enabled : Whether RO mode is enabled for this request + * @fd_results : Pointer to save face detection results + * @raw_results : Pointer to save face detection raw results + */ +struct cam_fd_hw_req_private { + void *ctx_hw_private; + uint64_t request_id; + bool get_raw_results; + bool ro_mode_enabled; + struct cam_fd_results *fd_results; + uint32_t *raw_results; +}; + +/** + * struct cam_fd_hw_reserve_args : Reserve args for this HW context + * + * @hw_ctx : HW context for which reserve is requested + * @mode : Mode for which this reserve is requested + * @ctx_hw_private : Pointer to save HW layer's private information specific + * to this hw context. This has to be passed while calling + * further HW layer calls + */ +struct cam_fd_hw_reserve_args { + void *hw_ctx; + enum cam_fd_hw_mode mode; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_release_args : Release args for this HW context + * + * @hw_ctx : HW context for which release is requested + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_release_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_init_args : Init args for this HW context + * + * @hw_ctx : HW context for which init is requested + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_init_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_deinit_args : Deinit args for this HW context + * + * @hw_ctx : HW context for which deinit is requested + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_deinit_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_cmd_prestart_args : Prestart command args + * + * @hw_ctx : HW context which submitted this prestart + * @ctx_hw_private : HW layer's private information specific to + * this hw context + * @request_id : Request ID corresponds to this pre-start command + * @get_raw_results : Whether to get raw results for this request + * @input_buf : Input IO Buffer information for this request + * @output_buf : Output IO Buffer information for this request + * @cmd_buf_addr : Command buffer address to fill kmd commands + * @size : Size available in command buffer + * @pre_config_buf_size : Buffer size filled with commands by KMD that has + * to be inserted before umd commands + * @post_config_buf_size : Buffer size filled with commands by KMD that has + * to be inserted after umd commands + * @hw_req_private : HW layer's private information specific to + * this request + */ +struct cam_fd_hw_cmd_prestart_args { + void *hw_ctx; + void *ctx_hw_private; + uint64_t request_id; + bool get_raw_results; + struct cam_fd_hw_io_buffer input_buf[CAM_FD_MAX_IO_BUFFERS]; + struct cam_fd_hw_io_buffer output_buf[CAM_FD_MAX_IO_BUFFERS]; + uint32_t *cmd_buf_addr; + uint32_t size; + uint32_t pre_config_buf_size; + uint32_t post_config_buf_size; + struct cam_fd_hw_req_private hw_req_private; +}; + +/** + * struct cam_fd_hw_cmd_start_args : Start command args + * + * @hw_ctx : HW context which submitting start command + * @ctx_hw_private : HW layer's private information specific to + * this hw context + * @hw_req_private : HW layer's private information specific to + * this request + * @hw_update_entries : HW update entries corresponds to this request + * @num_hw_update_entries : Number of hw update entries + */ +struct cam_fd_hw_cmd_start_args { + void *hw_ctx; + void *ctx_hw_private; + struct cam_fd_hw_req_private *hw_req_private; + struct cam_hw_update_entry *hw_update_entries; + uint32_t num_hw_update_entries; +}; + +/** + * struct cam_fd_hw_stop_args : Stop command args + * + * @hw_ctx : HW context which submitting stop command + * @ctx_hw_private : HW layer's private information specific to this hw context + * @request_id : Request ID that need to be stopped + * @hw_req_private : HW layer's private information specific to this request + */ +struct cam_fd_hw_stop_args { + void *hw_ctx; + void *ctx_hw_private; + uint64_t request_id; + struct cam_fd_hw_req_private *hw_req_private; +}; + +/** + * struct cam_fd_hw_frame_done_args : Frame done command args + * + * @hw_ctx : HW context which submitting frame done request + * @ctx_hw_private : HW layer's private information specific to this hw context + * @request_id : Request ID that need to be stopped + * @hw_req_private : HW layer's private information specific to this request + */ +struct cam_fd_hw_frame_done_args { + void *hw_ctx; + void *ctx_hw_private; + uint64_t request_id; + struct cam_fd_hw_req_private *hw_req_private; +}; + +/** + * struct cam_fd_hw_reset_args : Reset command args + * + * @hw_ctx : HW context which submitting reset command + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_reset_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_cmd_set_irq_cb : Set IRQ callback command args + * + * @cam_fd_hw_mgr_cb : HW Mgr's callback pointer + * @data : HW Mgr's private data + */ +struct cam_fd_hw_cmd_set_irq_cb { + int (*cam_fd_hw_mgr_cb)(void *data, enum cam_fd_hw_irq_type irq_type); + void *data; +}; + +#endif /* _CAM_FD_HW_INTF_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c new file mode 100644 index 000000000000..56635aa6bce4 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" + +static bool cam_fd_hw_util_cpas_callback(uint32_t handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + if (!irq_data) + return false; + + CAM_DBG(CAM_FD, "CPAS hdl=%d, udata=%pK, irq_type=%d", + handle, userdata, irq_data->irq_type); + + return false; +} + +static int cam_fd_hw_soc_util_setup_regbase_indices( + struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + uint32_t index; + int rc, i; + + for (i = 0; i < CAM_FD_REG_MAX; i++) + soc_private->regbase_index[i] = -1; + + if ((soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) || + (soc_info->num_mem_block != CAM_FD_REG_MAX)) { + CAM_ERR(CAM_FD, "Invalid num_mem_block=%d", + soc_info->num_mem_block); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "fd_core", &index); + if ((rc == 0) && (index < CAM_FD_REG_MAX)) { + soc_private->regbase_index[CAM_FD_REG_CORE] = index; + } else { + CAM_ERR(CAM_FD, "regbase not found for FD_CORE, rc=%d, %d %d", + rc, index, CAM_FD_REG_MAX); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "fd_wrapper", &index); + if ((rc == 0) && (index < CAM_FD_REG_MAX)) { + soc_private->regbase_index[CAM_FD_REG_WRAPPER] = index; + } else { + CAM_ERR(CAM_FD, "regbase not found FD_WRAPPER, rc=%d, %d %d", + rc, index, CAM_FD_REG_MAX); + return -EINVAL; + } + + CAM_DBG(CAM_FD, "Reg indices : CORE=%d, WRAPPER=%d", + soc_private->regbase_index[CAM_FD_REG_CORE], + soc_private->regbase_index[CAM_FD_REG_WRAPPER]); + + return 0; +} + +static int cam_fd_soc_set_clk_flags(struct cam_hw_soc_info *soc_info) +{ + int i, rc = 0; + + if (soc_info->num_clk > CAM_SOC_MAX_CLK) { + CAM_ERR(CAM_FD, "Invalid num clk %d", soc_info->num_clk); + return -EINVAL; + } + + /* set memcore and mem periphery logic flags to 0 */ + for (i = 0; i < soc_info->num_clk; i++) { + if ((strcmp(soc_info->clk_name[i], "fd_core_clk") == 0) || + (strcmp(soc_info->clk_name[i], "fd_core_uar_clk") == + 0)) { + rc = cam_soc_util_set_clk_flags(soc_info, i, + CLKFLAG_NORETAIN_MEM); + if (rc) + CAM_ERR(CAM_FD, + "Failed in NORETAIN_MEM i=%d, rc=%d", + i, rc); + + cam_soc_util_set_clk_flags(soc_info, i, + CLKFLAG_NORETAIN_PERIPH); + if (rc) + CAM_ERR(CAM_FD, + "Failed in NORETAIN_PERIPH i=%d, rc=%d", + i, rc); + } + } + + return rc; +} + +void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + int32_t reg_index = soc_private->regbase_index[reg_base]; + + CAM_DBG(CAM_FD, "FD_REG_WRITE: Base[%d] Offset[0x%8x] Value[0x%8x]", + reg_base, reg_offset, reg_value); + + cam_io_w_mb(reg_value, + soc_info->reg_map[reg_index].mem_base + reg_offset); +} + +uint32_t cam_fd_soc_register_read(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + int32_t reg_index = soc_private->regbase_index[reg_base]; + uint32_t reg_value; + + reg_value = cam_io_r_mb( + soc_info->reg_map[reg_index].mem_base + reg_offset); + + CAM_DBG(CAM_FD, "FD_REG_READ: Base[%d] Offset[0x%8x] Value[0x%8x]", + reg_base, reg_offset, reg_value); + + return reg_value; +} + +int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private = soc_info->soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = 7200000; + axi_vote.axi_path[0].mnoc_ab_bw = 7200000; + axi_vote.axi_path[0].mnoc_ib_bw = 7200000; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = 7200000; + axi_vote.axi_path[1].mnoc_ab_bw = 7200000; + axi_vote.axi_path[1].mnoc_ib_bw = 7200000; + + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_FD, "Error in CPAS START, rc=%d", rc); + return -EFAULT; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE, + true); + if (rc) { + CAM_ERR(CAM_FD, "Error enable platform failed, rc=%d", rc); + goto stop_cpas; + } + + return rc; + +stop_cpas: + if (cam_cpas_stop(soc_private->cpas_handle)) + CAM_ERR(CAM_FD, "Error in CPAS STOP"); + + return rc; +} + + +int cam_fd_soc_disable_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private; + int rc = 0; + + if (!soc_info) { + CAM_ERR(CAM_FD, "Invalid soc_info param"); + return -EINVAL; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_FD, "disable platform resources failed, rc=%d", rc); + return rc; + } + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_FD, "Error in CPAS STOP, handle=0x%x, rc=%d", + soc_private->cpas_handle, rc); + return rc; + } + + return rc; +} + +int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data) +{ + struct cam_fd_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_FD, "Failed in get_dt_properties, rc=%d", rc); + return rc; + } + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + private_data); + if (rc) { + CAM_ERR(CAM_FD, "Failed in request_platform_resource rc=%d", + rc); + return rc; + } + + rc = cam_fd_soc_set_clk_flags(soc_info); + if (rc) { + CAM_ERR(CAM_FD, "failed in set_clk_flags rc=%d", rc); + goto release_res; + } + + soc_private = kzalloc(sizeof(struct cam_fd_soc_private), GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto release_res; + } + soc_info->soc_private = soc_private; + + rc = cam_fd_hw_soc_util_setup_regbase_indices(soc_info); + if (rc) { + CAM_ERR(CAM_FD, "Failed in setup regbase, rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "fd", CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = &soc_info->pdev->dev; + cpas_register_param.userdata = private_data; + cpas_register_param.cam_cpas_client_cb = cam_fd_hw_util_cpas_callback; + + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_FD, "CPAS registration failed"); + goto free_soc_private; + } + soc_private->cpas_handle = cpas_register_param.client_handle; + CAM_DBG(CAM_FD, "CPAS handle=%d", soc_private->cpas_handle); + + return rc; + +free_soc_private: + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; +release_res: + cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_fd_soc_deinit_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + int rc; + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_FD, "Unregister cpas failed, handle=%d, rc=%d", + soc_private->cpas_handle, rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_FD, "release platform failed, rc=%d", rc); + + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; + + return rc; +} diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h new file mode 100644 index 000000000000..b27ce09e36e6 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_SOC_H_ +#define _CAM_FD_HW_SOC_H_ + +#include "cam_soc_util.h" + +/** + * enum cam_fd_reg_base - Enum for FD register sets + * + * @CAM_FD_REG_CORE : Indicates FD Core register space + * @CAM_FD_REG_WRAPPER : Indicates FD Wrapper register space + * @CAM_FD_REG_MAX : Max number of register sets supported + */ +enum cam_fd_reg_base { + CAM_FD_REG_CORE, + CAM_FD_REG_WRAPPER, + CAM_FD_REG_MAX +}; + +/** + * struct cam_fd_soc_private : FD private SOC information + * + * @regbase_index : Mapping between Register base enum to register index in SOC + * @cpas_handle : CPAS handle + * + */ +struct cam_fd_soc_private { + int32_t regbase_index[CAM_FD_REG_MAX]; + uint32_t cpas_handle; +}; + +int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data); +int cam_fd_soc_deinit_resources(struct cam_hw_soc_info *soc_info); +int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info); +int cam_fd_soc_disable_resources(struct cam_hw_soc_info *soc_info); +uint32_t cam_fd_soc_register_read(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset); +void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value); + +#endif /* _CAM_FD_HW_SOC_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h new file mode 100644 index 000000000000..ad1fb0bc5737 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_V41_H_ +#define _CAM_FD_HW_V41_H_ + +static struct cam_fd_hw_static_info cam_fd_wrapper120_core410_info = { + .core_version = { + .major = 4, + .minor = 1, + .incr = 0, + }, + .wrapper_version = { + .major = 1, + .minor = 2, + .incr = 0, + }, + .core_regs = { + .version = 0x38, + .control = 0x0, + .result_cnt = 0x4, + .result_addr = 0x20, + .image_addr = 0x24, + .work_addr = 0x28, + .ro_mode = 0x34, + .results_reg_base = 0x400, + .raw_results_reg_base = 0x800, + }, + .wrapper_regs = { + .wrapper_version = 0x0, + .cgc_disable = 0x4, + .hw_stop = 0x8, + .sw_reset = 0x10, + .vbif_req_priority = 0x20, + .vbif_priority_level = 0x24, + .vbif_done_status = 0x34, + .irq_mask = 0x50, + .irq_status = 0x54, + .irq_clear = 0x58, + }, + .results = { + .max_faces = 35, + .per_face_entries = 4, + .raw_results_available = true, + .raw_results_entries = 512, + }, + .enable_errata_wa = { + .single_irq_only = true, + .ro_mode_enable_always = true, + .ro_mode_results_invalid = true, + }, + .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE), + .qos_priority = 4, + .qos_priority_level = 4, + .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID, + .ro_mode_supported = true, +}; + +#endif /* _CAM_FD_HW_V41_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h new file mode 100644 index 000000000000..f3eedeb3b811 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_V501_H_ +#define _CAM_FD_HW_V501_H_ + +static struct cam_fd_hw_static_info cam_fd_wrapper200_core501_info = { + .core_version = { + .major = 5, + .minor = 0, + .incr = 1, + }, + .wrapper_version = { + .major = 2, + .minor = 0, + .incr = 0, + }, + .core_regs = { + .version = 0x38, + .control = 0x0, + .result_cnt = 0x4, + .result_addr = 0x20, + .image_addr = 0x24, + .work_addr = 0x28, + .ro_mode = 0x34, + .results_reg_base = 0x400, + .raw_results_reg_base = 0x800, + }, + .wrapper_regs = { + .wrapper_version = 0x0, + .cgc_disable = 0x4, + .hw_stop = 0x8, + .sw_reset = 0x10, + .vbif_req_priority = 0x20, + .vbif_priority_level = 0x24, + .vbif_done_status = 0x34, + .irq_mask = 0x50, + .irq_status = 0x54, + .irq_clear = 0x58, + }, + .results = { + .max_faces = 35, + .per_face_entries = 4, + .raw_results_available = true, + .raw_results_entries = 512, + }, + .enable_errata_wa = { + .single_irq_only = true, + .ro_mode_enable_always = true, + .ro_mode_results_invalid = true, + }, + .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE), + .qos_priority = 4, + .qos_priority_level = 4, + .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID, + .ro_mode_supported = true, +}; + +#endif /* _CAM_FD_HW_V501_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h new file mode 100644 index 000000000000..0c81cb642930 --- /dev/null +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_V600_H_ +#define _CAM_FD_HW_V600_H_ + +static struct cam_fd_hw_static_info cam_fd_wrapper200_core600_info = { + .core_version = { + .major = 6, + .minor = 0, + .incr = 0, + }, + .wrapper_version = { + .major = 2, + .minor = 0, + .incr = 0, + }, + .core_regs = { + .version = 0x38, + .control = 0x0, + .result_cnt = 0x4, + .result_addr = 0x20, + .image_addr = 0x24, + .work_addr = 0x28, + .ro_mode = 0x34, + .results_reg_base = 0x400, + }, + .wrapper_regs = { + .wrapper_version = 0x0, + .cgc_disable = 0x4, + .hw_stop = 0x8, + .sw_reset = 0x10, + .vbif_req_priority = 0x20, + .vbif_priority_level = 0x24, + .vbif_done_status = 0x34, + .irq_mask = 0x50, + .irq_status = 0x54, + .irq_clear = 0x58, + }, + .results = { + .max_faces = 35, + .per_face_entries = 4, + .raw_results_available = false, + }, + .enable_errata_wa = { + .single_irq_only = true, + .ro_mode_enable_always = true, + .ro_mode_results_invalid = true, + }, + .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE), + .qos_priority = 4, + .qos_priority_level = 4, + .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID, + .ro_mode_supported = true, +}; + +#endif /* _CAM_FD_HW_V600_H_ */ diff --git a/drivers/cam_icp/Makefile b/drivers/cam_icp/Makefile new file mode 100644 index 000000000000..b41c6cf1fb65 --- /dev/null +++ b/drivers/cam_icp/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_subdev.o cam_icp_context.o hfi.o diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c new file mode 100644 index 000000000000..c7d9c63f8429 --- /dev/null +++ b/drivers/cam_icp/cam_icp_context.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cam_node.h" +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_icp_context.h" +#include "cam_req_mgr_util.h" +#include "cam_mem_mgr.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" + +static const char icp_dev_name[] = "icp"; + +static int cam_icp_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info) +{ + struct cam_context *ctx = (struct cam_context *)data; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_temp = NULL; + struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL; + int rc = 0; + bool b_mem_found = false; + + if (!ctx) { + CAM_ERR(CAM_ICP, "Invalid ctx"); + return -EINVAL; + } + + CAM_INFO(CAM_ICP, "iommu fault for icp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ICP, "req_id : %lld", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &b_mem_found); + if (rc) + CAM_ERR(CAM_ICP, "Failed to dump pf info"); + + if (b_mem_found) + CAM_ERR(CAM_ICP, "Found page fault in req %lld %d", + req->request_id, rc); + } + + return rc; +} + +static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ICP", ctx); + } + + return rc; +} + +static int __cam_icp_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Unable to release device"); + + ctx->state = CAM_CTX_AVAILABLE; + trace_cam_context_state("ICP", ctx); + return rc; +} + +static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_start_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ICP", ctx); + } + + return rc; +} + +static int __cam_icp_flush_dev_in_ready(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to flush device"); + + return rc; +} + +static int __cam_icp_config_dev_in_ready(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + size_t len; + uintptr_t packet_addr; + struct cam_packet *packet; + + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "[%s][%d] Can not get packet address", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + return rc; + } + + packet = (struct cam_packet *) ((uint8_t *)packet_addr + + (uint32_t)cmd->offset); + + if (((packet->header.op_code & 0xff) == + CAM_ICP_OPCODE_IPE_SETTINGS) || + ((packet->header.op_code & 0xff) == + CAM_ICP_OPCODE_BPS_SETTINGS)) + rc = cam_context_config_dev_to_hw(ctx, cmd); + else + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + + if (rc) + CAM_ERR(CAM_ICP, "Failed to prepare device"); + + return rc; +} + +static int __cam_icp_stop_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) + CAM_ERR(CAM_ICP, "Failed to stop device"); + + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ICP", ctx); + return rc; +} + +static int __cam_icp_release_dev_in_ready(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = __cam_icp_stop_dev_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_ICP, "Failed to stop device"); + + rc = __cam_icp_release_dev_in_acquired(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to release device"); + + return rc; +} + +static int __cam_icp_handle_buf_done_in_ready(void *ctx, + uint32_t evt_id, void *done) +{ + return cam_context_buf_done_from_hw(ctx, done, evt_id); +} + +static struct cam_ctx_ops + cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_icp_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_icp_release_dev_in_acquired, + .start_dev = __cam_icp_start_dev_in_acquired, + .config_dev = __cam_icp_config_dev_in_ready, + .flush_dev = __cam_icp_flush_dev_in_ready, + }, + .crm_ops = {}, + .irq_ops = __cam_icp_handle_buf_done_in_ready, + .pagefault_ops = cam_icp_context_dump_active_request, + }, + /* Ready */ + { + .ioctl_ops = { + .stop_dev = __cam_icp_stop_dev_in_ready, + .release_dev = __cam_icp_release_dev_in_ready, + .config_dev = __cam_icp_config_dev_in_ready, + .flush_dev = __cam_icp_flush_dev_in_ready, + }, + .crm_ops = {}, + .irq_ops = __cam_icp_handle_buf_done_in_ready, + .pagefault_ops = cam_icp_context_dump_active_request, + }, + /* Activated */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + .pagefault_ops = cam_icp_context_dump_active_request, + }, +}; + +int cam_icp_context_init(struct cam_icp_context *ctx, + struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id) +{ + int rc; + + if ((!ctx) || (!ctx->base) || (!hw_intf)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK %pK", ctx, hw_intf); + rc = -EINVAL; + goto err; + } + + rc = cam_context_init(ctx->base, icp_dev_name, CAM_ICP, ctx_id, + NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_ICP, "Camera Context Base init failed"); + goto err; + } + + ctx->base->state_machine = cam_icp_ctx_state_machine; + ctx->base->ctx_priv = ctx; + ctx->ctxt_to_hw_map = NULL; + +err: + return rc; +} + +int cam_icp_context_deinit(struct cam_icp_context *ctx) +{ + if ((!ctx) || (!ctx->base)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK", ctx); + return -EINVAL; + } + + cam_context_deinit(ctx->base); + memset(ctx, 0, sizeof(*ctx)); + + return 0; +} diff --git a/drivers/cam_icp/cam_icp_context.h b/drivers/cam_icp/cam_icp_context.h new file mode 100644 index 000000000000..edd8bd5617c9 --- /dev/null +++ b/drivers/cam_icp/cam_icp_context.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ICP_CONTEXT_H_ +#define _CAM_ICP_CONTEXT_H_ + +#include "cam_context.h" + +/** + * struct cam_icp_context - icp context + * @base: icp context object + * @state_machine: state machine for ICP context + * @req_base: common request structure + * @state: icp context state + * @ctxt_to_hw_map: context to FW handle mapping + */ +struct cam_icp_context { + struct cam_context *base; + struct cam_ctx_ops *state_machine; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + uint32_t state; + void *ctxt_to_hw_map; +}; + +/** + * cam_icp_context_init() - ICP context init + * @ctx: Pointer to context + * @hw_intf: Pointer to ICP hardware interface + * @ctx_id: ID for this context + */ +int cam_icp_context_init(struct cam_icp_context *ctx, + struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id); + +/** + * cam_icp_context_deinit() - ICP context deinit + * @ctx: Pointer to context + */ +int cam_icp_context_deinit(struct cam_icp_context *ctx); + +#endif /* _CAM_ICP_CONTEXT_H_ */ diff --git a/drivers/cam_icp/cam_icp_subdev.c b/drivers/cam_icp/cam_icp_subdev.c new file mode 100644 index 000000000000..f6dbaec5f133 --- /dev/null +++ b/drivers/cam_icp/cam_icp_subdev.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_req_mgr_dev.h" +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_context.h" +#include "cam_icp_context.h" +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +#define CAM_ICP_DEV_NAME "cam-icp" + +struct cam_icp_subdev { + struct cam_subdev sd; + struct cam_node *node; + struct cam_context ctx[CAM_ICP_CTX_MAX]; + struct cam_icp_context ctx_icp[CAM_ICP_CTX_MAX]; + struct mutex icp_lock; + int32_t open_cnt; + int32_t reserved; +}; + +static struct cam_icp_subdev g_icp_dev; + +static const struct of_device_id cam_icp_dt_match[] = { + {.compatible = "qcom,cam-icp"}, + {} +}; + +static void cam_icp_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_ICP, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static int cam_icp_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_hw_mgr_intf *hw_mgr_intf = NULL; + struct cam_node *node = v4l2_get_subdevdata(sd); + int rc = 0; + + mutex_lock(&g_icp_dev.icp_lock); + if (g_icp_dev.open_cnt >= 1) { + CAM_ERR(CAM_ICP, "ICP subdev is already opened"); + rc = -EALREADY; + goto end; + } + + if (!node) { + CAM_ERR(CAM_ICP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + hw_mgr_intf = &node->hw_mgr_intf; + rc = hw_mgr_intf->hw_open(hw_mgr_intf->hw_mgr_priv, NULL); + if (rc < 0) { + CAM_ERR(CAM_ICP, "FW download failed"); + goto end; + } + g_icp_dev.open_cnt++; +end: + mutex_unlock(&g_icp_dev.icp_lock); + return rc; +} + +static int cam_icp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_hw_mgr_intf *hw_mgr_intf = NULL; + struct cam_node *node = v4l2_get_subdevdata(sd); + + mutex_lock(&g_icp_dev.icp_lock); + if (g_icp_dev.open_cnt <= 0) { + CAM_DBG(CAM_ICP, "ICP subdev is already closed"); + rc = -EINVAL; + goto end; + } + g_icp_dev.open_cnt--; + if (!node) { + CAM_ERR(CAM_ICP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + hw_mgr_intf = &node->hw_mgr_intf; + if (!hw_mgr_intf) { + CAM_ERR(CAM_ICP, "hw_mgr_intf is not initialized"); + rc = -EINVAL; + goto end; + } + + rc = cam_node_shutdown(node); + if (rc < 0) { + CAM_ERR(CAM_ICP, "HW close failed"); + goto end; + } + +end: + mutex_unlock(&g_icp_dev.icp_lock); + return 0; +} + +const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = { + .open = cam_icp_subdev_open, + .close = cam_icp_subdev_close, +}; + +static int cam_icp_probe(struct platform_device *pdev) +{ + int rc = 0, i = 0; + struct cam_node *node; + struct cam_hw_mgr_intf *hw_mgr_intf; + int iommu_hdl = -1; + + if (!pdev) { + CAM_ERR(CAM_ICP, "pdev is NULL"); + return -EINVAL; + } + + g_icp_dev.sd.pdev = pdev; + g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops; + rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME, + CAM_ICP_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_ICP, "ICP cam_subdev_probe failed"); + goto probe_fail; + } + + node = (struct cam_node *) g_icp_dev.sd.token; + + hw_mgr_intf = kzalloc(sizeof(*hw_mgr_intf), GFP_KERNEL); + if (!hw_mgr_intf) { + rc = -EINVAL; + goto hw_alloc_fail; + } + + rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf, + &iommu_hdl); + if (rc) { + CAM_ERR(CAM_ICP, "ICP HW manager init failed: %d", rc); + goto hw_init_fail; + } + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + g_icp_dev.ctx_icp[i].base = &g_icp_dev.ctx[i]; + rc = cam_icp_context_init(&g_icp_dev.ctx_icp[i], + hw_mgr_intf, i); + if (rc) { + CAM_ERR(CAM_ICP, "ICP context init failed"); + goto ctx_fail; + } + } + + rc = cam_node_init(node, hw_mgr_intf, g_icp_dev.ctx, + CAM_ICP_CTX_MAX, CAM_ICP_DEV_NAME); + if (rc) { + CAM_ERR(CAM_ICP, "ICP node init failed"); + goto ctx_fail; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_icp_dev_iommu_fault_handler, node); + + g_icp_dev.open_cnt = 0; + mutex_init(&g_icp_dev.icp_lock); + + CAM_DBG(CAM_ICP, "ICP probe complete"); + + return rc; + +ctx_fail: + for (--i; i >= 0; i--) + cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]); +hw_init_fail: + kfree(hw_mgr_intf); +hw_alloc_fail: + cam_subdev_remove(&g_icp_dev.sd); +probe_fail: + return rc; +} + +static int cam_icp_remove(struct platform_device *pdev) +{ + int i; + struct v4l2_subdev *sd; + struct cam_subdev *subdev; + + if (!pdev) { + CAM_ERR(CAM_ICP, "pdev is NULL"); + return -ENODEV; + } + + sd = platform_get_drvdata(pdev); + if (!sd) { + CAM_ERR(CAM_ICP, "V4l2 subdev is NULL"); + return -ENODEV; + } + + subdev = v4l2_get_subdevdata(sd); + if (!subdev) { + CAM_ERR(CAM_ICP, "cam subdev is NULL"); + return -ENODEV; + } + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) + cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]); + cam_node_deinit(g_icp_dev.node); + cam_subdev_remove(&g_icp_dev.sd); + mutex_destroy(&g_icp_dev.icp_lock); + + return 0; +} + +static struct platform_driver cam_icp_driver = { + .probe = cam_icp_probe, + .remove = cam_icp_remove, + .driver = { + .name = "cam_icp", + .owner = THIS_MODULE, + .of_match_table = cam_icp_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_icp_init_module(void) +{ + return platform_driver_register(&cam_icp_driver); +} + +static void __exit cam_icp_exit_module(void) +{ + platform_driver_unregister(&cam_icp_driver); +} +module_init(cam_icp_init_module); +module_exit(cam_icp_exit_module); +MODULE_DESCRIPTION("MSM ICP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_icp/fw_inc/hfi_intf.h b/drivers/cam_icp/fw_inc/hfi_intf.h new file mode 100644 index 000000000000..1dcf4ee3668a --- /dev/null +++ b/drivers/cam_icp/fw_inc/hfi_intf.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _HFI_INTF_H_ +#define _HFI_INTF_H_ + +#include + +/** + * struct hfi_mem + * @len: length of memory + * @kva: kernel virtual address + * @iova: IO virtual address + * @reserved: reserved field + */ +struct hfi_mem { + uint64_t len; + uintptr_t kva; + uint32_t iova; + uint32_t reserved; +}; + +/** + * struct hfi_mem_info + * @qtbl: qtable hfi memory + * @cmd_q: command queue hfi memory for host to firmware communication + * @msg_q: message queue hfi memory for firmware to host communication + * @dbg_q: debug queue hfi memory for firmware debug information + * @sfr_buf: buffer for subsystem failure reason[SFR] + * @sec_heap: secondary heap hfi memory for firmware + * @qdss: qdss mapped memory for fw + * @io_mem: io memory info + * @icp_base: icp base address + */ +struct hfi_mem_info { + struct hfi_mem qtbl; + struct hfi_mem cmd_q; + struct hfi_mem msg_q; + struct hfi_mem dbg_q; + struct hfi_mem sfr_buf; + struct hfi_mem sec_heap; + struct hfi_mem shmem; + struct hfi_mem qdss; + struct hfi_mem io_mem; + void __iomem *icp_base; +}; + +/** + * hfi_write_cmd() - function for hfi write + * @cmd_ptr: pointer to command data for hfi write + * + * Returns success(zero)/failure(non zero) + */ +int hfi_write_cmd(void *cmd_ptr); + +/** + * hfi_read_message() - function for hfi read + * @pmsg: buffer to place read message for hfi queue + * @q_id: queue id + * @words_read: total number of words read from the queue + * returned as output to the caller + * + * Returns success(zero)/failure(non zero) + */ +int hfi_read_message(uint32_t *pmsg, uint8_t q_id, uint32_t *words_read); + +/** + * hfi_init() - function initialize hfi after firmware download + * @event_driven_mode: event mode + * @hfi_mem: hfi memory info + * @icp_base: icp base address + * @debug: debug flag + * + * Returns success(zero)/failure(non zero) + */ +int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, + void *__iomem icp_base, bool debug); + +/** + * hfi_get_hw_caps() - hardware capabilities from firmware + * @query_caps: holds query information from hfi + * + * Returns success(zero)/failure(non zero) + */ +int hfi_get_hw_caps(void *query_caps); + +/** + * hfi_send_system_cmd() - send hfi system command to firmware + * @type: type of system command + * @data: command data + * @size: size of command data + */ +void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size); + +/** + * cam_hfi_enable_cpu() - enable A5 CPU + * @icp_base: icp base address + */ +void cam_hfi_enable_cpu(void __iomem *icp_base); + +/** + * cam_hfi_disable_cpu() - disable A5 CPU + * @icp_base: icp base address + */ +void cam_hfi_disable_cpu(void __iomem *icp_base); + +/** + * cam_hfi_deinit() - cleanup HFI + */ +void cam_hfi_deinit(void __iomem *icp_base); +/** + * hfi_set_debug_level() - set debug level + * @a5_dbg_type: 1 for debug_q & 2 for qdss + * @lvl: FW debug message level + */ +int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl); + +/** + * hfi_set_fw_dump_level() - set firmware dump level + * @lvl: level of firmware dump level + */ +int hfi_set_fw_dump_level(uint32_t lvl); + +/** + * hfi_enable_ipe_bps_pc() - Enable interframe pc + * Host sends a command to firmware to enable interframe + * power collapse for IPE and BPS hardware. + * + * @enable: flag to enable/disable + * @core_info: Core information to firmware + */ +int hfi_enable_ipe_bps_pc(bool enable, uint32_t core_info); + +/** + * hfi_cmd_ubwc_config_ext() - UBWC configuration to firmware + * @ubwc_ipe_cfg: UBWC ipe fetch/write configuration params + * @ubwc_bps_cfg: UBWC bps fetch/write configuration params + */ +int hfi_cmd_ubwc_config_ext(uint32_t *ubwc_ipe_cfg, + uint32_t *ubwc_bps_cfg); + +/** + * hfi_cmd_ubwc_config() - UBWC configuration to firmware + * for older targets + * @ubwc_cfg: UBWC configuration parameters + */ +int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg); + +/** + * cam_hfi_resume() - function to resume + * @hfi_mem: hfi memory info + * @icp_base: icp base address + * @debug: debug flag + * + * Returns success(zero)/failure(non zero) + */ +int cam_hfi_resume(struct hfi_mem_info *hfi_mem, + void __iomem *icp_base, bool debug); + +/** + * cam_hfi_queue_dump() - utility function to dump hfi queues + */ +void cam_hfi_queue_dump(void); + + +#endif /* _HFI_INTF_H_ */ diff --git a/drivers/cam_icp/fw_inc/hfi_reg.h b/drivers/cam_icp/fw_inc/hfi_reg.h new file mode 100644 index 000000000000..f67a7044f26b --- /dev/null +++ b/drivers/cam_icp/fw_inc/hfi_reg.h @@ -0,0 +1,336 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HFI_REG_H_ +#define _CAM_HFI_REG_H_ + +#include +#include "hfi_intf.h" + + +/* start of ICP CSR registers */ +#define HFI_REG_A5_HW_VERSION 0x0 +#define HFI_REG_A5_CSR_NSEC_RESET 0x4 +#define HFI_REG_A5_CSR_A5_CONTROL 0x8 +#define HFI_REG_A5_CSR_ETM 0xC +#define HFI_REG_A5_CSR_A2HOSTINTEN 0x10 +#define HFI_REG_A5_CSR_A2HOSTINT 0x14 +#define HFI_REG_A5_CSR_A2HOSTINTCLR 0x18 +#define HFI_REG_A5_CSR_A2HOSTINTSTATUS 0x1C +#define HFI_REG_A5_CSR_A2HOSTINTSET 0x20 +#define HFI_REG_A5_CSR_HOST2ICPINT 0x30 +#define HFI_REG_A5_CSR_A5_STATUS 0x200 +#define HFI_REG_A5_QGIC2_LM_ID 0x204 +#define HFI_REG_A5_SPARE 0x400 + +/* general purpose registers from */ +#define HFI_REG_FW_VERSION 0x44 +#define HFI_REG_HOST_ICP_INIT_REQUEST 0x48 +#define HFI_REG_ICP_HOST_INIT_RESPONSE 0x4C +#define HFI_REG_SHARED_MEM_PTR 0x50 +#define HFI_REG_SHARED_MEM_SIZE 0x54 +#define HFI_REG_QTBL_PTR 0x58 +#define HFI_REG_UNCACHED_HEAP_PTR 0x5C +#define HFI_REG_UNCACHED_HEAP_SIZE 0x60 +#define HFI_REG_QDSS_IOVA 0x6C +#define HFI_REG_SFR_PTR 0x68 +#define HFI_REG_QDSS_IOVA_SIZE 0x70 +#define HFI_REG_IO_REGION_IOVA 0x74 +#define HFI_REG_IO_REGION_SIZE 0x78 + +/* end of ICP CSR registers */ + +/* flags for ICP CSR registers */ +#define ICP_FLAG_CSR_WAKE_UP_EN (1 << 4) +#define ICP_FLAG_CSR_A5_EN (1 << 9) +#define ICP_CSR_EN_CLKGATE_WFI (1 << 12) +#define ICP_CSR_EDBGRQ (1 << 14) +#define ICP_CSR_DBGSWENABLE (1 << 22) +#define ICP_CSR_A5_STATUS_WFI (1 << 7) + +#define ICP_FLAG_A5_CTRL_DBG_EN (ICP_FLAG_CSR_WAKE_UP_EN|\ + ICP_FLAG_CSR_A5_EN|\ + ICP_CSR_EDBGRQ|\ + ICP_CSR_DBGSWENABLE) + +#define ICP_FLAG_A5_CTRL_EN (ICP_FLAG_CSR_WAKE_UP_EN|\ + ICP_FLAG_CSR_A5_EN|\ + ICP_CSR_EN_CLKGATE_WFI) + +/* start of Queue table and queues */ +#define MAX_ICP_HFI_QUEUES 4 +#define ICP_QHDR_TX_TYPE_MASK 0xFF000000 +#define ICP_QHDR_RX_TYPE_MASK 0x00FF0000 +#define ICP_QHDR_PRI_TYPE_MASK 0x0000FF00 +#define ICP_QHDR_Q_ID_MASK 0x000000FF + +#define ICP_CMD_Q_SIZE_IN_BYTES 4096 +#define ICP_MSG_Q_SIZE_IN_BYTES 4096 +#define ICP_DBG_Q_SIZE_IN_BYTES 102400 +#define ICP_MSG_SFR_SIZE_IN_BYTES 4096 + +#define ICP_SHARED_MEM_IN_BYTES (1024 * 1024) +#define ICP_UNCACHED_HEAP_SIZE_IN_BYTES (2 * 1024 * 1024) +#define ICP_HFI_MAX_PKT_SIZE_IN_WORDS 25600 +#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS 256 + +#define ICP_HFI_QTBL_HOSTID1 0x01000000 +#define ICP_HFI_QTBL_STATUS_ENABLED 0x00000001 +#define ICP_HFI_NUMBER_OF_QS 3 +#define ICP_HFI_NUMBER_OF_ACTIVE_QS 3 +#define ICP_HFI_QTBL_OFFSET 0 +#define ICP_HFI_VAR_SIZE_PKT 0 +#define ICP_HFI_MAX_MSG_SIZE_IN_WORDS 128 + + +/* Queue Header type masks. Use these to access bitfields in qhdr_type */ +#define HFI_MASK_QHDR_TX_TYPE 0xFF000000 +#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000 +#define HFI_MASK_QHDR_PRI_TYPE 0x0000FF00 +#define HFI_MASK_QHDR_Q_ID_TYPE 0x000000FF + + +#define TX_EVENT_DRIVEN_MODE_1 0 +#define RX_EVENT_DRIVEN_MODE_1 0 +#define TX_EVENT_DRIVEN_MODE_2 0x01000000 +#define RX_EVENT_DRIVEN_MODE_2 0x00010000 +#define TX_EVENT_POLL_MODE_2 0x02000000 +#define RX_EVENT_POLL_MODE_2 0x00020000 +#define U32_OFFSET 0x1 +#define BYTE_WORD_SHIFT 2 + +/** + * @INVALID: Invalid state + * @HFI_DEINIT: HFI is not initialized yet + * @HFI_INIT: HFI is initialized + * @HFI_READY: HFI is ready to send/receive commands/messages + */ +enum hfi_state { + HFI_DEINIT, + HFI_INIT, + HFI_READY +}; + +/** + * @RESET: init success + * @SET: init failed + */ +enum reg_settings { + RESET, + SET, + SET_WM = 1024 +}; + +/** + * @INTR_DISABLE: Disable interrupt + * @INTR_ENABLE: Enable interrupt + * @INTR_ENABLE_WD0: Enable WD0 + * @INTR_ENABLE_WD1: Enable WD1 + */ +enum intr_status { + INTR_DISABLE, + INTR_ENABLE, + INTR_ENABLE_WD0, + INTR_ENABLE_WD1 = 0x4 +}; + +/** + * @ICP_INIT_RESP_RESET: reset init state + * @ICP_INIT_RESP_SUCCESS: init success + * @ICP_INIT_RESP_FAILED: init failed + */ +enum host_init_resp { + ICP_INIT_RESP_RESET, + ICP_INIT_RESP_SUCCESS, + ICP_INIT_RESP_FAILED +}; + +/** + * @ICP_INIT_REQUEST_RESET: reset init request + * @ICP_INIT_REQUEST_SET: set init request + */ +enum host_init_request { + ICP_INIT_REQUEST_RESET, + ICP_INIT_REQUEST_SET +}; + +/** + * @QHDR_INACTIVE: Queue is inactive + * @QHDR_ACTIVE: Queue is active + */ +enum qhdr_status { + QHDR_INACTIVE, + QHDR_ACTIVE +}; + +/** + * @INTR_MODE: event driven mode 1, each send and receive generates interrupt + * @WM_MODE: event driven mode 2, interrupts based on watermark mechanism + * @POLL_MODE: poll method + */ +enum qhdr_event_drv_type { + INTR_MODE, + WM_MODE, + POLL_MODE +}; + +/** + * @TX_INT: event driven mode 1, each send and receive generates interrupt + * @TX_INT_WM: event driven mode 2, interrupts based on watermark mechanism + * @TX_POLL: poll method + * @ICP_QHDR_TX_TYPE_MASK defines position in qhdr_type + */ +enum qhdr_tx_type { + TX_INT, + TX_INT_WM, + TX_POLL +}; + +/** + * @RX_INT: event driven mode 1, each send and receive generates interrupt + * @RX_INT_WM: event driven mode 2, interrupts based on watermark mechanism + * @RX_POLL: poll method + * @ICP_QHDR_RX_TYPE_MASK defines position in qhdr_type + */ +enum qhdr_rx_type { + RX_INT, + RX_INT_WM, + RX_POLL +}; + +/** + * @Q_CMD: Host to FW command queue + * @Q_MSG: FW to Host message queue + * @Q_DEBUG: FW to Host debug queue + * @ICP_QHDR_Q_ID_MASK defines position in qhdr_type + */ +enum qhdr_q_id { + Q_CMD, + Q_MSG, + Q_DBG +}; + +/** + * struct hfi_qtbl_hdr + * @qtbl_version: Queue table version number + * Higher 16 bits: Major version + * Lower 16 bits: Minor version + * @qtbl_size: Queue table size from version to last parametr in qhdr entry + * @qtbl_qhdr0_offset: Offset to the start of first qhdr + * @qtbl_qhdr_size: Queue header size in bytes + * @qtbl_num_q: Total number of queues in Queue table + * @qtbl_num_active_q: Total number of active queues + */ +struct hfi_qtbl_hdr { + uint32_t qtbl_version; + uint32_t qtbl_size; + uint32_t qtbl_qhdr0_offset; + uint32_t qtbl_qhdr_size; + uint32_t qtbl_num_q; + uint32_t qtbl_num_active_q; +} __packed; + +/** + * struct hfi_q_hdr + * @qhdr_status: Queue status, qhdr_state define possible status + * @qhdr_start_addr: Queue start address in non cached memory + * @qhdr_type: qhdr_tx, qhdr_rx, qhdr_q_id and priority defines qhdr type + * @qhdr_q_size: Queue size + * Number of queue packets if qhdr_pkt_size is non-zero + * Queue size in bytes if qhdr_pkt_size is zero + * @qhdr_pkt_size: Size of queue packet entries + * 0x0: variable queue packet size + * non zero: size of queue packet entry, fixed + * @qhdr_pkt_drop_cnt: Number of packets dropped by sender + * @qhdr_rx_wm: Receiver watermark, applicable in event driven mode + * @qhdr_tx_wm: Sender watermark, applicable in event driven mode + * @qhdr_rx_req: Receiver sets this bit if queue is empty + * @qhdr_tx_req: Sender sets this bit if queue is full + * @qhdr_rx_irq_status: Receiver sets this bit and triggers an interrupt to + * the sender after packets are dequeued. Sender clears this bit + * @qhdr_tx_irq_status: Sender sets this bit and triggers an interrupt to + * the receiver after packets are queued. Receiver clears this bit + * @qhdr_read_idx: Read index + * @qhdr_write_idx: Write index + */ +struct hfi_q_hdr { + uint32_t dummy[15]; + uint32_t qhdr_status; + uint32_t dummy1[15]; + uint32_t qhdr_start_addr; + uint32_t dummy2[15]; + uint32_t qhdr_type; + uint32_t dummy3[15]; + uint32_t qhdr_q_size; + uint32_t dummy4[15]; + uint32_t qhdr_pkt_size; + uint32_t dummy5[15]; + uint32_t qhdr_pkt_drop_cnt; + uint32_t dummy6[15]; + uint32_t qhdr_rx_wm; + uint32_t dummy7[15]; + uint32_t qhdr_tx_wm; + uint32_t dummy8[15]; + uint32_t qhdr_rx_req; + uint32_t dummy9[15]; + uint32_t qhdr_tx_req; + uint32_t dummy10[15]; + uint32_t qhdr_rx_irq_status; + uint32_t dummy11[15]; + uint32_t qhdr_tx_irq_status; + uint32_t dummy12[15]; + uint32_t qhdr_read_idx; + uint32_t dummy13[15]; + uint32_t qhdr_write_idx; + uint32_t dummy14[15]; +}; + +/** + * struct sfr_buf + * @size: Number of characters + * @msg : Subsystem failure reason + */ +struct sfr_buf { + uint32_t size; + char msg[ICP_MSG_SFR_SIZE_IN_BYTES]; +}; + +/** + * struct hfi_q_tbl + * @q_tbl_hdr: Queue table header + * @q_hdr: Queue header info, it holds info of cmd, msg and debug queues + */ +struct hfi_qtbl { + struct hfi_qtbl_hdr q_tbl_hdr; + struct hfi_q_hdr q_hdr[MAX_ICP_HFI_QUEUES]; +}; + +/** + * struct hfi_info + * @map: Hfi shared memory info + * @smem_size: Shared memory size + * @uncachedheap_size: uncached heap size + * @msgpacket_buf: message buffer + * @hfi_state: State machine for hfi + * @cmd_q_lock: Lock for command queue + * @cmd_q_state: State of command queue + * @mutex msg_q_lock: Lock for message queue + * @msg_q_state: State of message queue + * @csr_base: CSR base address + */ +struct hfi_info { + struct hfi_mem_info map; + uint32_t smem_size; + uint32_t uncachedheap_size; + uint32_t msgpacket_buf[ICP_HFI_MAX_MSG_SIZE_IN_WORDS]; + uint8_t hfi_state; + struct mutex cmd_q_lock; + bool cmd_q_state; + struct mutex msg_q_lock; + bool msg_q_state; + void __iomem *csr_base; +}; + +#endif /* _CAM_HFI_REG_H_ */ diff --git a/drivers/cam_icp/fw_inc/hfi_session_defs.h b/drivers/cam_icp/fw_inc/hfi_session_defs.h new file mode 100644 index 000000000000..e50b5d147a2f --- /dev/null +++ b/drivers/cam_icp/fw_inc/hfi_session_defs.h @@ -0,0 +1,564 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HFI_SESSION_DEFS_H +#define _CAM_HFI_SESSION_DEFS_H + +#include + +#define HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO 0x1 +#define HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS 0x2 +#define HFI_IPEBPS_CMD_OPCODE_BPS_ABORT 0x3 +#define HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY 0x4 + +#define HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO 0x5 +#define HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS 0x6 +#define HFI_IPEBPS_CMD_OPCODE_IPE_ABORT 0x7 +#define HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY 0x8 + +#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_IPE 0x9 +#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_BPS 0xa +#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_BPS 0xb +#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_IPE 0xc + +#define HFI_IPEBPS_CMD_OPCODE_MEM_MAP 0xe +#define HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP 0xf + +#define HFI_IPEBPS_HANDLE_TYPE_BPS 0x1 +#define HFI_IPEBPS_HANDLE_TYPE_IPE_RT 0x2 +#define HFI_IPEBPS_HANDLE_TYPE_IPE_NON_RT 0x3 + +/** + * struct mem_map_region_data + * @start_addr: cmd buffer region start addr + * @len : length of the region + * + * create mem_map_region_data + */ +struct mem_map_region_data { + uint32_t start_addr; + uint32_t len; +}; + +/** + * struct hfi_cmd_ipe_bps_map + * @user_data : user arg + * @mem_map_request_num: number of mappings + * @mem_map_region_sets: array of all map/unmap info + * + * create hfi_cmd_ipe_bps_map + */ +struct hfi_cmd_ipe_bps_map { + uint64_t user_data; + uint32_t mem_map_request_num; + struct mem_map_region_data mem_map_region_sets[1]; +} __packed; + +/** + * struct hfi_cmd_ipe_bps_map_ack + * @rc : Async return code + * @user_data: user_arg + * + * create hfi_cmd_ipe_bps_map_ack + */ +struct hfi_cmd_ipe_bps_map_ack { + uint32_t rc; + uint64_t user_data; +}; + +/** + * struct abort_data + * @num_req_ids: Number of req ids + * @num_req_id: point to specific req id + * + * create abort data + */ +struct abort_data { + uint32_t num_req_ids; + uint32_t num_req_id[1]; +}; + +/** + * struct hfi_cmd_data + * @abort: abort data + * @user data: user supplied argument + * + * create session abort data + */ +struct hfi_cmd_abort { + struct abort_data abort; + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_abort_destroy + * @user_data: user supplied data + * + * IPE/BPS destroy/abort command + * @HFI_IPEBPS_CMD_OPCODE_IPE_ABORT + * @HFI_IPEBPS_CMD_OPCODE_BPS_ABORT + * @HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY + * @HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY + */ +struct hfi_cmd_abort_destroy { + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_chaining_ops + * @wait_hdl: current session handle waits on wait_hdl to complete operation + * @user_data: user supplied argument + * + * this structure for chaining opcodes + * BPS_WAITS_FOR_IPE + * BPS_WAITS_FOR_BPS + * IPE_WAITS_FOR_BPS + * IPE_WAITS_FOR_IPE + */ +struct hfi_cmd_chaining_ops { + uint32_t wait_hdl; + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_create_handle + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @handle_type: IPE/BPS firmware session handle type + * @user_data1: caller provided data1 + * @user_data2: caller provided data2 + * + * create firmware session handle + */ +struct hfi_cmd_create_handle { + uint32_t size; + uint32_t pkt_type; + uint32_t handle_type; + uint64_t user_data1; + uint64_t user_data2; +} __packed; + +/** + * struct hfi_cmd_ipebps_async + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @opcode: opcode for IPE/BPS async operation + * CONFIG_IO: configures I/O for IPE/BPS handle + * FRAME_PROCESS: image frame to be processed by IPE/BPS + * ABORT: abort all processing frames of IPE/BPS handle + * DESTROY: destroy earlier created IPE/BPS handle + * BPS_WAITS_FOR_IPE: sync for BPS to wait for IPE + * BPS_WAITS_FOR_BPS: sync for BPS to wait for BPS + * IPE_WAITS_FOR_IPE: sync for IPE to wait for IPE + * IPE_WAITS_FOR_BPS: sync for IPE to wait for BPS + * @num_fw_handles: number of IPE/BPS firmware handles in fw_handles array + * @fw_handles: IPE/BPS handles array + * @payload: command payload for IPE/BPS opcodes + * @direct: points to actual payload + * @indirect: points to address of payload + * + * sends async command to the earlier created IPE or BPS handle + * for asynchronous operation. + */ +struct hfi_cmd_ipebps_async { + uint32_t size; + uint32_t pkt_type; + uint32_t opcode; + uint64_t user_data1; + uint64_t user_data2; + uint32_t num_fw_handles; + uint32_t fw_handles[1]; + union { + uint32_t direct[1]; + uint32_t indirect; + } payload; +} __packed; + +/** + * struct hfi_msg_create_handle_ack + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @err_type: error code + * @fw_handle: output param for IPE/BPS handle + * @user_data1: user provided data1 + * @user_data2: user provided data2 + * + * ack for create handle command of IPE/BPS + * @HFI_MSG_IPEBPS_CREATE_HANDLE_ACK + */ +struct hfi_msg_create_handle_ack { + uint32_t size; + uint32_t pkt_type; + uint32_t err_type; + uint32_t fw_handle; + uint64_t user_data1; + uint64_t user_data2; +} __packed; + +/** + * struct hfi_msg_ipebps_async + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @opcode: opcode of IPE/BPS async operation + * @user_data1: user provided data1 + * @user_data2: user provided data2 + * @err_type: error code + * @msg_data: IPE/BPS async done message data + * + * result of IPE/BPS async command + * @HFI_MSG_IPEBPS_ASYNC_COMMAND_ACK + */ +struct hfi_msg_ipebps_async_ack { + uint32_t size; + uint32_t pkt_type; + uint32_t opcode; + uint64_t user_data1; + uint64_t user_data2; + uint32_t err_type; + uint32_t msg_data[1]; +} __packed; + +/** + * struct hfi_msg_frame_process_done + * @result: result of frame process command + * @scratch_buffer_address: address of scratch buffer + */ +struct hfi_msg_frame_process_done { + uint32_t result; + uint32_t scratch_buffer_address; +}; + +/** + * struct hfi_msg_chaining_op + * @status: return status + * @user_data: user data provided as part of chaining ops + * + * IPE/BPS wait response + */ +struct hfi_msg_chaining_op { + uint32_t status; + uint64_t user_data; +} __packed; + +/** + * struct hfi_msg_abort_destroy + * @status: return status + * @user_data: user data provided as part of abort/destroy ops + * + * IPE/BPS abort/destroy response + */ +struct hfi_msg_abort_destroy { + uint32_t status; + uint64_t user_data; +} __packed; + +#define MAX_NUM_OF_IMAGE_PLANES 2 +#define MAX_HFR_GROUP 16 + +enum hfi_ipe_io_images { + IPE_INPUT_IMAGE_FULL, + IPE_INPUT_IMAGE_DS4, + IPE_INPUT_IMAGE_DS16, + IPE_INPUT_IMAGE_DS64, + IPE_INPUT_IMAGE_FULL_REF, + IPE_INPUT_IMAGE_DS4_REF, + IPE_INPUT_IMAGE_DS16_REF, + IPE_INPUT_IMAGE_DS64_REF, + IPE_OUTPUT_IMAGE_DISPLAY, + IPE_OUTPUT_IMAGE_VIDEO, + IPE_OUTPUT_IMAGE_FULL_REF, + IPE_OUTPUT_IMAGE_DS4_REF, + IPE_OUTPUT_IMAGE_DS16_REF, + IPE_OUTPUT_IMAGE_DS64_REF, + IPE_INPUT_IMAGE_FIRST = IPE_INPUT_IMAGE_FULL, + IPE_INPUT_IMAGE_LAST = IPE_INPUT_IMAGE_DS64_REF, + IPE_OUTPUT_IMAGE_FIRST = IPE_OUTPUT_IMAGE_DISPLAY, + IPE_OUTPUT_IMAGE_LAST = IPE_OUTPUT_IMAGE_DS64_REF, + IPE_IO_IMAGES_MAX +}; + +enum bps_io_images { + BPS_INPUT_IMAGE, + BPS_OUTPUT_IMAGE_FULL, + BPS_OUTPUT_IMAGE_DS4, + BPS_OUTPUT_IMAGE_DS16, + BPS_OUTPUT_IMAGE_DS64, + BPS_OUTPUT_IMAGE_STATS_BG, + BPS_OUTPUT_IMAGE_STATS_BHIST, + BPS_OUTPUT_IMAGE_REG1, + BPS_OUTPUT_IMAGE_REG2, + BPS_OUTPUT_IMAGE_FIRST = BPS_OUTPUT_IMAGE_FULL, + BPS_OUTPUT_IMAGE_LAST = BPS_OUTPUT_IMAGE_REG2, + BPS_IO_IMAGES_MAX +}; + +struct frame_buffer { + uint32_t buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; + uint32_t meta_buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; +} __packed; + +struct bps_frame_process_data { + struct frame_buffer buffers[BPS_IO_IMAGES_MAX]; + uint32_t max_num_cores; + uint32_t target_time; + uint32_t ubwc_stats_buffer_addr; + uint32_t ubwc_stats_buffer_size; + uint32_t cdm_buffer_addr; + uint32_t cdm_buffer_size; + uint32_t iq_settings_addr; + uint32_t strip_lib_out_addr; + uint32_t cdm_prog_addr; + uint32_t request_id; +}; + +enum hfi_ipe_image_format { + IMAGE_FORMAT_INVALID, + IMAGE_FORMAT_MIPI_8, + IMAGE_FORMAT_MIPI_10, + IMAGE_FORMAT_MIPI_12, + IMAGE_FORMAT_MIPI_14, + IMAGE_FORMAT_BAYER_8, + IMAGE_FORMAT_BAYER_10, + IMAGE_FORMAT_BAYER_12, + IMAGE_FORMAT_BAYER_14, + IMAGE_FORMAT_PDI_10, + IMAGE_FORMAT_PD_10, + IMAGE_FORMAT_PD_8, + IMAGE_FORMAT_INDICATIONS, + IMAGE_FORMAT_REFINEMENT, + IMAGE_FORMAT_UBWC_TP_10, + IMAGE_FORMAT_UBWC_NV_12, + IMAGE_FORMAT_UBWC_NV12_4R, + IMAGE_FORMAT_UBWC_P010, + IMAGE_FORMAT_LINEAR_TP_10, + IMAGE_FORMAT_LINEAR_P010, + IMAGE_FORMAT_LINEAR_NV12, + IMAGE_FORMAT_LINEAR_PLAIN_16, + IMAGE_FORMAT_YUV422_8, + IMAGE_FORMAT_YUV422_10, + IMAGE_FORMAT_STATISTICS_BAYER_GRID, + IMAGE_FORMAT_STATISTICS_BAYER_HISTOGRAM, + IMAGE_FORMAT_MAX +}; + +enum hfi_ipe_plane_format { + PLANE_FORMAT_INVALID = 0, + PLANE_FORMAT_MIPI_8, + PLANE_FORMAT_MIPI_10, + PLANE_FORMAT_MIPI_12, + PLANE_FORMAT_MIPI_14, + PLANE_FORMAT_BAYER_8, + PLANE_FORMAT_BAYER_10, + PLANE_FORMAT_BAYER_12, + PLANE_FORMAT_BAYER_14, + PLANE_FORMAT_PDI_10, + PLANE_FORMAT_PD_10, + PLANE_FORMAT_PD_8, + PLANE_FORMAT_INDICATIONS, + PLANE_FORMAT_REFINEMENT, + PLANE_FORMAT_UBWC_TP_10_Y, + PLANE_FORMAT_UBWC_TP_10_C, + PLANE_FORMAT_UBWC_NV_12_Y, + PLANE_FORMAT_UBWC_NV_12_C, + PLANE_FORMAT_UBWC_NV_12_4R_Y, + PLANE_FORMAT_UBWC_NV_12_4R_C, + PLANE_FORMAT_UBWC_P010_Y, + PLANE_FORMAT_UBWC_P010_C, + PLANE_FORMAT_LINEAR_TP_10_Y, + PLANE_FORMAT_LINEAR_TP_10_C, + PLANE_FORMAT_LINEAR_P010_Y, + PLANE_FORMAT_LINEAR_P010_C, + PLANE_FORMAT_LINEAR_NV12_Y, + PLANE_FORMAT_LINEAR_NV12_C, + PLANE_FORMAT_LINEAR_PLAIN_16_Y, + PLANE_FORMAT_LINEAR_PLAIN_16_C, + PLANE_FORMAT_YUV422_8, + PLANE_FORMAT_YUV422_10, + PLANE_FORMAT_STATISTICS_BAYER_GRID, + PLANE_FORMAT_STATISTICS_BAYER_HISTOGRAM, + PLANE_FORMAT_MAX +}; + +enum hfi_ipe_bayer_pixel_order { + FIRST_PIXEL_R, + FIRST_PIXEL_GR, + FIRST_PIXEL_B, + FIRST_PIXEL_GB, + FIRST_PIXEL_MAX +}; + +enum hfi_ipe_pixel_pack_alignment { + PIXEL_LSB_ALIGNED, + PIXEL_MSB_ALIGNED, +}; + +enum hfi_ipe_yuv_422_order { + PIXEL_ORDER_Y_U_Y_V, + PIXEL_ORDER_Y_V_Y_U, + PIXEL_ORDER_U_Y_V_Y, + PIXEL_ORDER_V_Y_U_Y, + PIXEL_ORDER_YUV422_MAX +}; + +enum ubwc_write_client { + IPE_WR_CLIENT_0 = 0, + IPE_WR_CLIENT_1, + IPE_WR_CLIENT_5, + IPE_WR_CLIENT_6, + IPE_WR_CLIENT_7, + IPE_WR_CLIENT_8, + IPE_WR_CLIENT_MAX +}; + +/** + * struct image_info + * @format: image format + * @img_width: image width + * @img_height: image height + * @bayer_order: pixel order + * @pix_align: alignment + * @yuv422_order: YUV order + * @byte_swap: byte swap + */ +struct image_info { + enum hfi_ipe_image_format format; + uint32_t img_width; + uint32_t img_height; + enum hfi_ipe_bayer_pixel_order bayer_order; + enum hfi_ipe_pixel_pack_alignment pix_align; + enum hfi_ipe_yuv_422_order yuv422_order; + uint32_t byte_swap; +} __packed; + +/** + * struct buffer_layout + * @buf_stride: buffer stride + * @buf_height: buffer height + */ +struct buffer_layout { + uint32_t buf_stride; + uint32_t buf_height; +} __packed; + +/** + * struct image_desc + * @info: image info + * @buf_layout: buffer layout + * @meta_buf_layout: meta buffer layout + */ +struct image_desc { + struct image_info info; + struct buffer_layout buf_layout[MAX_NUM_OF_IMAGE_PLANES]; + struct buffer_layout meta_buf_layout[MAX_NUM_OF_IMAGE_PLANES]; +} __packed; + +struct ica_stab_coeff { + uint32_t coeffs[8]; +} __packed; + +struct ica_stab_params { + uint32_t mode; + struct ica_stab_coeff transforms[3]; +} __packed; + +struct frame_set { + struct frame_buffer buffers[IPE_IO_IMAGES_MAX]; + struct ica_stab_params ica_params; + uint32_t cdm_ica1_addr; + uint32_t cdm_ica2_addr; +} __packed; + +struct ipe_frame_process_data { + uint32_t strip_lib_out_addr; + uint32_t iq_settings_addr; + uint32_t scratch_buffer_addr; + uint32_t scratch_buffer_size; + uint32_t ubwc_stats_buffer_addr; + uint32_t ubwc_stats_buffer_size; + uint32_t cdm_buffer_addr; + uint32_t cdm_buffer_size; + uint32_t max_num_cores; + uint32_t target_time; + uint32_t cdm_prog_base; + uint32_t cdm_pre_ltm; + uint32_t cdm_post_ltm; + uint32_t cdm_anr_full_pass; + uint32_t cdm_anr_ds4; + uint32_t cdm_anr_ds16; + uint32_t cdm_anr_ds64; + uint32_t cdm_tf_full_pass; + uint32_t cdm_tf_ds4; + uint32_t cdm_tf_ds16; + uint32_t cdm_tf_ds64; + uint32_t request_id; + uint32_t frames_in_batch; + struct frame_set framesets[MAX_HFR_GROUP]; +} __packed; + +/** + * struct hfi_cmd_ipe_config + * @images: images descreptions + * @user_data: user supplied data + * + * payload for IPE async command + */ +struct hfi_cmd_ipe_config { + struct image_desc images[IPE_IO_IMAGES_MAX]; + uint64_t user_data; +} __packed; + +/** + * struct frame_buffers + * @buf_ptr: buffer pointers for all planes + * @meta_buf_ptr: meta buffer pointers for all planes + */ +struct frame_buffers { + uint32_t buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; + uint32_t meta_buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; +} __packed; + +/** + * struct hfi_msg_ipe_config + * @rc: result of ipe config command + * @scratch_mem_size: scratch mem size for a config + * @user_data: user data + */ +struct hfi_msg_ipe_config { + uint32_t rc; + uint32_t scratch_mem_size; + uint64_t user_data; +} __packed; + +/** + * struct hfi_msg_bps_common + * @rc: result of ipe config command + * @user_data: user data + */ +struct hfi_msg_bps_common { + uint32_t rc; + uint64_t user_data; +} __packed; + +/** + * struct ipe_bps_destroy + * @user_data: user data + */ +struct ipe_bps_destroy { + uint64_t userdata; +}; + +/** + * struct hfi_msg_ipe_frame_process + * @status: result of ipe frame process command + * @scratch_buf_addr: address of scratch buffer + * @user_data: user data + */ +struct hfi_msg_ipe_frame_process { + uint32_t status; + uint32_t scratch_buf_addr; + uint64_t user_data; +} __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 new file mode 100644 index 000000000000..ddd9bf15c6aa --- /dev/null +++ b/drivers/cam_icp/fw_inc/hfi_sys_defs.h @@ -0,0 +1,540 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _HFI_DEFS_H_ +#define _HFI_DEFS_H_ + +#include + +/* + * Following base acts as common starting points + * for all enumerations. + */ +#define HFI_COMMON_BASE 0x0 + +/* HFI Domain base offset for commands and messages */ +#define HFI_DOMAIN_SHFT (24) +#define HFI_DOMAIN_BMSK (0x7 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_ICP (0x0 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_IPE_BPS (0x1 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_CDM (0x2 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_DBG (0x3 << HFI_DOMAIN_SHFT) + +/* Command base offset for commands */ +#define HFI_CMD_START_OFFSET 0x10000 + +/* Command base offset for messages */ +#define HFI_MSG_START_OFFSET 0x20000 + +/* System Level Error types */ +#define HFI_ERR_SYS_NONE (HFI_COMMON_BASE) +#define HFI_ERR_SYS_FATAL (HFI_COMMON_BASE + 0x1) +#define HFI_ERR_SYS_VERSION_MISMATCH (HFI_COMMON_BASE + 0x2) +#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN (HFI_COMMON_BASE + 0x3) +#define HFI_ERR_SYS_UNSUPPORT_CMD (HFI_COMMON_BASE + 0x4) +#define HFI_ERR_SYS_CMDFAILED (HFI_COMMON_BASE + 0x5) +#define HFI_ERR_SYS_CMDSIZE (HFI_COMMON_BASE + 0x6) + +/* System Level Event types */ +#define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1) +#define HFI_EVENT_ICP_ERROR (HFI_COMMON_BASE + 0x2) +#define HFI_EVENT_IPE_BPS_ERROR (HFI_COMMON_BASE + 0x3) +#define HFI_EVENT_CDM_ERROR (HFI_COMMON_BASE + 0x4) +#define HFI_EVENT_DBG_ERROR (HFI_COMMON_BASE + 0x5) + +/* Core level start Ranges for errors */ +#define HFI_ERR_ICP_START (HFI_COMMON_BASE + 0x64) +#define HFI_ERR_IPE_BPS_START (HFI_ERR_ICP_START + 0x64) +#define HFI_ERR_CDM_START (HFI_ERR_IPE_BPS_START + 0x64) +#define HFI_ERR_DBG_START (HFI_ERR_CDM_START + 0x64) + +/*ICP Core level error messages */ +#define HFI_ERR_NO_RES (HFI_ERR_ICP_START + 0x1) +#define HFI_ERR_UNSUPPORTED_RES (HFI_ERR_ICP_START + 0x2) +#define HFI_ERR_UNSUPPORTED_PROP (HFI_ERR_ICP_START + 0x3) +#define HFI_ERR_INIT_EXPECTED (HFI_ERR_ICP_START + 0x4) +#define HFI_ERR_INIT_IGNORED (HFI_ERR_ICP_START + 0x5) + +/* System level commands */ +#define HFI_CMD_COMMON_START \ + (HFI_DOMAIN_BASE_ICP + HFI_CMD_START_OFFSET + 0x0) +#define HFI_CMD_SYS_INIT (HFI_CMD_COMMON_START + 0x1) +#define HFI_CMD_SYS_PC_PREP (HFI_CMD_COMMON_START + 0x2) +#define HFI_CMD_SYS_SET_PROPERTY (HFI_CMD_COMMON_START + 0x3) +#define HFI_CMD_SYS_GET_PROPERTY (HFI_CMD_COMMON_START + 0x4) +#define HFI_CMD_SYS_PING (HFI_CMD_COMMON_START + 0x5) +#define HFI_CMD_SYS_RESET (HFI_CMD_COMMON_START + 0x6) + +/* Core level commands */ +/* IPE/BPS core Commands */ +#define HFI_CMD_IPE_BPS_COMMON_START \ + (HFI_DOMAIN_BASE_IPE_BPS + HFI_CMD_START_OFFSET + 0x0) +#define HFI_CMD_IPEBPS_CREATE_HANDLE \ + (HFI_CMD_IPE_BPS_COMMON_START + 0x8) +#define HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT \ + (HFI_CMD_IPE_BPS_COMMON_START + 0xa) +#define HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT \ + (HFI_CMD_IPE_BPS_COMMON_START + 0xe) + +/* CDM core Commands */ +#define HFI_CMD_CDM_COMMON_START \ + (HFI_DOMAIN_BASE_CDM + HFI_CMD_START_OFFSET + 0x0) +#define HFI_CMD_CDM_TEST_START (HFI_CMD_CDM_COMMON_START + 0x800) +#define HFI_CMD_CDM_END (HFI_CMD_CDM_COMMON_START + 0xFFF) + +/* Debug/Test Commands */ +#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_END (HFI_CMD_DBG_COMMON_START + 0xFFF) + +/* System level messages */ +#define HFI_MSG_ICP_COMMON_START \ + (HFI_DOMAIN_BASE_ICP + HFI_MSG_START_OFFSET + 0x0) +#define HFI_MSG_SYS_INIT_DONE (HFI_MSG_ICP_COMMON_START + 0x1) +#define HFI_MSG_SYS_PC_PREP_DONE (HFI_MSG_ICP_COMMON_START + 0x2) +#define HFI_MSG_SYS_DEBUG (HFI_MSG_ICP_COMMON_START + 0x3) +#define HFI_MSG_SYS_IDLE (HFI_MSG_ICP_COMMON_START + 0x4) +#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_ICP_COMMON_START + 0x5) +#define HFI_MSG_SYS_PING_ACK (HFI_MSG_ICP_COMMON_START + 0x6) +#define HFI_MSG_SYS_RESET_ACK (HFI_MSG_ICP_COMMON_START + 0x7) +#define HFI_MSG_EVENT_NOTIFY (HFI_MSG_ICP_COMMON_START + 0x8) + +/* Core level Messages */ +/* IPE/BPS core Messages */ +#define HFI_MSG_IPE_BPS_COMMON_START \ + (HFI_DOMAIN_BASE_IPE_BPS + HFI_MSG_START_OFFSET + 0x0) +#define HFI_MSG_IPEBPS_CREATE_HANDLE_ACK \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x08) +#define HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x0a) +#define HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x0e) +#define HFI_MSG_IPE_BPS_TEST_START \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x800) +#define HFI_MSG_IPE_BPS_END \ + (HFI_MSG_IPE_BPS_COMMON_START + 0xFFF) + +/* CDM core Messages */ +#define HFI_MSG_CDM_COMMON_START \ + (HFI_DOMAIN_BASE_CDM + HFI_MSG_START_OFFSET + 0x0) +#define HFI_MSG_PRI_CDM_PAYLOAD_ACK (HFI_MSG_CDM_COMMON_START + 0xa) +#define HFI_MSG_PRI_LLD_PAYLOAD_ACK (HFI_MSG_CDM_COMMON_START + 0xb) +#define HFI_MSG_CDM_TEST_START (HFI_MSG_CDM_COMMON_START + 0x800) +#define HFI_MSG_CDM_END (HFI_MSG_CDM_COMMON_START + 0xFFF) + +/* core level test command ranges */ +/* ICP core level test command range */ +#define HFI_CMD_ICP_TEST_START (HFI_CMD_ICP_COMMON_START + 0x800) +#define HFI_CMD_ICP_END (HFI_CMD_ICP_COMMON_START + 0xFFF) + +/* IPE/BPS core level test command range */ +#define HFI_CMD_IPE_BPS_TEST_START \ + (HFI_CMD_IPE_BPS_COMMON_START + 0x800) +#define HFI_CMD_IPE_BPS_END (HFI_CMD_IPE_BPS_COMMON_START + 0xFFF) + +/* ICP core level test message range */ +#define HFI_MSG_ICP_TEST_START (HFI_MSG_ICP_COMMON_START + 0x800) +#define HFI_MSG_ICP_END (HFI_MSG_ICP_COMMON_START + 0xFFF) + +/* ICP core level Debug test message range */ +#define HFI_MSG_DBG_COMMON_START \ + (HFI_DOMAIN_BASE_DBG + 0x0) +#define HFI_MSG_DBG_TEST_START (HFI_MSG_DBG_COMMON_START + 0x800) +#define HFI_MSG_DBG_END (HFI_MSG_DBG_COMMON_START + 0xFFF) + +/* System level property base offset */ +#define HFI_PROPERTY_ICP_COMMON_START (HFI_DOMAIN_BASE_ICP + 0x0) + +#define HFI_PROP_SYS_DEBUG_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x1) +#define HFI_PROP_SYS_UBWC_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x2) +#define HFI_PROP_SYS_IMAGE_VER (HFI_PROPERTY_ICP_COMMON_START + 0x3) +#define HFI_PROP_SYS_SUPPORTED (HFI_PROPERTY_ICP_COMMON_START + 0x4) +#define HFI_PROP_SYS_IPEBPS_PC (HFI_PROPERTY_ICP_COMMON_START + 0x5) +#define HFI_PROP_SYS_FW_DUMP_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x8) +#define HFI_PROPERTY_SYS_UBWC_CONFIG_EX (HFI_PROPERTY_ICP_COMMON_START + 0x9) + +/* Capabilities reported at sys init */ +#define HFI_CAPS_PLACEHOLDER_1 (HFI_COMMON_BASE + 0x1) +#define HFI_CAPS_PLACEHOLDER_2 (HFI_COMMON_BASE + 0x2) + +/* Section describes different debug levels (HFI_DEBUG_MSG_X) + * available for debug messages from FW + */ +#define HFI_DEBUG_MSG_LOW 0x00000001 +#define HFI_DEBUG_MSG_MEDIUM 0x00000002 +#define HFI_DEBUG_MSG_HIGH 0x00000004 +#define HFI_DEBUG_MSG_ERROR 0x00000008 +#define HFI_DEBUG_MSG_FATAL 0x00000010 +/* Messages containing performance data */ +#define HFI_DEBUG_MSG_PERF 0x00000020 +/* Disable ARM9 WFI in low power mode. */ +#define HFI_DEBUG_CFG_WFI 0x01000000 +/* Disable ARM9 watchdog. */ +#define HFI_DEBUG_CFG_ARM9WD 0x10000000 + + +/* + * HFI_FW_DUMP levels + * HFI_FW_DUMP_xx + */ +#define HFI_FW_DUMP_DISABLED 0x00000000 +#define HFI_FW_DUMP_ON_FAILURE 0x00000001 +#define HFI_FW_DUMP_ALWAYS 0x00000002 + +/* Number of available dump levels. */ +#define NUM_HFI_DUMP_LVL 0x00000003 + +/* Debug Msg Communication types: + * Section describes different modes (HFI_DEBUG_MODE_X) + * available to communicate the debug messages + */ + /* Debug message output through the interface debug queue. */ +#define HFI_DEBUG_MODE_QUEUE 0x00000001 + /* Debug message output through QDSS. */ +#define HFI_DEBUG_MODE_QDSS 0x00000002 + /* Number of debug modes available. */ +#define NUM_HFI_DEBUG_MODE 0x00000002 + +#define HFI_DEBUG_MSG_LOW 0x00000001 +#define HFI_DEBUG_MSG_MEDIUM 0x00000002 +#define HFI_DEBUG_MSG_HIGH 0x00000004 +#define HFI_DEBUG_MSG_ERROR 0x00000008 +#define HFI_DEBUG_MSG_FATAL 0x00000010 +#define HFI_DEBUG_MSG_PERF 0x00000020 +#define HFI_DEBUG_CFG_WFI 0x01000000 +#define HFI_DEBUG_CFG_ARM9WD 0x10000000 + +#define HFI_DEV_VERSION_MAX 0x5 + +/** + * start of sys command packet types + * These commands are used to get system level information + * from firmware + */ + +/** + * struct hfi_caps_support + * payload to report caps through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED + * @type: capability type + * @min: minimum supported value for the capability + * @max: maximum supported value for the capability + * @step_size: supported steps between min-max + */ +struct hfi_caps_support { + uint32_t type; + uint32_t min; + uint32_t max; + uint32_t step_size; +} __packed; + +/** + * struct hfi_caps_support_info + * capability report through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED + * @num_caps: number of capabilities listed + * @caps_data: capabilities info array + */ +struct hfi_caps_support_info { + uint32_t num_caps; + struct hfi_caps_support caps_data[1]; +} __packed; + +/** + * struct hfi_debug + * payload structure to configure HFI_PROPERTY_SYS_DEBUG_CONFIG + * @debug_config: it is a result of HFI_DEBUG_MSG_X values that + * are OR-ed together to specify the debug message types + * to otput + * @debug_mode: debug message output through debug queue/qdss + * @HFI_PROPERTY_SYS_DEBUG_CONFIG + */ +struct hfi_debug { + uint32_t debug_config; + uint32_t debug_mode; +} __packed; + +/** + * struct hfi_ipe_bps_pc + * payload structure to configure HFI_PROPERTY_SYS_IPEBPS_PC + * @enable: Flag to enable IPE, BPS interfrane power collapse + * @core_info: Core information to firmware + */ +struct hfi_ipe_bps_pc { + uint32_t enable; + uint32_t core_info; +} __packed; + +/** + * struct hfi_cmd_ubwc_cfg + * Payload structure to configure HFI_PROP_SYS_UBWC_CFG + * @ubwc_fetch_cfg: UBWC configuration for fecth + * @ubwc_write_cfg: UBWC configuration for write + */ +struct hfi_cmd_ubwc_cfg { + uint32_t ubwc_fetch_cfg; + uint32_t ubwc_write_cfg; +} __packed; + +/** + * struct hfi_cmd_ubwc_cfg_ext + * Payload structure to configure HFI_UBWC_CFG_TYPE_EXT + * @bps: UBWC configuration for bps + * @ipe: UBWC configuration for ipe + */ +struct hfi_cmd_ubwc_cfg_ext { + struct hfi_cmd_ubwc_cfg bps; + struct hfi_cmd_ubwc_cfg ipe; +} __packed; + +/** + * struct hfi_cmd_sys_init + * command to initialization of system session + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @HFI_CMD_SYS_INIT + */ +struct hfi_cmd_sys_init { + uint32_t size; + uint32_t pkt_type; +} __packed; + +/** + * struct hfi_cmd_pc_prep + * command to firmware to prepare for power collapse + * @eize: packet size in bytes + * @pkt_type: opcode of a packet + * @HFI_CMD_SYS_PC_PREP + */ +struct hfi_cmd_pc_prep { + uint32_t size; + uint32_t pkt_type; +} __packed; + +/** + * struct hfi_cmd_prop + * command to get/set properties of firmware + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @num_prop: number of properties queried/set + * @prop_data: array of property IDs being queried. size depends on num_prop + * array of property IDs and associated structure pairs in set + * @HFI_CMD_SYS_GET_PROPERTY + * @HFI_CMD_SYS_SET_PROPERTY + */ +struct hfi_cmd_prop { + uint32_t size; + uint32_t pkt_type; + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_cmd_ping_pkt + * ping command pings the firmware to confirm whether + * it is alive. + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @user_data: client data, firmware returns this data + * as part of HFI_MSG_SYS_PING_ACK + * @HFI_CMD_SYS_PING + */ +struct hfi_cmd_ping_pkt { + uint32_t size; + uint32_t pkt_type; + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_sys_reset_pkt + * sends the reset command to FW. FW responds in the same type + * of packet. so can be used for reset_ack_pkt type also + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @user_data: client data, firmware returns this data + * as part of HFI_MSG_SYS_RESET_ACK + * @HFI_CMD_SYS_RESET + */ + +struct hfi_cmd_sys_reset_pkt { + uint32_t size; + uint32_t pkt_type; + uint64_t user_data; +} __packed; + +/* end of sys command packet types */ + +/* start of sys message packet types */ + +/** + * struct hfi_prop + * structure to report maximum supported features of firmware. + */ +struct hfi_sys_support { + uint32_t place_holder; +} __packed; + +/** + * struct hfi_supported_prop + * structure to report HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED + * for a session + * @num_prop: number of properties supported + * @prop_data: array of supported property IDs + */ +struct hfi_supported_prop { + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_image_version + * system image version + * @major: major version number + * @minor: minor version number + * @ver_name_size: size of version name + * @ver_name: image version name + */ +struct hfi_image_version { + uint32_t major; + uint32_t minor; + uint32_t ver_name_size; + uint8_t ver_name[1]; +} __packed; + +/** + * struct hfi_msg_init_done_data + * @api_ver: Firmware API version + * @dev_ver: Device version + * @num_icp_hw: Number of ICP hardware information + * @dev_hw_ver: Supported hardware version information + * @reserved: Reserved field + */ +struct hfi_msg_init_done_data { + uint32_t api_ver; + uint32_t dev_ver; + uint32_t num_icp_hw; + uint32_t dev_hw_ver[HFI_DEV_VERSION_MAX]; + uint32_t reserved; +}; + +/** + * struct hfi_msg_init_done + * system init done message from firmware. Many system level properties + * are returned with the packet + * @size: Packet size in bytes + * @pkt_type: Opcode of a packet + * @err_type: Error code associated with response + * @num_prop: Number of default capability info + * @prop_data: Array of property ids and corresponding structure pairs + */ +struct hfi_msg_init_done { + uint32_t size; + uint32_t pkt_type; + uint32_t err_type; + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_msg_pc_prep_done + * system power collapse preparation done message + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @err_type: error code associated with the response + */ +struct hfi_msg_pc_prep_done { + uint32_t size; + uint32_t pkt_type; + uint32_t err_type; +} __packed; + +/** + * struct hfi_msg_prop + * system property info from firmware + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @num_prop: number of property info structures + * @prop_data: array of property IDs and associated structure pairs + */ +struct hfi_msg_prop { + uint32_t size; + uint32_t pkt_type; + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_msg_idle + * system idle message from firmware + * @size: packet size in bytes + * @pkt_type: opcode of a packet + */ +struct hfi_msg_idle { + uint32_t size; + uint32_t pkt_type; +} __packed; + +/** + * struct hfi_msg_ping_ack + * system ping ack message + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @user_data: this data is sent as part of ping command from host + */ +struct hfi_msg_ping_ack { + uint32_t size; + uint32_t pkt_type; + uint64_t user_data; +} __packed; + +/** + * struct hfi_msg_debug + * system debug message defination + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @msg_type: debug message type + * @msg_size: size of debug message in bytes + * @timestamp_hi: most significant 32 bits of the 64 bit timestamp field. + * timestamp shall be interpreted as a signed 64-bit value + * representing microseconds. + * @timestamp_lo: least significant 32 bits of the 64 bit timestamp field. + * timestamp shall be interpreted as a signed 64-bit value + * representing microseconds. + * @msg_data: message data in string form + */ +struct hfi_msg_debug { + uint32_t size; + uint32_t pkt_type; + uint32_t msg_type; + uint32_t msg_size; + uint32_t timestamp_hi; + uint32_t timestamp_lo; + uint8_t msg_data[1]; +} __packed; +/** + * struct hfi_msg_event_notify + * event notify message + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @fw_handle: firmware session handle + * @event_id: session event id + * @event_data1: event data corresponding to event ID + * @event_data2: event data corresponding to event ID + * @ext_event_data: info array, interpreted based on event_data1 + * and event_data2 + */ +struct hfi_msg_event_notify { + uint32_t size; + uint32_t pkt_type; + uint32_t fw_handle; + uint32_t event_id; + uint32_t event_data1; + uint32_t event_data2; + uint32_t ext_event_data[1]; +} __packed; +/** + * end of sys message packet types + */ + +#endif /* _HFI_DEFS_H_ */ diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c new file mode 100644 index 000000000000..06ad9de00eac --- /dev/null +++ b/drivers/cam_icp/hfi.c @@ -0,0 +1,942 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "hfi_reg.h" +#include "hfi_sys_defs.h" +#include "hfi_session_defs.h" +#include "hfi_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_debug_util.h" +#include "cam_soc_util.h" + +#define HFI_VERSION_INFO_MAJOR_VAL 1 +#define HFI_VERSION_INFO_MINOR_VAL 1 +#define HFI_VERSION_INFO_STEP_VAL 0 +#define HFI_VERSION_INFO_STEP_VAL 0 +#define HFI_VERSION_INFO_MAJOR_BMSK 0xFF000000 +#define HFI_VERSION_INFO_MAJOR_SHFT 24 +#define HFI_VERSION_INFO_MINOR_BMSK 0xFFFF00 +#define HFI_VERSION_INFO_MINOR_SHFT 8 +#define HFI_VERSION_INFO_STEP_BMSK 0xFF +#define HFI_VERSION_INFO_STEP_SHFT 0 + +#define HFI_MAX_POLL_TRY 5 + +#define HFI_MAX_PC_POLL_TRY 150 +#define HFI_POLL_TRY_SLEEP 1 + +static struct hfi_info *g_hfi; +unsigned int g_icp_mmu_hdl; +static DEFINE_MUTEX(hfi_cmd_q_mutex); +static DEFINE_MUTEX(hfi_msg_q_mutex); + +void cam_hfi_queue_dump(void) +{ + struct hfi_qtbl *qtbl; + struct hfi_qtbl_hdr *qtbl_hdr; + struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr; + struct hfi_mem_info *hfi_mem = NULL; + uint32_t *read_q, *read_ptr; + int i; + + hfi_mem = &g_hfi->map; + if (!hfi_mem) { + CAM_ERR(CAM_HFI, "Unable to dump queues hfi memory is NULL"); + return; + } + + qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; + qtbl_hdr = &qtbl->q_tbl_hdr; + CAM_DBG(CAM_HFI, + "qtbl: version = %x size = %u num q = %u qhdr_size = %u", + qtbl_hdr->qtbl_version, qtbl_hdr->qtbl_size, + qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size); + + cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; + CAM_DBG(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", + cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx, + cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova); + read_q = (uint32_t *)g_hfi->map.cmd_q.kva; + read_ptr = (uint32_t *)(read_q + 0); + CAM_DBG(CAM_HFI, "CMD Q START"); + for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + + msg_q_hdr = &qtbl->q_hdr[Q_MSG]; + CAM_DBG(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", + msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx, + msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova); + read_q = (uint32_t *)g_hfi->map.msg_q.kva; + read_ptr = (uint32_t *)(read_q + 0); + CAM_DBG(CAM_HFI, "MSG Q START"); + for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); +} + +int hfi_write_cmd(void *cmd_ptr) +{ + uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp; + uint32_t *write_q, *write_ptr; + struct hfi_qtbl *q_tbl; + struct hfi_q_hdr *q; + int rc = 0; + + if (!cmd_ptr) { + CAM_ERR(CAM_HFI, "command is null"); + return -EINVAL; + } + + mutex_lock(&hfi_cmd_q_mutex); + if (!g_hfi) { + CAM_ERR(CAM_HFI, "HFI interface not setup"); + rc = -ENODEV; + goto err; + } + + if (g_hfi->hfi_state != HFI_READY || + !g_hfi->cmd_q_state) { + CAM_ERR(CAM_HFI, "HFI state: %u, cmd q state: %u", + g_hfi->hfi_state, g_hfi->cmd_q_state); + rc = -ENODEV; + goto err; + } + + q_tbl = (struct hfi_qtbl *)g_hfi->map.qtbl.kva; + q = &q_tbl->q_hdr[Q_CMD]; + + write_q = (uint32_t *)g_hfi->map.cmd_q.kva; + + size_in_words = (*(uint32_t *)cmd_ptr) >> BYTE_WORD_SHIFT; + if (!size_in_words) { + CAM_DBG(CAM_HFI, "failed"); + rc = -EINVAL; + goto err; + } + + read_idx = q->qhdr_read_idx; + empty_space = (q->qhdr_write_idx >= read_idx) ? + (q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) : + (read_idx - q->qhdr_write_idx); + if (empty_space <= size_in_words) { + CAM_ERR(CAM_HFI, "failed: empty space %u, size_in_words %u", + empty_space, size_in_words); + rc = -EIO; + goto err; + } + + new_write_idx = q->qhdr_write_idx + size_in_words; + write_ptr = (uint32_t *)(write_q + q->qhdr_write_idx); + + if (new_write_idx < q->qhdr_q_size) { + memcpy(write_ptr, (uint8_t *)cmd_ptr, + size_in_words << BYTE_WORD_SHIFT); + } else { + new_write_idx -= q->qhdr_q_size; + temp = (size_in_words - new_write_idx) << BYTE_WORD_SHIFT; + memcpy(write_ptr, (uint8_t *)cmd_ptr, temp); + memcpy(write_q, (uint8_t *)cmd_ptr + temp, + new_write_idx << BYTE_WORD_SHIFT); + } + + /* + * To make sure command data in a command queue before + * updating write index + */ + wmb(); + + q->qhdr_write_idx = new_write_idx; + + /* + * Before raising interrupt make sure command data is ready for + * firmware to process + */ + wmb(); + cam_io_w_mb((uint32_t)INTR_ENABLE, + g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT); +err: + mutex_unlock(&hfi_cmd_q_mutex); + return rc; +} + +int hfi_read_message(uint32_t *pmsg, uint8_t q_id, + uint32_t *words_read) +{ + struct hfi_qtbl *q_tbl_ptr; + struct hfi_q_hdr *q; + uint32_t new_read_idx, size_in_words, word_diff, temp; + uint32_t *read_q, *read_ptr, *write_ptr; + uint32_t size_upper_bound = 0; + int rc = 0; + + if (!pmsg) { + CAM_ERR(CAM_HFI, "Invalid msg"); + return -EINVAL; + } + + if (q_id > Q_DBG) { + CAM_ERR(CAM_HFI, "Invalid q :%u", q_id); + return -EINVAL; + } + + mutex_lock(&hfi_msg_q_mutex); + if (!g_hfi) { + CAM_ERR(CAM_HFI, "hfi not set up yet"); + rc = -ENODEV; + goto err; + } + + if ((g_hfi->hfi_state != HFI_READY) || + !g_hfi->msg_q_state) { + CAM_ERR(CAM_HFI, "hfi state: %u, msg q state: %u", + g_hfi->hfi_state, g_hfi->msg_q_state); + rc = -ENODEV; + goto err; + } + + q_tbl_ptr = (struct hfi_qtbl *)g_hfi->map.qtbl.kva; + q = &q_tbl_ptr->q_hdr[q_id]; + + if (q->qhdr_read_idx == q->qhdr_write_idx) { + CAM_DBG(CAM_HFI, "Q not ready, state:%u, r idx:%u, w idx:%u", + g_hfi->hfi_state, q->qhdr_read_idx, q->qhdr_write_idx); + rc = -EIO; + goto err; + } + + if (q_id == Q_MSG) { + read_q = (uint32_t *)g_hfi->map.msg_q.kva; + size_upper_bound = ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS; + } else { + read_q = (uint32_t *)g_hfi->map.dbg_q.kva; + size_upper_bound = ICP_HFI_MAX_PKT_SIZE_IN_WORDS; + } + + read_ptr = (uint32_t *)(read_q + q->qhdr_read_idx); + write_ptr = (uint32_t *)(read_q + q->qhdr_write_idx); + + if (write_ptr > read_ptr) + size_in_words = write_ptr - read_ptr; + else { + word_diff = read_ptr - write_ptr; + if (q_id == Q_MSG) + size_in_words = (ICP_MSG_Q_SIZE_IN_BYTES >> + BYTE_WORD_SHIFT) - word_diff; + else + size_in_words = (ICP_DBG_Q_SIZE_IN_BYTES >> + BYTE_WORD_SHIFT) - word_diff; + } + + if ((size_in_words == 0) || + (size_in_words > size_upper_bound)) { + CAM_ERR(CAM_HFI, "invalid HFI message packet size - 0x%08x", + size_in_words << BYTE_WORD_SHIFT); + q->qhdr_read_idx = q->qhdr_write_idx; + rc = -EIO; + goto err; + } + + new_read_idx = q->qhdr_read_idx + size_in_words; + + if (new_read_idx < q->qhdr_q_size) { + memcpy(pmsg, read_ptr, size_in_words << BYTE_WORD_SHIFT); + } else { + new_read_idx -= q->qhdr_q_size; + temp = (size_in_words - new_read_idx) << BYTE_WORD_SHIFT; + memcpy(pmsg, read_ptr, temp); + memcpy((uint8_t *)pmsg + temp, read_q, + new_read_idx << BYTE_WORD_SHIFT); + } + + q->qhdr_read_idx = new_read_idx; + *words_read = size_in_words; + /* Memory Barrier to make sure message + * queue parameters are updated after read + */ + wmb(); +err: + mutex_unlock(&hfi_msg_q_mutex); + return rc; +} + +int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_cmd_ubwc_cfg); + + CAM_DBG(CAM_HFI, + "size of ubwc %u, ubwc_cfg [rd-0x%x,wr-0x%x]", + size, ubwc_cfg[0], ubwc_cfg[1]); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROP_SYS_UBWC_CFG; + dbg_prop->prop_data[1] = ubwc_cfg[0]; + dbg_prop->prop_data[2] = ubwc_cfg[1]; + + hfi_write_cmd(prop); + kfree(prop); + + return 0; +} + +int hfi_cmd_ubwc_config_ext(uint32_t *ubwc_ipe_cfg, + uint32_t *ubwc_bps_cfg) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_cmd_ubwc_cfg_ext); + + CAM_DBG(CAM_HFI, + "size of ubwc %u, ubwc_ipe_cfg[rd-0x%x,wr-0x%x] ubwc_bps_cfg[rd-0x%x,wr-0x%x]", + size, ubwc_ipe_cfg[0], ubwc_ipe_cfg[1], + ubwc_bps_cfg[0], ubwc_bps_cfg[1]); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG_EX; + dbg_prop->prop_data[1] = ubwc_bps_cfg[0]; + dbg_prop->prop_data[2] = ubwc_bps_cfg[1]; + dbg_prop->prop_data[3] = ubwc_ipe_cfg[0]; + dbg_prop->prop_data[4] = ubwc_ipe_cfg[1]; + + hfi_write_cmd(prop); + kfree(prop); + + return 0; +} + + +int hfi_enable_ipe_bps_pc(bool enable, uint32_t core_info) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_ipe_bps_pc); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROP_SYS_IPEBPS_PC; + dbg_prop->prop_data[1] = enable; + dbg_prop->prop_data[2] = core_info; + + hfi_write_cmd(prop); + kfree(prop); + + return 0; +} + +int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0, val; + + val = HFI_DEBUG_MSG_LOW | + HFI_DEBUG_MSG_MEDIUM | + HFI_DEBUG_MSG_HIGH | + HFI_DEBUG_MSG_ERROR | + HFI_DEBUG_MSG_FATAL | + HFI_DEBUG_MSG_PERF | + HFI_DEBUG_CFG_WFI | + HFI_DEBUG_CFG_ARM9WD; + + if (lvl > val) + return -EINVAL; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_debug); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROP_SYS_DEBUG_CFG; + dbg_prop->prop_data[1] = lvl; + dbg_prop->prop_data[2] = a5_dbg_type; + hfi_write_cmd(prop); + + kfree(prop); + + return 0; +} + +int hfi_set_fw_dump_level(uint32_t lvl) +{ + uint8_t *prop = NULL; + struct hfi_cmd_prop *fw_dump_level_switch_prop = NULL; + uint32_t size = 0; + + CAM_DBG(CAM_HFI, "fw dump ENTER"); + + size = sizeof(struct hfi_cmd_prop) + sizeof(lvl); + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + fw_dump_level_switch_prop = (struct hfi_cmd_prop *)prop; + fw_dump_level_switch_prop->size = size; + fw_dump_level_switch_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + fw_dump_level_switch_prop->num_prop = 1; + fw_dump_level_switch_prop->prop_data[0] = HFI_PROP_SYS_FW_DUMP_CFG; + fw_dump_level_switch_prop->prop_data[1] = lvl; + + CAM_DBG(CAM_HFI, "prop->size = %d\n" + "prop->pkt_type = %d\n" + "prop->num_prop = %d\n" + "prop->prop_data[0] = %d\n" + "prop->prop_data[1] = %d\n", + fw_dump_level_switch_prop->size, + fw_dump_level_switch_prop->pkt_type, + fw_dump_level_switch_prop->num_prop, + fw_dump_level_switch_prop->prop_data[0], + fw_dump_level_switch_prop->prop_data[1]); + + hfi_write_cmd(prop); + kfree(prop); + return 0; +} + +void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size) +{ + switch (type) { + case HFI_CMD_SYS_INIT: { + struct hfi_cmd_sys_init init; + + memset(&init, 0, sizeof(init)); + + init.size = sizeof(struct hfi_cmd_sys_init); + init.pkt_type = type; + hfi_write_cmd(&init); + } + break; + case HFI_CMD_SYS_PC_PREP: { + struct hfi_cmd_pc_prep prep; + + prep.size = sizeof(struct hfi_cmd_pc_prep); + prep.pkt_type = type; + hfi_write_cmd(&prep); + } + break; + case HFI_CMD_SYS_SET_PROPERTY: { + struct hfi_cmd_prop prop; + + if ((uint32_t)data == (uint32_t)HFI_PROP_SYS_DEBUG_CFG) { + prop.size = sizeof(struct hfi_cmd_prop); + prop.pkt_type = type; + prop.num_prop = 1; + prop.prop_data[0] = HFI_PROP_SYS_DEBUG_CFG; + hfi_write_cmd(&prop); + } + } + break; + case HFI_CMD_SYS_GET_PROPERTY: + break; + case HFI_CMD_SYS_PING: { + struct hfi_cmd_ping_pkt ping; + + ping.size = sizeof(struct hfi_cmd_ping_pkt); + ping.pkt_type = type; + ping.user_data = (uint64_t)data; + hfi_write_cmd(&ping); + } + break; + case HFI_CMD_SYS_RESET: { + struct hfi_cmd_sys_reset_pkt reset; + + reset.size = sizeof(struct hfi_cmd_sys_reset_pkt); + reset.pkt_type = type; + reset.user_data = (uint64_t)data; + hfi_write_cmd(&reset); + } + break; + case HFI_CMD_IPEBPS_CREATE_HANDLE: { + struct hfi_cmd_create_handle handle; + + handle.size = sizeof(struct hfi_cmd_create_handle); + handle.pkt_type = type; + handle.handle_type = (uint32_t)data; + handle.user_data1 = 0; + hfi_write_cmd(&handle); + } + break; + case HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT: + break; + default: + CAM_ERR(CAM_HFI, "command not supported :%d", type); + break; + } +} + + +int hfi_get_hw_caps(void *query_buf) +{ + int i = 0; + struct cam_icp_query_cap_cmd *query_cmd = NULL; + + if (!query_buf) { + CAM_ERR(CAM_HFI, "query buf is NULL"); + return -EINVAL; + } + + query_cmd = (struct cam_icp_query_cap_cmd *)query_buf; + query_cmd->fw_version.major = 0x12; + query_cmd->fw_version.minor = 0x12; + query_cmd->fw_version.revision = 0x12; + + query_cmd->api_version.major = 0x13; + query_cmd->api_version.minor = 0x13; + query_cmd->api_version.revision = 0x13; + + query_cmd->num_ipe = 2; + query_cmd->num_bps = 1; + + for (i = 0; i < CAM_ICP_DEV_TYPE_MAX; i++) { + query_cmd->dev_ver[i].dev_type = i; + query_cmd->dev_ver[i].hw_ver.major = 0x34 + i; + query_cmd->dev_ver[i].hw_ver.minor = 0x34 + i; + query_cmd->dev_ver[i].hw_ver.incr = 0x34 + i; + } + return 0; +} + +void cam_hfi_disable_cpu(void __iomem *icp_base) +{ + uint32_t data; + uint32_t val; + uint32_t try = 0; + + while (try < HFI_MAX_PC_POLL_TRY) { + data = cam_io_r_mb(icp_base + HFI_REG_A5_CSR_A5_STATUS); + CAM_DBG(CAM_HFI, "wfi status = %x\n", (int)data); + + if (data & ICP_CSR_A5_STATUS_WFI) + break; + /* Need to poll here to confirm that FW is going trigger wfi + * and Host can the proceed. No interrupt is expected from FW + * at this time. + */ + usleep_range(HFI_POLL_TRY_SLEEP * 1000, + (HFI_POLL_TRY_SLEEP * 1000) + 1000); + try++; + } + + val = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_CONTROL); + val &= ~(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN); + cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL); + + val = cam_io_r(icp_base + HFI_REG_A5_CSR_NSEC_RESET); + cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_NSEC_RESET); + + cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_RESET, + icp_base + HFI_REG_HOST_ICP_INIT_REQUEST); + cam_io_w_mb((uint32_t)INTR_DISABLE, + icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); +} + +void cam_hfi_enable_cpu(void __iomem *icp_base) +{ + cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + cam_io_w_mb((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET); +} + +int cam_hfi_resume(struct hfi_mem_info *hfi_mem, + void __iomem *icp_base, bool debug) +{ + int rc = 0; + uint32_t data; + uint32_t fw_version, status = 0; + uint32_t retry_cnt = 0; + + cam_hfi_enable_cpu(icp_base); + g_hfi->csr_base = icp_base; + + if (debug) { + cam_io_w_mb(ICP_FLAG_A5_CTRL_DBG_EN, + (icp_base + HFI_REG_A5_CSR_A5_CONTROL)); + + /* Barrier needed as next write should be done after + * sucessful previous write. Next write enable clock + * gating + */ + wmb(); + + cam_io_w_mb((uint32_t)ICP_FLAG_A5_CTRL_EN, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + + } else { + cam_io_w_mb((uint32_t)ICP_FLAG_A5_CTRL_EN, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + } + + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE), + status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000); + + CAM_DBG(CAM_HFI, "1: status = %u", status); + status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE); + CAM_DBG(CAM_HFI, "2: status = %u", status); + if (status == ICP_INIT_RESP_SUCCESS) + break; + + if (status == ICP_INIT_RESP_FAILED) { + CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version); + return -EINVAL; + } + retry_cnt++; + } + + if ((retry_cnt == HFI_MAX_POLL_TRY) && + (status == ICP_INIT_RESP_RESET)) { + CAM_ERR(CAM_HFI, "Reached Max retries. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version); + return -EINVAL; + } + + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), + icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); + + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_DBG(CAM_HFI, "fw version : [%x]", fw_version); + + data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS); + CAM_DBG(CAM_HFI, "wfi status = %x", (int)data); + + cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, + icp_base + HFI_REG_SHARED_MEM_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.len, + icp_base + HFI_REG_SHARED_MEM_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova, + icp_base + HFI_REG_UNCACHED_HEAP_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len, + icp_base + HFI_REG_UNCACHED_HEAP_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->qdss.iova, + icp_base + HFI_REG_QDSS_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->qdss.len, + icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); + + return rc; +} + +int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, + void __iomem *icp_base, bool debug) +{ + int rc = 0; + struct hfi_qtbl *qtbl; + struct hfi_qtbl_hdr *qtbl_hdr; + struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr; + uint32_t hw_version, soc_version, fw_version, status = 0; + uint32_t retry_cnt = 0; + struct sfr_buf *sfr_buffer; + + mutex_lock(&hfi_cmd_q_mutex); + mutex_lock(&hfi_msg_q_mutex); + + if (!g_hfi) { + g_hfi = kzalloc(sizeof(struct hfi_info), GFP_KERNEL); + if (!g_hfi) { + rc = -ENOMEM; + goto alloc_fail; + } + } + + if (g_hfi->hfi_state != HFI_DEINIT) { + CAM_ERR(CAM_HFI, "hfi_init: invalid state"); + return -EINVAL; + } + + memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map)); + g_hfi->hfi_state = HFI_DEINIT; + soc_version = socinfo_get_version(); + if (debug) { + cam_io_w_mb( + (uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN | + ICP_CSR_EDBGRQ | ICP_CSR_DBGSWENABLE), + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + msleep(100); + cam_io_w_mb((uint32_t)(ICP_FLAG_CSR_A5_EN | + ICP_FLAG_CSR_WAKE_UP_EN | ICP_CSR_EN_CLKGATE_WFI), + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + } else { + /* Due to hardware bug in V1 ICP clock gating has to be + * disabled, this is supposed to be fixed in V-2. But enabling + * the clock gating is causing the firmware hang, hence + * disabling the clock gating on both V1 and V2 until the + * hardware team root causes this + */ + cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN | + ICP_FLAG_CSR_WAKE_UP_EN | + ICP_CSR_EN_CLKGATE_WFI, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + } + + qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; + qtbl_hdr = &qtbl->q_tbl_hdr; + qtbl_hdr->qtbl_version = 0xFFFFFFFF; + qtbl_hdr->qtbl_size = sizeof(struct hfi_qtbl); + qtbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_qtbl_hdr); + qtbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_q_hdr); + qtbl_hdr->qtbl_num_q = ICP_HFI_NUMBER_OF_QS; + qtbl_hdr->qtbl_num_active_q = ICP_HFI_NUMBER_OF_QS; + + /* setup host-to-firmware command queue */ + cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; + cmd_q_hdr->qhdr_status = QHDR_ACTIVE; + cmd_q_hdr->qhdr_start_addr = hfi_mem->cmd_q.iova; + cmd_q_hdr->qhdr_q_size = ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; + cmd_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT; + cmd_q_hdr->qhdr_pkt_drop_cnt = RESET; + cmd_q_hdr->qhdr_read_idx = RESET; + cmd_q_hdr->qhdr_write_idx = RESET; + + /* setup firmware-to-Host message queue */ + msg_q_hdr = &qtbl->q_hdr[Q_MSG]; + msg_q_hdr->qhdr_status = QHDR_ACTIVE; + msg_q_hdr->qhdr_start_addr = hfi_mem->msg_q.iova; + msg_q_hdr->qhdr_q_size = ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; + msg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT; + msg_q_hdr->qhdr_pkt_drop_cnt = RESET; + msg_q_hdr->qhdr_read_idx = RESET; + msg_q_hdr->qhdr_write_idx = RESET; + + /* setup firmware-to-Host message queue */ + dbg_q_hdr = &qtbl->q_hdr[Q_DBG]; + dbg_q_hdr->qhdr_status = QHDR_ACTIVE; + dbg_q_hdr->qhdr_start_addr = hfi_mem->dbg_q.iova; + dbg_q_hdr->qhdr_q_size = ICP_DBG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; + dbg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT; + dbg_q_hdr->qhdr_pkt_drop_cnt = RESET; + dbg_q_hdr->qhdr_read_idx = RESET; + dbg_q_hdr->qhdr_write_idx = RESET; + + sfr_buffer = (struct sfr_buf *)hfi_mem->sfr_buf.kva; + sfr_buffer->size = ICP_MSG_SFR_SIZE_IN_BYTES; + + switch (event_driven_mode) { + case INTR_MODE: + cmd_q_hdr->qhdr_type = Q_CMD; + cmd_q_hdr->qhdr_rx_wm = SET; + cmd_q_hdr->qhdr_tx_wm = SET; + cmd_q_hdr->qhdr_rx_req = SET; + cmd_q_hdr->qhdr_tx_req = RESET; + cmd_q_hdr->qhdr_rx_irq_status = RESET; + cmd_q_hdr->qhdr_tx_irq_status = RESET; + + msg_q_hdr->qhdr_type = Q_MSG; + msg_q_hdr->qhdr_rx_wm = SET; + msg_q_hdr->qhdr_tx_wm = SET; + msg_q_hdr->qhdr_rx_req = SET; + msg_q_hdr->qhdr_tx_req = RESET; + msg_q_hdr->qhdr_rx_irq_status = RESET; + msg_q_hdr->qhdr_tx_irq_status = RESET; + + dbg_q_hdr->qhdr_type = Q_DBG; + dbg_q_hdr->qhdr_rx_wm = SET; + dbg_q_hdr->qhdr_tx_wm = SET_WM; + dbg_q_hdr->qhdr_rx_req = RESET; + dbg_q_hdr->qhdr_tx_req = RESET; + dbg_q_hdr->qhdr_rx_irq_status = RESET; + dbg_q_hdr->qhdr_tx_irq_status = RESET; + + break; + + case POLL_MODE: + cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_POLL_MODE_2 | + RX_EVENT_POLL_MODE_2; + msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_POLL_MODE_2 | + RX_EVENT_POLL_MODE_2; + dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_POLL_MODE_2 | + RX_EVENT_POLL_MODE_2; + break; + + case WM_MODE: + cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_DRIVEN_MODE_2 | + RX_EVENT_DRIVEN_MODE_2; + cmd_q_hdr->qhdr_rx_wm = SET; + cmd_q_hdr->qhdr_tx_wm = SET; + cmd_q_hdr->qhdr_rx_req = RESET; + cmd_q_hdr->qhdr_tx_req = SET; + cmd_q_hdr->qhdr_rx_irq_status = RESET; + cmd_q_hdr->qhdr_tx_irq_status = RESET; + + msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_DRIVEN_MODE_2 | + RX_EVENT_DRIVEN_MODE_2; + msg_q_hdr->qhdr_rx_wm = SET; + msg_q_hdr->qhdr_tx_wm = SET; + msg_q_hdr->qhdr_rx_req = SET; + msg_q_hdr->qhdr_tx_req = RESET; + msg_q_hdr->qhdr_rx_irq_status = RESET; + msg_q_hdr->qhdr_tx_irq_status = RESET; + + dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_DRIVEN_MODE_2 | + RX_EVENT_DRIVEN_MODE_2; + dbg_q_hdr->qhdr_rx_wm = SET; + dbg_q_hdr->qhdr_tx_wm = SET_WM; + dbg_q_hdr->qhdr_rx_req = RESET; + dbg_q_hdr->qhdr_tx_req = RESET; + dbg_q_hdr->qhdr_rx_irq_status = RESET; + dbg_q_hdr->qhdr_tx_irq_status = RESET; + break; + + default: + CAM_ERR(CAM_HFI, "Invalid event driven mode :%u", + event_driven_mode); + break; + } + + cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, + icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, + icp_base + HFI_REG_SHARED_MEM_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.len, + icp_base + HFI_REG_SHARED_MEM_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova, + icp_base + HFI_REG_UNCACHED_HEAP_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len, + icp_base + HFI_REG_UNCACHED_HEAP_SIZE); + cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_SET, + icp_base + HFI_REG_HOST_ICP_INIT_REQUEST); + cam_io_w_mb((uint32_t)hfi_mem->qdss.iova, + icp_base + HFI_REG_QDSS_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->qdss.len, + icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); + + hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION); + + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE), + status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000); + + CAM_DBG(CAM_HFI, "1: status = %u rc = %d", status, rc); + status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE); + CAM_DBG(CAM_HFI, "2: status = %u rc = %d", status, rc); + if (status == ICP_INIT_RESP_SUCCESS) + break; + + if (status == ICP_INIT_RESP_FAILED) { + CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version); + goto regions_fail; + } + retry_cnt++; + } + + if ((retry_cnt == HFI_MAX_POLL_TRY) && + (status == ICP_INIT_RESP_RESET)) { + CAM_ERR(CAM_HFI, "Reached Max retries. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, + "hw version : : [%x], fw version : [%x]", + hw_version, fw_version); + goto regions_fail; + } + + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_DBG(CAM_HFI, "hw version : : [%x], fw version : [%x]", + hw_version, fw_version); + + g_hfi->csr_base = icp_base; + g_hfi->hfi_state = HFI_READY; + g_hfi->cmd_q_state = true; + g_hfi->msg_q_state = true; + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), + icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); + + mutex_unlock(&hfi_cmd_q_mutex); + mutex_unlock(&hfi_msg_q_mutex); + + return rc; +regions_fail: + kfree(g_hfi); + g_hfi = NULL; +alloc_fail: + mutex_unlock(&hfi_cmd_q_mutex); + mutex_unlock(&hfi_msg_q_mutex); + return rc; +} + +void cam_hfi_deinit(void __iomem *icp_base) +{ + mutex_lock(&hfi_cmd_q_mutex); + mutex_lock(&hfi_msg_q_mutex); + + if (!g_hfi) { + CAM_ERR(CAM_HFI, "hfi path not established yet"); + goto err; + } + + g_hfi->cmd_q_state = false; + g_hfi->msg_q_state = false; + + kzfree(g_hfi); + g_hfi = NULL; + +err: + mutex_unlock(&hfi_cmd_q_mutex); + mutex_unlock(&hfi_msg_q_mutex); +} diff --git a/drivers/cam_icp/icp_hw/Makefile b/drivers/cam_icp/icp_hw/Makefile new file mode 100644 index 000000000000..e07836a01f12 --- /dev/null +++ b/drivers/cam_icp/icp_hw/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw_mgr/ a5_hw/ ipe_hw/ bps_hw/ diff --git a/drivers/cam_icp/icp_hw/a5_hw/Makefile b/drivers/cam_icp/icp_hw/a5_hw/Makefile new file mode 100644 index 000000000000..db80567488a0 --- /dev/null +++ b/drivers/cam_icp/icp_hw/a5_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/a5_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += a5_dev.o a5_core.o a5_soc.o diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c new file mode 100644 index 000000000000..baac5ff5976c --- /dev/null +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -0,0 +1,518 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_a5_hw_intf.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "a5_core.h" +#include "a5_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "hfi_intf.h" +#include "hfi_sys_defs.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static int cam_a5_cpas_vote(struct cam_a5_device_core_info *core_info, + struct cam_icp_cpas_vote *cpas_vote) +{ + int rc = 0; + + if (cpas_vote->ahb_vote_valid) + rc = cam_cpas_update_ahb_vote(core_info->cpas_handle, + &cpas_vote->ahb_vote); + + if (cpas_vote->axi_vote_valid) + rc = cam_cpas_update_axi_vote(core_info->cpas_handle, + &cpas_vote->axi_vote); + + if (rc) + CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + + return rc; +} + +static int32_t cam_icp_validate_fw(const uint8_t *elf) +{ + struct elf32_hdr *elf_hdr; + + if (!elf) { + CAM_ERR(CAM_ICP, "Invalid params"); + return -EINVAL; + } + + elf_hdr = (struct elf32_hdr *)elf; + + if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG)) { + CAM_ERR(CAM_ICP, "ICP elf identifier is failed"); + return -EINVAL; + } + + /* check architecture */ + if (elf_hdr->e_machine != EM_ARM) { + CAM_ERR(CAM_ICP, "unsupported arch"); + return -EINVAL; + } + + /* check elf bit format */ + if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) { + CAM_ERR(CAM_ICP, "elf doesn't support 32 bit format"); + return -EINVAL; + } + + return 0; +} + +static int32_t cam_icp_get_fw_size(const uint8_t *elf, uint32_t *fw_size) +{ + int32_t rc = 0; + int32_t i = 0; + uint32_t num_prg_hdrs; + unsigned char *icp_prg_hdr_tbl; + uint32_t seg_mem_size = 0; + struct elf32_hdr *elf_hdr; + struct elf32_phdr *prg_hdr; + + if (!elf || !fw_size) { + CAM_ERR(CAM_ICP, "invalid args"); + return -EINVAL; + } + + *fw_size = 0; + + elf_hdr = (struct elf32_hdr *)elf; + num_prg_hdrs = elf_hdr->e_phnum; + icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff; + prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0]; + + if (!prg_hdr) { + CAM_ERR(CAM_ICP, "failed to get elf program header attr"); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "num_prg_hdrs = %d", num_prg_hdrs); + for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) { + if (prg_hdr->p_flags == 0) + continue; + + seg_mem_size = (prg_hdr->p_memsz + prg_hdr->p_align - 1) & + ~(prg_hdr->p_align - 1); + seg_mem_size += prg_hdr->p_vaddr; + CAM_DBG(CAM_ICP, "memsz:%x align:%x addr:%x seg_mem_size:%x", + (int)prg_hdr->p_memsz, (int)prg_hdr->p_align, + (int)prg_hdr->p_vaddr, (int)seg_mem_size); + if (*fw_size < seg_mem_size) + *fw_size = seg_mem_size; + + } + + if (*fw_size == 0) { + CAM_ERR(CAM_ICP, "invalid elf fw file"); + return -EINVAL; + } + + return rc; +} + +static int32_t cam_icp_program_fw(const uint8_t *elf, + struct cam_a5_device_core_info *core_info) +{ + int32_t rc = 0; + uint32_t num_prg_hdrs; + unsigned char *icp_prg_hdr_tbl; + int32_t i = 0; + u8 *dest; + u8 *src; + struct elf32_hdr *elf_hdr; + struct elf32_phdr *prg_hdr; + + elf_hdr = (struct elf32_hdr *)elf; + num_prg_hdrs = elf_hdr->e_phnum; + icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff; + prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0]; + + if (!prg_hdr) { + CAM_ERR(CAM_ICP, "failed to get elf program header attr"); + return -EINVAL; + } + + for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) { + if (prg_hdr->p_flags == 0) + continue; + + CAM_DBG(CAM_ICP, "Loading FW header size: %u", + prg_hdr->p_filesz); + if (prg_hdr->p_filesz != 0) { + src = (u8 *)((u8 *)elf + prg_hdr->p_offset); + dest = (u8 *)(((u8 *)core_info->fw_kva_addr) + + prg_hdr->p_vaddr); + + memcpy_toio(dest, src, prg_hdr->p_filesz); + } + } + + return rc; +} + +static int32_t cam_a5_download_fw(void *device_priv) +{ + int32_t rc = 0; + uint32_t fw_size; + const uint8_t *fw_start = NULL; + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + struct platform_device *pdev = NULL; + struct a5_soc_info *cam_a5_soc_info = NULL; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + hw_info = core_info->a5_hw_info; + pdev = soc_info->pdev; + cam_a5_soc_info = soc_info->soc_private; + + rc = request_firmware(&core_info->fw_elf, "CAMERA_ICP.elf", &pdev->dev); + if (rc) { + CAM_ERR(CAM_ICP, "Failed to locate fw: %d", rc); + return rc; + } + + if (!core_info->fw_elf) { + CAM_ERR(CAM_ICP, "Invalid elf size"); + rc = -EINVAL; + goto fw_download_failed; + } + + fw_start = core_info->fw_elf->data; + rc = cam_icp_validate_fw(fw_start); + if (rc) { + CAM_ERR(CAM_ICP, "fw elf validation failed"); + goto fw_download_failed; + } + + rc = cam_icp_get_fw_size(fw_start, &fw_size); + if (rc) { + CAM_ERR(CAM_ICP, "unable to get fw size"); + goto fw_download_failed; + } + + if (core_info->fw_buf_len < fw_size) { + CAM_ERR(CAM_ICP, "mismatch in fw size: %u %llu", + fw_size, core_info->fw_buf_len); + rc = -EINVAL; + goto fw_download_failed; + } + + rc = cam_icp_program_fw(fw_start, core_info); + if (rc) { + CAM_ERR(CAM_ICP, "fw program is failed"); + goto fw_download_failed; + } + +fw_download_failed: + release_firmware(core_info->fw_elf); + return rc; +} + +int cam_a5_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_icp_cpas_vote cpas_vote; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info: %pK core_info: %pK", + soc_info, core_info); + return -EINVAL; + } + + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote.axi_vote.num_paths = 1; + cpas_vote.axi_vote.axi_path[0].path_data_type = + CAM_ICP_DEFAULT_AXI_PATH; + cpas_vote.axi_vote.axi_path[0].transac_type = + CAM_ICP_DEFAULT_AXI_TRANSAC; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].ddr_ab_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].ddr_ib_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_ICP, "cpas start failed: %d", rc); + goto error; + } + core_info->cpas_start = true; + + rc = cam_a5_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ICP, "soc enable is failed: %d", rc); + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + +error: + return rc; +} + +int cam_a5_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + rc = cam_a5_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ICP, "soc disable is failed: %d", rc); + + if (core_info->cpas_start) { + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + + return rc; +} + +irqreturn_t cam_a5_irq(int irq_num, void *data) +{ + struct cam_hw_info *a5_dev = data; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + uint32_t irq_status = 0; + + if (!data) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info or query_cap args"); + return IRQ_HANDLED; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + hw_info = core_info->a5_hw_info; + + irq_status = cam_io_r_mb(soc_info->reg_map[A5_SIERRA_BASE].mem_base + + core_info->a5_hw_info->a5_host_int_status); + + cam_io_w_mb(irq_status, + soc_info->reg_map[A5_SIERRA_BASE].mem_base + + core_info->a5_hw_info->a5_host_int_clr); + + if ((irq_status & A5_WDT_0) || + (irq_status & A5_WDT_1)) { + CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5"); + } + + spin_lock(&a5_dev->hw_lock); + if (core_info->irq_cb.icp_hw_mgr_cb) + core_info->irq_cb.icp_hw_mgr_cb(irq_status, + core_info->irq_cb.data); + spin_unlock(&a5_dev->hw_lock); + + return IRQ_HANDLED; +} + +int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + struct a5_soc_info *a5_soc = NULL; + unsigned long flags; + uint32_t ubwc_ipe_cfg[ICP_UBWC_MAX] = {0}; + uint32_t ubwc_bps_cfg[ICP_UBWC_MAX] = {0}; + uint32_t index = 0; + int rc = 0, ddr_type = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_ICP_A5_CMD_MAX) { + CAM_ERR(CAM_ICP, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + hw_info = core_info->a5_hw_info; + + switch (cmd_type) { + case CAM_ICP_A5_CMD_FW_DOWNLOAD: + rc = cam_a5_download_fw(device_priv); + break; + case CAM_ICP_A5_CMD_SET_FW_BUF: { + struct cam_icp_a5_set_fw_buf_info *fw_buf_info = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + core_info->fw_buf = fw_buf_info->iova; + core_info->fw_kva_addr = fw_buf_info->kva; + core_info->fw_buf_len = fw_buf_info->len; + + CAM_DBG(CAM_ICP, "fw buf info = %x %llx %lld", + core_info->fw_buf, core_info->fw_kva_addr, + core_info->fw_buf_len); + break; + } + case CAM_ICP_A5_SET_IRQ_CB: { + struct cam_icp_a5_set_irq_cb *irq_cb = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + spin_lock_irqsave(&a5_dev->hw_lock, flags); + core_info->irq_cb.icp_hw_mgr_cb = irq_cb->icp_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + spin_unlock_irqrestore(&a5_dev->hw_lock, flags); + break; + } + + case CAM_ICP_A5_SEND_INIT: + hfi_send_system_cmd(HFI_CMD_SYS_INIT, 0, 0); + break; + + case CAM_ICP_A5_CMD_PC_PREP: + hfi_send_system_cmd(HFI_CMD_SYS_PC_PREP, 0, 0); + break; + + case CAM_ICP_A5_CMD_VOTE_CPAS: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + cam_a5_cpas_vote(core_info, cpas_vote); + break; + } + + case CAM_ICP_A5_CMD_CPAS_START: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + if (!core_info->cpas_start) { + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote->ahb_vote, + &cpas_vote->axi_vote); + core_info->cpas_start = true; + } + break; + } + + case CAM_ICP_A5_CMD_CPAS_STOP: + if (core_info->cpas_start) { + cam_cpas_stop(core_info->cpas_handle); + core_info->cpas_start = false; + } + break; + case CAM_ICP_A5_CMD_UBWC_CFG: { + struct a5_ubwc_cfg_ext *ubwc_cfg_ext = NULL; + + a5_soc = soc_info->soc_private; + if (!a5_soc) { + CAM_ERR(CAM_ICP, "A5 private soc info is NULL"); + return -EINVAL; + } + + if (a5_soc->ubwc_config_ext) { + /* Invoke kernel API to determine DDR type */ + ddr_type = of_fdt_get_ddrtype(); + if ((ddr_type == DDR_TYPE_LPDDR5) || + (ddr_type == DDR_TYPE_LPDDR5X)) + index = 1; + + ubwc_cfg_ext = &a5_soc->uconfig.ubwc_cfg_ext; + ubwc_ipe_cfg[0] = + ubwc_cfg_ext->ubwc_ipe_fetch_cfg[index]; + ubwc_ipe_cfg[1] = + ubwc_cfg_ext->ubwc_ipe_write_cfg[index]; + ubwc_bps_cfg[0] = + ubwc_cfg_ext->ubwc_bps_fetch_cfg[index]; + ubwc_bps_cfg[1] = + ubwc_cfg_ext->ubwc_bps_write_cfg[index]; + rc = hfi_cmd_ubwc_config_ext(&ubwc_ipe_cfg[0], + &ubwc_bps_cfg[0]); + } else { + rc = hfi_cmd_ubwc_config(a5_soc->uconfig.ubwc_cfg); + } + + break; + } + default: + break; + } + + return rc; +} diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.h b/drivers/cam_icp/icp_hw/a5_hw/a5_core.h new file mode 100644 index 000000000000..a5c0fffde1d1 --- /dev/null +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_A5_CORE_H +#define CAM_A5_CORE_H + +#include +#include +#include +#include +#include "cam_a5_hw_intf.h" + +#define A5_QGIC_BASE 0 +#define A5_SIERRA_BASE 1 +#define A5_CSR_BASE 2 + +#define A5_HOST_INT 0x1 +#define A5_WDT_0 0x2 +#define A5_WDT_1 0x4 + +#define ELF_GUARD_PAGE (2 * 1024 * 1024) + +struct cam_a5_device_hw_info { + uint32_t hw_ver; + uint32_t nsec_reset; + uint32_t a5_control; + uint32_t a5_host_int_en; + uint32_t a5_host_int; + uint32_t a5_host_int_clr; + uint32_t a5_host_int_status; + uint32_t a5_host_int_set; + uint32_t host_a5_int; + uint32_t fw_version; + uint32_t init_req; + uint32_t init_response; + uint32_t shared_mem_ptr; + uint32_t shared_mem_size; + uint32_t qtbl_ptr; + uint32_t uncached_heap_ptr; + uint32_t uncached_heap_size; + uint32_t a5_status; +}; + +/** + * struct cam_a5_device_hw_info + * @a5_hw_info: A5 hardware info + * @fw_elf: start address of fw start with elf header + * @fw: start address of fw blob + * @fw_buf: smmu alloc/mapped fw buffer + * @fw_buf_len: fw buffer length + * @query_cap: A5 query info from firmware + * @a5_acquire: Acquire information of A5 + * @irq_cb: IRQ callback + * @cpas_handle: CPAS handle for A5 + * @cpast_start: state variable for cpas + */ +struct cam_a5_device_core_info { + struct cam_a5_device_hw_info *a5_hw_info; + const struct firmware *fw_elf; + void *fw; + uint32_t fw_buf; + uintptr_t fw_kva_addr; + uint64_t fw_buf_len; + struct cam_icp_a5_query_cap query_cap; + struct cam_icp_a5_acquire_dev a5_acquire[8]; + struct cam_icp_a5_set_irq_cb irq_cb; + uint32_t cpas_handle; + bool cpas_start; +}; + +int cam_a5_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_a5_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_a5_irq(int irq_num, void *data); +#endif /* CAM_A5_CORE_H */ diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_dev.c b/drivers/cam_icp/icp_hw/a5_hw/a5_dev.c new file mode 100644 index 000000000000..b4f33d3e4dd3 --- /dev/null +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_dev.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "a5_core.h" +#include "a5_soc.h" +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_a5_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +struct a5_soc_info cam_a5_soc_info; +EXPORT_SYMBOL(cam_a5_soc_info); + +struct cam_a5_device_hw_info cam_a5_hw_info = { + .hw_ver = 0x0, + .nsec_reset = 0x4, + .a5_control = 0x8, + .a5_host_int_en = 0x10, + .a5_host_int = 0x14, + .a5_host_int_clr = 0x18, + .a5_host_int_status = 0x1c, + .a5_host_int_set = 0x20, + .host_a5_int = 0x30, + .fw_version = 0x44, + .init_req = 0x48, + .init_response = 0x4c, + .shared_mem_ptr = 0x50, + .shared_mem_size = 0x54, + .qtbl_ptr = 0x58, + .uncached_heap_ptr = 0x5c, + .uncached_heap_size = 0x60, + .a5_status = 0x200, +}; +EXPORT_SYMBOL(cam_a5_hw_info); + +static bool cam_a5_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + bool error_handled = false; + + if (!irq_data) + return error_handled; + + switch (irq_data->irq_type) { + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Decode error type=%d status=%x thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d", + irq_data->irq_type, + irq_data->u.dec_err.decerr_status.value, + irq_data->u.dec_err.decerr_status.thr_err, + irq_data->u.dec_err.decerr_status.fcl_err, + irq_data->u.dec_err.decerr_status.len_md_err, + irq_data->u.dec_err.decerr_status.format_err); + error_handled = true; + break; + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Encode error type=%d status=%x", + irq_data->irq_type, + irq_data->u.enc_err.encerr_status.value); + error_handled = true; + break; + default: + break; + } + + return error_handled; +} + +int cam_a5_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_a5_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = &soc_info->pdev->dev; + memcpy(cpas_register_params.identifier, "icp", sizeof("icp")); + cpas_register_params.cam_cpas_client_cb = cam_a5_cpas_cb; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed: %d", rc); + return rc; + } + + core_info->cpas_handle = cpas_register_params.client_handle; + return rc; +} + +int cam_a5_probe(struct platform_device *pdev) +{ + int rc = 0; + struct cam_hw_info *a5_dev = NULL; + struct cam_hw_intf *a5_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + + a5_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!a5_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &a5_dev_intf->hw_idx); + + a5_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!a5_dev) { + rc = -ENOMEM; + goto a5_dev_alloc_failure; + } + + a5_dev->soc_info.pdev = pdev; + a5_dev->soc_info.dev = &pdev->dev; + a5_dev->soc_info.dev_name = pdev->name; + a5_dev_intf->hw_priv = a5_dev; + a5_dev_intf->hw_ops.init = cam_a5_init_hw; + a5_dev_intf->hw_ops.deinit = cam_a5_deinit_hw; + a5_dev_intf->hw_ops.process_cmd = cam_a5_process_cmd; + a5_dev_intf->hw_type = CAM_ICP_DEV_A5; + + CAM_DBG(CAM_ICP, "type %d index %d", + a5_dev_intf->hw_type, + a5_dev_intf->hw_idx); + + platform_set_drvdata(pdev, a5_dev_intf); + + a5_dev->core_info = kzalloc(sizeof(struct cam_a5_device_core_info), + GFP_KERNEL); + if (!a5_dev->core_info) { + rc = -ENOMEM; + goto core_info_alloc_failure; + } + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ICP, "No a5 hardware info"); + rc = -EINVAL; + goto match_err; + } + hw_info = (struct cam_a5_device_hw_info *)match_dev->data; + core_info->a5_hw_info = hw_info; + + a5_dev->soc_info.soc_private = &cam_a5_soc_info; + + rc = cam_a5_init_soc_resources(&a5_dev->soc_info, cam_a5_irq, + a5_dev); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed to init_soc"); + goto init_soc_failure; + } + + CAM_DBG(CAM_ICP, "soc info : %pK", + (void *)&a5_dev->soc_info); + rc = cam_a5_register_cpas(&a5_dev->soc_info, + core_info, a5_dev_intf->hw_idx); + if (rc < 0) { + CAM_ERR(CAM_ICP, "a5 cpas registration failed"); + goto cpas_reg_failed; + } + a5_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&a5_dev->hw_mutex); + spin_lock_init(&a5_dev->hw_lock); + init_completion(&a5_dev->hw_complete); + + CAM_DBG(CAM_ICP, "A5%d probe successful", + a5_dev_intf->hw_idx); + return 0; + +cpas_reg_failed: +init_soc_failure: +match_err: + kfree(a5_dev->core_info); +core_info_alloc_failure: + kfree(a5_dev); +a5_dev_alloc_failure: + kfree(a5_dev_intf); + + return rc; +} + +static const struct of_device_id cam_a5_dt_match[] = { + { + .compatible = "qcom,cam-a5", + .data = &cam_a5_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_a5_dt_match); + +static struct platform_driver cam_a5_driver = { + .probe = cam_a5_probe, + .driver = { + .name = "cam-a5", + .owner = THIS_MODULE, + .of_match_table = cam_a5_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_a5_init_module(void) +{ + return platform_driver_register(&cam_a5_driver); +} + +static void __exit cam_a5_exit_module(void) +{ + platform_driver_unregister(&cam_a5_driver); +} + +module_init(cam_a5_init_module); +module_exit(cam_a5_exit_module); +MODULE_DESCRIPTION("CAM A5 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c new file mode 100644 index 000000000000..bcdc12632356 --- /dev/null +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "a5_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static int cam_a5_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0, i; + const char *fw_name; + struct a5_soc_info *a5_soc_info; + struct device_node *of_node = NULL; + struct platform_device *pdev = NULL; + struct a5_ubwc_cfg_ext *ubwc_cfg_ext = NULL; + int num_ubwc_cfg; + + pdev = soc_info->pdev; + of_node = pdev->dev.of_node; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_ICP, "get a5 dt prop is failed"); + return rc; + } + + a5_soc_info = soc_info->soc_private; + fw_name = a5_soc_info->fw_name; + + rc = of_property_read_string(of_node, "fw_name", &fw_name); + if (rc < 0) { + CAM_ERR(CAM_ICP, "fw_name read failed"); + goto end; + } + + ubwc_cfg_ext = &a5_soc_info->uconfig.ubwc_cfg_ext; + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-ipe-fetch-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_DBG(CAM_ICP, "wrong ubwc_ipe_fetch_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto ubwc_ex_cfg; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-ipe-fetch-cfg", + i, &ubwc_cfg_ext->ubwc_ipe_fetch_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_ipe_fetch_cfg values"); + goto end; + } + } + + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-ipe-write-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_ipe_write_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-ipe-write-cfg", + i, &ubwc_cfg_ext->ubwc_ipe_write_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_ipe_write_cfg values"); + goto end; + } + } + + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-bps-fetch-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_bps_fetch_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-bps-fetch-cfg", + i, &ubwc_cfg_ext->ubwc_bps_fetch_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_bps_fetch_cfg values"); + goto end; + } + } + + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-bps-write-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_bps_write_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-bps-write-cfg", + i, &ubwc_cfg_ext->ubwc_bps_write_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_bps_write_cfg values"); + goto end; + } + } + + a5_soc_info->ubwc_config_ext = true; + CAM_DBG(CAM_ICP, "read ubwc_cfg_ext for ipe/bps"); + return rc; + +ubwc_ex_cfg: + num_ubwc_cfg = of_property_count_u32_elems(of_node, "ubwc-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-cfg", + i, &a5_soc_info->uconfig.ubwc_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, "unable to read ubwc_cfg values"); + break; + } + } + +end: + return rc; +} + +static int cam_a5_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t a5_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, a5_irq_handler, + irq_data); + + return rc; +} + +int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t a5_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_a5_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + rc = cam_a5_request_platform_resource(soc_info, a5_irq_handler, + irq_data); + if (rc < 0) + return rc; + + return rc; +} + +int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) + CAM_ERR(CAM_ICP, "enable platform failed"); + + return rc; +} + +int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_ICP, "disable platform failed"); + + return rc; +} diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h new file mode 100644 index 000000000000..eadf9d726696 --- /dev/null +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_A5_SOC_H +#define CAM_A5_SOC_H + +#include "cam_soc_util.h" + +#define ICP_UBWC_MAX 2 + +struct a5_ubwc_cfg_ext { + uint32_t ubwc_ipe_fetch_cfg[ICP_UBWC_MAX]; + uint32_t ubwc_ipe_write_cfg[ICP_UBWC_MAX]; + uint32_t ubwc_bps_fetch_cfg[ICP_UBWC_MAX]; + uint32_t ubwc_bps_write_cfg[ICP_UBWC_MAX]; +}; + +struct a5_soc_info { + char *fw_name; + bool ubwc_config_ext; + union { + uint32_t ubwc_cfg[ICP_UBWC_MAX]; + struct a5_ubwc_cfg_ext ubwc_cfg_ext; + } uconfig; +}; + +int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t a5_irq_handler, void *irq_data); + +int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +#endif diff --git a/drivers/cam_icp/icp_hw/bps_hw/Makefile b/drivers/cam_icp/icp_hw/bps_hw/Makefile new file mode 100644 index 000000000000..2abf88310cbd --- /dev/null +++ b/drivers/cam_icp/icp_hw/bps_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/bps_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += bps_dev.o bps_core.o bps_soc.o diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c new file mode 100644 index 000000000000..73075a4ec379 --- /dev/null +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "bps_core.h" +#include "bps_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_bps_hw_intf.h" +#include "cam_icp_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 + +static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info, + struct cam_icp_cpas_vote *cpas_vote) +{ + int rc = 0; + + if (cpas_vote->ahb_vote_valid) + rc = cam_cpas_update_ahb_vote(core_info->cpas_handle, + &cpas_vote->ahb_vote); + if (cpas_vote->axi_vote_valid) + rc = cam_cpas_update_axi_vote(core_info->cpas_handle, + &cpas_vote->axi_vote); + + if (rc < 0) + CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + + return rc; +} + + +int cam_bps_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *bps_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_icp_cpas_vote cpas_vote; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote.axi_vote.num_paths = 1; + cpas_vote.axi_vote.axi_path[0].path_data_type = + CAM_BPS_DEFAULT_AXI_PATH; + cpas_vote.axi_vote.axi_path[0].transac_type = + CAM_BPS_DEFAULT_AXI_TRANSAC; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_ICP, "cpas start failed: %d", rc); + goto error; + } + core_info->cpas_start = true; + + rc = cam_bps_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ICP, "soc enable is failed: %d", rc); + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } else { + core_info->clk_enable = true; + } + +error: + return rc; +} + +int cam_bps_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *bps_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + rc = cam_bps_disable_soc_resources(soc_info, core_info->clk_enable); + if (rc) + CAM_ERR(CAM_ICP, "soc disable is failed: %d", rc); + core_info->clk_enable = false; + + if (core_info->cpas_start) { + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + + return rc; +} + +static int cam_bps_handle_pc(struct cam_hw_info *bps_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + hw_info = core_info->bps_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + if (!(pwr_ctrl & BPS_COLLAPSE_MASK)) { + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x1); + + if ((pwr_status >> BPS_PWR_ON_MASK)) + CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + pwr_status, pwr_ctrl); + } + cam_bps_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, + &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return 0; +} + +static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + int rc = 0; + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + hw_info = core_info->bps_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); + if (pwr_ctrl & BPS_COLLAPSE_MASK) { + CAM_DBG(CAM_ICP, "BPS: pwr_ctrl set(%x)", pwr_ctrl); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0); + } + + rc = cam_bps_transfer_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); + CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return rc; +} + +static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_bps_device_core_info *core_info) +{ + uint32_t retry_cnt = 0; + uint32_t status = 0; + int pwr_ctrl, pwr_status, rc = 0; + bool reset_bps_cdm_fail = false; + bool reset_bps_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET"); + + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_ICP, "BPS reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + + /* Reset BPS CDM core*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_cdm_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS CDM rst failed status 0x%x", status); + reset_bps_cdm_fail = true; + } + + /* Reset BPS core*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + BPS_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_top_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS top rst failed status 0x%x", status); + reset_bps_top_fail = true; + } + + cam_bps_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After) pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_bps_cdm_fail || reset_bps_top_fail) + rc = -EAGAIN; + + return rc; +} + +int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *bps_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_ICP_BPS_CMD_MAX) { + CAM_ERR(CAM_ICP, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + hw_info = core_info->bps_hw_info; + + switch (cmd_type) { + case CAM_ICP_BPS_CMD_VOTE_CPAS: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + cam_bps_cpas_vote(core_info, cpas_vote); + break; + } + + case CAM_ICP_BPS_CMD_CPAS_START: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + if (!core_info->cpas_start) { + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote->ahb_vote, + &cpas_vote->axi_vote); + core_info->cpas_start = true; + } + break; + } + + case CAM_ICP_BPS_CMD_CPAS_STOP: + if (core_info->cpas_start) { + cam_cpas_stop(core_info->cpas_handle); + core_info->cpas_start = false; + } + break; + case CAM_ICP_BPS_CMD_POWER_COLLAPSE: + rc = cam_bps_handle_pc(bps_dev); + break; + case CAM_ICP_BPS_CMD_POWER_RESUME: + rc = cam_bps_handle_resume(bps_dev); + break; + case CAM_ICP_BPS_CMD_UPDATE_CLK: { + struct cam_a5_clk_update_cmd *clk_upd_cmd = + (struct cam_a5_clk_update_cmd *)cmd_args; + uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + + CAM_DBG(CAM_ICP, "bps_src_clk rate = %d", (int)clk_rate); + + if (!core_info->clk_enable) { + if (clk_upd_cmd->ipe_bps_pc_enable) { + cam_bps_handle_pc(bps_dev); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x0); + } + rc = cam_bps_toggle_clk(soc_info, true); + if (rc) + CAM_ERR(CAM_ICP, "Enable failed"); + else + core_info->clk_enable = true; + if (clk_upd_cmd->ipe_bps_pc_enable) { + rc = cam_bps_handle_resume(bps_dev); + if (rc) + CAM_ERR(CAM_ICP, "BPS resume failed"); + } + } + CAM_DBG(CAM_ICP, "clock rate %d", clk_rate); + rc = cam_bps_update_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_ICP, "Failed to update clk"); + } + break; + case CAM_ICP_BPS_CMD_DISABLE_CLK: + if (core_info->clk_enable == true) + cam_bps_toggle_clk(soc_info, false); + core_info->clk_enable = false; + break; + case CAM_ICP_BPS_CMD_RESET: + rc = cam_bps_cmd_reset(soc_info, core_info); + break; + default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; + break; + } + return rc; +} + +irqreturn_t cam_bps_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_core.h b/drivers/cam_icp/icp_hw/bps_hw/bps_core.h new file mode 100644 index 000000000000..162c5e65530c --- /dev/null +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_core.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_BPS_CORE_H +#define CAM_BPS_CORE_H + +#include +#include +#include +#include + +#define BPS_COLLAPSE_MASK 0x1 +#define BPS_PWR_ON_MASK 0x2 + +struct cam_bps_device_hw_info { + uint32_t hw_idx; + uint32_t pwr_ctrl; + uint32_t pwr_status; + uint32_t reserved; +}; + +struct cam_bps_device_core_info { + struct cam_bps_device_hw_info *bps_hw_info; + uint32_t cpas_handle; + bool cpas_start; + bool clk_enable; +}; + +int cam_bps_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_bps_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_bps_irq(int irq_num, void *data); +#endif /* CAM_BPS_CORE_H */ diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_dev.c b/drivers/cam_icp/icp_hw/bps_hw/bps_dev.c new file mode 100644 index 000000000000..a80c27325b72 --- /dev/null +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_dev.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "bps_core.h" +#include "bps_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_icp_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static struct cam_bps_device_hw_info cam_bps_hw_info = { + .hw_idx = 0, + .pwr_ctrl = 0x5c, + .pwr_status = 0x58, + .reserved = 0, +}; +EXPORT_SYMBOL(cam_bps_hw_info); + +static char bps_dev_name[8]; + +static bool cam_bps_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + bool error_handled = false; + + if (!irq_data) + return error_handled; + + switch (irq_data->irq_type) { + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Decode error type=%d status=%x thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d", + irq_data->irq_type, + irq_data->u.dec_err.decerr_status.value, + irq_data->u.dec_err.decerr_status.thr_err, + irq_data->u.dec_err.decerr_status.fcl_err, + irq_data->u.dec_err.decerr_status.len_md_err, + irq_data->u.dec_err.decerr_status.format_err); + error_handled = true; + break; + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Encode error type=%d status=%x", + irq_data->irq_type, + irq_data->u.enc_err.encerr_status.value); + error_handled = true; + break; + default: + break; + } + + return error_handled; +} + +int cam_bps_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_bps_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = &soc_info->pdev->dev; + memcpy(cpas_register_params.identifier, "bps", sizeof("bps")); + cpas_register_params.cam_cpas_client_cb = cam_bps_cpas_cb; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +int cam_bps_probe(struct platform_device *pdev) +{ + struct cam_hw_info *bps_dev = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int rc = 0; + + bps_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!bps_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &bps_dev_intf->hw_idx); + + bps_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!bps_dev) { + kfree(bps_dev_intf); + return -ENOMEM; + } + + memset(bps_dev_name, 0, sizeof(bps_dev_name)); + snprintf(bps_dev_name, sizeof(bps_dev_name), + "bps%1u", bps_dev_intf->hw_idx); + + bps_dev->soc_info.pdev = pdev; + bps_dev->soc_info.dev = &pdev->dev; + bps_dev->soc_info.dev_name = bps_dev_name; + bps_dev_intf->hw_priv = bps_dev; + bps_dev_intf->hw_ops.init = cam_bps_init_hw; + bps_dev_intf->hw_ops.deinit = cam_bps_deinit_hw; + bps_dev_intf->hw_ops.process_cmd = cam_bps_process_cmd; + bps_dev_intf->hw_type = CAM_ICP_DEV_BPS; + platform_set_drvdata(pdev, bps_dev_intf); + bps_dev->core_info = kzalloc(sizeof(struct cam_bps_device_core_info), + GFP_KERNEL); + if (!bps_dev->core_info) { + kfree(bps_dev); + kfree(bps_dev_intf); + return -ENOMEM; + } + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ICP, "No bps hardware info"); + kfree(bps_dev->core_info); + kfree(bps_dev); + kfree(bps_dev_intf); + rc = -EINVAL; + return rc; + } + hw_info = &cam_bps_hw_info; + core_info->bps_hw_info = hw_info; + + rc = cam_bps_init_soc_resources(&bps_dev->soc_info, cam_bps_irq, + bps_dev); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed to init_soc"); + kfree(bps_dev->core_info); + kfree(bps_dev); + kfree(bps_dev_intf); + return rc; + } + CAM_DBG(CAM_ICP, "soc info : %pK", + (void *)&bps_dev->soc_info); + + rc = cam_bps_register_cpas(&bps_dev->soc_info, + core_info, bps_dev_intf->hw_idx); + if (rc < 0) { + kfree(bps_dev->core_info); + kfree(bps_dev); + kfree(bps_dev_intf); + return rc; + } + bps_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&bps_dev->hw_mutex); + spin_lock_init(&bps_dev->hw_lock); + init_completion(&bps_dev->hw_complete); + CAM_DBG(CAM_ICP, "BPS%d probe successful", + bps_dev_intf->hw_idx); + + return rc; +} + +static const struct of_device_id cam_bps_dt_match[] = { + { + .compatible = "qcom,cam-bps", + .data = &cam_bps_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_bps_dt_match); + +static struct platform_driver cam_bps_driver = { + .probe = cam_bps_probe, + .driver = { + .name = "cam-bps", + .owner = THIS_MODULE, + .of_match_table = cam_bps_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_bps_init_module(void) +{ + return platform_driver_register(&cam_bps_driver); +} + +static void __exit cam_bps_exit_module(void) +{ + platform_driver_unregister(&cam_bps_driver); +} + +module_init(cam_bps_init_module); +module_exit(cam_bps_exit_module); +MODULE_DESCRIPTION("CAM BPS driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c new file mode 100644 index 000000000000..bf152d1fc485 --- /dev/null +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "bps_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static int cam_bps_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) + CAM_ERR(CAM_ICP, "get bps dt prop is failed"); + + return rc; +} + +static int cam_bps_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t bps_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, bps_irq_handler, + irq_data); + + return rc; +} + +int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t bps_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_bps_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + rc = cam_bps_request_platform_resource(soc_info, bps_irq_handler, + irq_data); + if (rc < 0) + return rc; + + return rc; +} + +int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, false); + if (rc) + CAM_ERR(CAM_ICP, "enable platform failed"); + + return rc; +} + +int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + false); + if (rc) + CAM_ERR(CAM_ICP, "disable platform failed"); + + return rc; +} + +int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + + return rc; +} + +int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + + return rc; +} + +int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate) +{ + int32_t src_clk_idx; + + if (!soc_info) + return -EINVAL; + + src_clk_idx = soc_info->src_clk_idx; + + if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && + (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && + (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { + CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + clk_rate, + soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); + clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; + } + + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); +} + +int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) +{ + int rc = 0; + + if (clk_enable) + rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + else + cam_soc_util_clk_disable_default(soc_info); + + return rc; +} diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.h b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.h new file mode 100644 index 000000000000..da4feac909e4 --- /dev/null +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_BPS_SOC_H_ +#define _CAM_BPS_SOC_H_ + +#include "cam_soc_util.h" + +int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t bps_irq_handler, void *irq_data); + +int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk); + +int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate); +int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable); +#endif /* _CAM_BPS_SOC_H_*/ diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile b/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile new file mode 100644 index 000000000000..2d06413e74ca --- /dev/null +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_hw_mgr.o 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 new file mode 100644 index 000000000000..2a77519d92cb --- /dev/null +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -0,0 +1,5582 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_sync_api.h" +#include "cam_packet_util.h" +#include "cam_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_icp_hw_mgr.h" +#include "cam_a5_hw_intf.h" +#include "cam_bps_hw_intf.h" +#include "cam_ipe_hw_intf.h" +#include "cam_smmu_api.h" +#include "cam_mem_mgr.h" +#include "hfi_intf.h" +#include "hfi_reg.h" +#include "hfi_session_defs.h" +#include "hfi_sys_defs.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "a5_core.h" +#include "hfi_sys_defs.h" +#include "cam_debug_util.h" +#include "cam_soc_util.h" +#include "cam_trace.h" +#include "cam_cpas_api.h" +#include "cam_common_util.h" + +#define ICP_WORKQ_TASK_CMD_TYPE 1 +#define ICP_WORKQ_TASK_MSG_TYPE 2 + +#define ICP_DEV_TYPE_TO_CLK_TYPE(dev_type) \ + ((dev_type == CAM_ICP_RES_TYPE_BPS) ? ICP_CLK_HW_BPS : ICP_CLK_HW_IPE) + +#define ICP_DEVICE_IDLE_TIMEOUT 400 + +static struct cam_icp_hw_mgr icp_hw_mgr; + +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl); + +static const char *cam_icp_dev_type_to_name( + uint32_t dev_type) +{ + switch (dev_type) { + case CAM_ICP_RES_TYPE_BPS: + return "BPS"; + case CAM_ICP_RES_TYPE_IPE_RT: + return "IPE_RT"; + case CAM_ICP_RES_TYPE_IPE: + return "IPE"; + default: + return "Invalid dev type"; + } +} + +static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + int rc; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is NULL"); + return -EINVAL; + } + + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_UBWC_CFG, NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "CAM_ICP_A5_CMD_UBWC_CFG is failed"); + + return rc; +} + +static void cam_icp_hw_mgr_clk_info_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + struct cam_icp_clk_info *hw_mgr_clk_info; + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + else + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + + if (hw_mgr_clk_info->base_clk >= ctx_data->clk_info.base_clk) + hw_mgr_clk_info->base_clk -= ctx_data->clk_info.base_clk; +} + +static void cam_icp_hw_mgr_reset_clk_info(struct cam_icp_hw_mgr *hw_mgr) +{ + int i; + + for (i = 0; i < ICP_CLK_HW_MAX; i++) { + hw_mgr->clk_info[i].base_clk = 0; + hw_mgr->clk_info[i].curr_clk = ICP_CLK_SVS_HZ; + hw_mgr->clk_info[i].threshold = ICP_OVER_CLK_THRESHOLD; + hw_mgr->clk_info[i].over_clked = 0; + hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + } + hw_mgr->icp_default_clk = ICP_CLK_SVS_HZ; +} + +static int cam_icp_get_actual_clk_rate_idx( + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + for (i = 0; i < CAM_MAX_VOTE; i++) + if (ctx_data->clk_info.clk_rate[i] >= base_clk) + return i; + + /* + * Caller has to ensure returned index is within array + * size bounds while accessing that index. + */ + + return i; +} + +static bool cam_icp_is_over_clk(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info) +{ + int base_clk_idx; + int curr_clk_idx; + + base_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data, + hw_mgr_clk_info->base_clk); + + curr_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data, + hw_mgr_clk_info->curr_clk); + + CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %d %d", + base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk, + hw_mgr_clk_info->curr_clk); + + if (curr_clk_idx > base_clk_idx) + return true; + + return false; +} + +static int cam_icp_get_lower_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + i = cam_icp_get_actual_clk_rate_idx(ctx_data, base_clk); + + if (i > 0) + return ctx_data->clk_info.clk_rate[i - 1]; + + CAM_DBG(CAM_ICP, "Already clk at lower level"); + return base_clk; +} + +static int cam_icp_get_next_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + i = cam_icp_get_actual_clk_rate_idx(ctx_data, base_clk); + + if (i < CAM_MAX_VOTE - 1) + return ctx_data->clk_info.clk_rate[i + 1]; + + CAM_DBG(CAM_ICP, "Already clk at higher level"); + + return base_clk; +} + +static int cam_icp_get_actual_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + for (i = 0; i < CAM_MAX_VOTE; i++) + if (ctx_data->clk_info.clk_rate[i] >= base_clk) + return ctx_data->clk_info.clk_rate[i]; + + return base_clk; +} + +static int cam_icp_supported_clk_rates(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *dev_intf = NULL; + struct cam_hw_info *dev = NULL; + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + dev_intf = hw_mgr->bps_dev_intf; + else + dev_intf = hw_mgr->ipe0_dev_intf; + + if (!dev_intf) { + CAM_ERR(CAM_ICP, "dev_intf is invalid"); + return -EINVAL; + } + dev = (struct cam_hw_info *)dev_intf->hw_priv; + soc_info = &dev->soc_info; + + for (i = 0; i < CAM_MAX_VOTE; i++) { + ctx_data->clk_info.clk_rate[i] = + soc_info->clk_rate[i][soc_info->src_clk_idx]; + CAM_DBG(CAM_ICP, "clk_info[%d] = %d", + i, ctx_data->clk_info.clk_rate[i]); + } + + return 0; +} + +static int cam_icp_clk_idx_from_req_id(struct cam_icp_hw_ctx_data *ctx_data, + uint64_t req_id) +{ + struct hfi_frame_process_info *frame_process; + int i; + + frame_process = &ctx_data->hfi_frame_process; + + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) + if (frame_process->request_id[i] == req_id) + return i; + + return 0; +} + +static int cam_icp_ctx_clk_info_init(struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + ctx_data->clk_info.uncompressed_bw = 0; + ctx_data->clk_info.compressed_bw = 0; + for (i = 0; i < CAM_ICP_MAX_PER_PATH_VOTES; i++) { + ctx_data->clk_info.axi_path[i].camnoc_bw = 0; + ctx_data->clk_info.axi_path[i].mnoc_ab_bw = 0; + ctx_data->clk_info.axi_path[i].mnoc_ib_bw = 0; + } + + cam_icp_supported_clk_rates(&icp_hw_mgr, ctx_data); + + return 0; +} + +static bool cam_icp_frame_pending(struct cam_icp_hw_ctx_data *ctx_data) +{ + return !bitmap_empty(ctx_data->hfi_frame_process.bitmap, + CAM_FRAME_CMD_MAX); +} + +static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data) +{ + if (ctx_data && ctx_data->watch_dog) { + ctx_data->watch_dog_reset_counter++; + CAM_DBG(CAM_ICP, "reset timer : ctx_id = %d, counter=%d", + ctx_data->ctx_id, ctx_data->watch_dog_reset_counter); + crm_timer_reset(ctx_data->watch_dog); + } + + return 0; +} + +static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr, + int device_index) +{ + if ((device_index >= ICP_CLK_HW_MAX) || (!hw_mgr)) + return; + + if (hw_mgr->clk_info[device_index].watch_dog) { + CAM_DBG(CAM_ICP, "reset timer : device_index = %d", + device_index); + crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog); + hw_mgr->clk_info[device_index].watch_dog_reset_counter++; + } +} + +static int32_t cam_icp_deinit_idle_clk(void *priv, void *data) +{ + struct cam_icp_hw_mgr *hw_mgr = (struct cam_icp_hw_mgr *)priv; + struct clk_work_data *task_data = (struct clk_work_data *)data; + struct cam_icp_clk_info *clk_info = + (struct cam_icp_clk_info *)task_data->data; + uint32_t id; + uint32_t i; + struct cam_icp_hw_ctx_data *ctx_data; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *dev_intf = NULL; + struct cam_a5_clk_update_cmd clk_upd_cmd; + int rc = 0; + bool busy = false; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + clk_info->base_clk = 0; + clk_info->curr_clk = 0; + clk_info->over_clked = 0; + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + ctx_data = &hw_mgr->ctx_data[i]; + mutex_lock(&ctx_data->ctx_mutex); + if ((ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED) && + (ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type) + == clk_info->hw_type)) { + busy = cam_icp_frame_pending(ctx_data); + if (busy) { + mutex_unlock(&ctx_data->ctx_mutex); + break; + } + cam_icp_ctx_clk_info_init(ctx_data); + } + mutex_unlock(&ctx_data->ctx_mutex); + } + + if (busy) { + cam_icp_device_timer_reset(hw_mgr, clk_info->hw_type); + rc = -EBUSY; + goto done; + } + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + rc = -EINVAL; + goto done; + } + + if (clk_info->hw_type == ICP_CLK_HW_BPS) { + dev_intf = bps_dev_intf; + id = CAM_ICP_BPS_CMD_DISABLE_CLK; + } else if (clk_info->hw_type == ICP_CLK_HW_IPE) { + dev_intf = ipe0_dev_intf; + id = CAM_ICP_IPE_CMD_DISABLE_CLK; + } else { + CAM_ERR(CAM_ICP, "Error"); + goto done; + } + + CAM_DBG(CAM_ICP, "Disable %d", clk_info->hw_type); + + clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; + + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd)); + + if (clk_info->hw_type != ICP_CLK_HW_BPS) + if (ipe1_dev_intf) + ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, id, + &clk_upd_cmd, + sizeof(struct cam_a5_clk_update_cmd)); + +done: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int32_t cam_icp_ctx_timer(void *priv, void *data) +{ + struct clk_work_data *task_data = (struct clk_work_data *)data; + struct cam_icp_hw_ctx_data *ctx_data = + (struct cam_icp_hw_ctx_data *)task_data->data; + struct cam_icp_hw_mgr *hw_mgr = &icp_hw_mgr; + uint32_t id; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *dev_intf = NULL; + struct cam_icp_clk_info *clk_info; + struct cam_icp_cpas_vote clk_update; + int i = 0; + int device_share_ratio = 1; + + if (!ctx_data) { + CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) || + (ctx_data->watch_dog_reset_counter == 0)) { + CAM_DBG(CAM_ICP, "state %d, counter=%d", + ctx_data->state, ctx_data->watch_dog_reset_counter); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + if (cam_icp_frame_pending(ctx_data)) { + cam_icp_ctx_timer_reset(ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + return -EBUSY; + } + + CAM_DBG(CAM_ICP, + "E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", + ctx_data->ctx_id, + ctx_data->clk_info.uncompressed_bw, + ctx_data->clk_info.compressed_bw, + ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + + if (!ctx_data->icp_dev_acquire_info) { + CAM_WARN(CAM_ICP, "NULL acquire info"); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + dev_intf = bps_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + id = CAM_ICP_BPS_CMD_VOTE_CPAS; + } else { + dev_intf = ipe0_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + id = CAM_ICP_IPE_CMD_VOTE_CPAS; + } + + /* + * Since there are 2 devices, we assume the load is evenly shared + * between HWs and corresponding AXI paths. So divide total bw by half + * to vote on each device + */ + if ((ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) + device_share_ratio = 2; + + clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC; + clk_update.ahb_vote.vote.freq = 0; + clk_update.ahb_vote_valid = false; + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { + clk_update.axi_vote.num_paths = 1; + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_BPS_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_BPS_DEFAULT_AXI_TRANSAC; + } else { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_IPE_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_IPE_DEFAULT_AXI_TRANSAC; + } + + clk_info->compressed_bw -= ctx_data->clk_info.compressed_bw; + clk_info->uncompressed_bw -= ctx_data->clk_info.uncompressed_bw; + + ctx_data->clk_info.uncompressed_bw = 0; + ctx_data->clk_info.compressed_bw = 0; + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + + clk_update.axi_vote.num_paths = 1; + clk_update.axi_vote.axi_path[0].camnoc_bw = + clk_info->uncompressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].mnoc_ab_bw = + clk_info->compressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].mnoc_ib_bw = + clk_info->compressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].ddr_ab_bw = + clk_info->compressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].ddr_ib_bw = + clk_info->compressed_bw / device_share_ratio; + } else { + int path_index; + + /* + * Remove previous vote of this context from hw mgr first. + * hw_mgr_clk_info has all valid paths, with each path in its + * own index. BW that we wanted to vote now is after removing + * current context's vote from hw mgr consolidated vote + */ + for (i = 0; i < ctx_data->clk_info.num_paths; i++) { + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + /* + * By assuming BPS has Read-All, Write-All + * votes only. + */ + path_index = + ctx_data->clk_info.axi_path[i] + .transac_type - + CAM_AXI_TRANSACTION_READ; + } else { + path_index = + ctx_data->clk_info.axi_path[i] + .path_data_type - + CAM_AXI_PATH_DATA_IPE_START_OFFSET; + } + + if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_WARN(CAM_ICP, + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i] + .path_data_type, + CAM_AXI_PATH_DATA_IPE_START_OFFSET, + CAM_ICP_MAX_PER_PATH_VOTES); + continue; + } + + clk_info->axi_path[path_index].camnoc_bw -= + ctx_data->clk_info.axi_path[i].camnoc_bw; + clk_info->axi_path[path_index].mnoc_ab_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + clk_info->axi_path[path_index].mnoc_ib_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + clk_info->axi_path[path_index].ddr_ab_bw -= + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + clk_info->axi_path[path_index].ddr_ib_bw -= + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + } + + memset(&ctx_data->clk_info.axi_path[0], 0, + CAM_ICP_MAX_PER_PATH_VOTES * + sizeof(struct cam_axi_per_path_bw_vote)); + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + + clk_update.axi_vote.num_paths = clk_info->num_paths; + memcpy(&clk_update.axi_vote.axi_path[0], + &clk_info->axi_path[0], + clk_update.axi_vote.num_paths * + sizeof(struct cam_axi_per_path_bw_vote)); + + if (device_share_ratio > 1) { + for (i = 0; i < clk_update.axi_vote.num_paths; i++) { + clk_update.axi_vote.axi_path[i].camnoc_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].mnoc_ab_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].mnoc_ib_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].ddr_ab_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].ddr_ib_bw /= + device_share_ratio; + } + } + } + + clk_update.axi_vote_valid = true; + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + + /* + * Vote half bandwidth each on both devices. + * Total bw at mnoc - CPAS will take care of adding up. + * camnoc clk calculate is more accurate this way. + */ + if ((ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) + ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + + CAM_DBG(CAM_ICP, "X :ctx_id = %d curr_fc = %u bc = %u", + ctx_data->ctx_id, ctx_data->clk_info.curr_fc, + ctx_data->clk_info.base_clk); + mutex_unlock(&ctx_data->ctx_mutex); + + return 0; +} + +static void cam_icp_ctx_timer_cb(struct timer_list *timer_data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct clk_work_data *task_data; + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + + spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); + return; + } + + task_data = (struct clk_work_data *)task->payload; + task_data->data = timer->parent; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_ctx_timer; + cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); +} + +static void cam_icp_device_timer_cb(struct timer_list *timer_data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct clk_work_data *task_data; + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + + spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); + return; + } + + task_data = (struct clk_work_data *)task->payload; + task_data->data = timer->parent; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_deinit_idle_clk; + cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); +} + +static int cam_icp_clk_info_init(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int i, j; + + for (i = 0; i < ICP_CLK_HW_MAX; i++) { + hw_mgr->clk_info[i].base_clk = ICP_CLK_SVS_HZ; + hw_mgr->clk_info[i].curr_clk = ICP_CLK_SVS_HZ; + hw_mgr->clk_info[i].threshold = ICP_OVER_CLK_THRESHOLD; + hw_mgr->clk_info[i].over_clked = 0; + hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + for (j = 0; j < CAM_ICP_MAX_PER_PATH_VOTES; j++) { + hw_mgr->clk_info[i].axi_path[j].path_data_type = 0; + hw_mgr->clk_info[i].axi_path[j].transac_type = 0; + hw_mgr->clk_info[i].axi_path[j].camnoc_bw = 0; + hw_mgr->clk_info[i].axi_path[j].mnoc_ab_bw = 0; + hw_mgr->clk_info[i].axi_path[j].mnoc_ib_bw = 0; + } + + hw_mgr->clk_info[i].hw_type = i; + hw_mgr->clk_info[i].watch_dog_reset_counter = 0; + } + + hw_mgr->icp_default_clk = ICP_CLK_SVS_HZ; + + return 0; +} + +static int cam_icp_ctx_timer_start(struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + + rc = crm_timer_init(&ctx_data->watch_dog, + 200, ctx_data, &cam_icp_ctx_timer_cb); + if (rc) + CAM_ERR(CAM_ICP, "Failed to start timer"); + + ctx_data->watch_dog_reset_counter = 0; + + CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + return rc; +} + +static int cam_icp_device_timer_start(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + int i; + + for (i = 0; i < ICP_CLK_HW_MAX; i++) { + if (!hw_mgr->clk_info[i].watch_dog) { + rc = crm_timer_init(&hw_mgr->clk_info[i].watch_dog, + ICP_DEVICE_IDLE_TIMEOUT, &hw_mgr->clk_info[i], + &cam_icp_device_timer_cb); + + if (rc) + CAM_ERR(CAM_ICP, "Failed to start timer %d", i); + + hw_mgr->clk_info[i].watch_dog_reset_counter = 0; + } + } + + return rc; +} + +static int cam_icp_ctx_timer_stop(struct cam_icp_hw_ctx_data *ctx_data) +{ + if (ctx_data->watch_dog) { + CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + ctx_data->watch_dog_reset_counter = 0; + crm_timer_exit(&ctx_data->watch_dog); + ctx_data->watch_dog = NULL; + } + + return 0; +} + +static void cam_icp_device_timer_stop(struct cam_icp_hw_mgr *hw_mgr) +{ + if (!hw_mgr->bps_ctxt_cnt && + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog = NULL; + } + + if (!hw_mgr->ipe_ctxt_cnt && + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog = NULL; + } +} + +static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles, + uint64_t budget) +{ + uint64_t base_clk; + uint64_t mul = 1000000000; + + base_clk = (frame_cycles * mul) / budget; + + CAM_DBG(CAM_ICP, "budget = %lld fc = %d ib = %lld base_clk = %lld", + budget, frame_cycles, + (long long)(frame_cycles * mul), base_clk); + + return base_clk; +} + +static bool cam_icp_busy_prev_reqs(struct hfi_frame_process_info *frm_process, + uint64_t req_id) +{ + int i; + int cnt; + + for (i = 0, cnt = 0; i < CAM_FRAME_CMD_MAX; i++) { + if (frm_process->request_id[i]) { + if (frm_process->fw_process_flag[i]) { + CAM_DBG(CAM_ICP, "r id = %lld busy = %d", + frm_process->request_id[i], + frm_process->fw_process_flag[i]); + cnt++; + } + } + } + if (cnt > 1) + return true; + + return false; +} + +static int cam_icp_calc_total_clk(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_clk_info *hw_mgr_clk_info, uint32_t dev_type) +{ + int i; + struct cam_icp_hw_ctx_data *ctx_data; + + hw_mgr_clk_info->base_clk = 0; + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + ctx_data = &hw_mgr->ctx_data[i]; + if (ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED && + ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type) == + ICP_DEV_TYPE_TO_CLK_TYPE(dev_type)) + hw_mgr_clk_info->base_clk += + ctx_data->clk_info.base_clk; + } + + return 0; +} + +static bool cam_icp_update_clk_busy(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + uint32_t base_clk) +{ + uint32_t next_clk_level; + uint32_t actual_clk; + bool rc = false; + + /* 1. if current request frame cycles(fc) are more than previous + * frame fc + * Calculate the new base clock. + * if sum of base clocks are more than next available clk level + * Update clock rate, change curr_clk_rate to sum of base clock + * rates and make over_clked to zero + * else + * Update clock rate to next level, update curr_clk_rate and make + * overclked cnt to zero + * 2. if current fc is less than or equal to previous frame fc + * Still Bump up the clock to next available level + * if it is available, then update clock, make overclk cnt to + * zero. If the clock is already at highest clock rate then + * no need to update the clock + */ + ctx_data->clk_info.base_clk = base_clk; + hw_mgr_clk_info->over_clked = 0; + if (clk_info->frame_cycles > ctx_data->clk_info.curr_fc) { + cam_icp_calc_total_clk(hw_mgr, hw_mgr_clk_info, + ctx_data->icp_dev_acquire_info->dev_type); + actual_clk = cam_icp_get_actual_clk_rate(hw_mgr, + ctx_data, base_clk); + if (hw_mgr_clk_info->base_clk > actual_clk) { + hw_mgr_clk_info->curr_clk = hw_mgr_clk_info->base_clk; + } else { + next_clk_level = cam_icp_get_next_clk_rate(hw_mgr, + ctx_data, hw_mgr_clk_info->curr_clk); + hw_mgr_clk_info->curr_clk = next_clk_level; + } + rc = true; + } else { + next_clk_level = + cam_icp_get_next_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + if (hw_mgr_clk_info->curr_clk < next_clk_level) { + hw_mgr_clk_info->curr_clk = next_clk_level; + rc = true; + } + } + ctx_data->clk_info.curr_fc = clk_info->frame_cycles; + + return rc; +} + +static bool cam_icp_update_clk_overclk_free(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + uint32_t base_clk) +{ + int rc = false; + + /* + * In caseof no pending packets case + * 1. In caseof overclk cnt is less than threshold, increase + * overclk count and no update in the clock rate + * 2. In caseof overclk cnt is greater than or equal to threshold + * then lower clock rate by one level and update hw_mgr current + * clock value. + * a. In case of new clock rate greater than sum of clock + * rates, reset overclk count value to zero if it is + * overclock + * b. if it is less than sum of base clocks then go to next + * level of clock and make overclk count to zero + * c. if it is same as sum of base clock rates update overclock + * cnt to 0 + */ + if (hw_mgr_clk_info->over_clked < hw_mgr_clk_info->threshold) { + hw_mgr_clk_info->over_clked++; + rc = false; + } else { + hw_mgr_clk_info->curr_clk = + cam_icp_get_lower_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) { + if (cam_icp_is_over_clk(hw_mgr, ctx_data, + hw_mgr_clk_info)) + hw_mgr_clk_info->over_clked = 0; + } else if (hw_mgr_clk_info->curr_clk < + hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->curr_clk = + cam_icp_get_next_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + hw_mgr_clk_info->over_clked = 0; + } else if (hw_mgr_clk_info->curr_clk == + hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->over_clked = 0; + } + rc = true; + } + + return rc; +} + +static bool cam_icp_update_clk_free(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + uint32_t base_clk) +{ + int rc = false; + bool over_clocked = false; + + ctx_data->clk_info.curr_fc = clk_info->frame_cycles; + ctx_data->clk_info.base_clk = base_clk; + cam_icp_calc_total_clk(hw_mgr, hw_mgr_clk_info, + ctx_data->icp_dev_acquire_info->dev_type); + + /* + * Current clock is not always sum of base clocks, due to + * clock scales update to next higher or lower levels, it + * equals to one of discrete clock values supported by hardware. + * So even current clock is higher than sum of base clocks, we + * can not consider it is over clocked. if it is greater than + * discrete clock level then only it is considered as over clock. + * 1. Handle over clock case + * 2. If current clock is less than sum of base clocks + * update current clock + * 3. If current clock is same as sum of base clocks no action + */ + + over_clocked = cam_icp_is_over_clk(hw_mgr, ctx_data, + hw_mgr_clk_info); + + if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk && + over_clocked) { + rc = cam_icp_update_clk_overclk_free(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + } else if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->over_clked = 0; + rc = false; + } else if (hw_mgr_clk_info->curr_clk < hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->curr_clk = cam_icp_get_actual_clk_rate(hw_mgr, + ctx_data, hw_mgr_clk_info->base_clk); + rc = true; + } + + return rc; +} + +static bool cam_icp_debug_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) +{ + if (icp_hw_mgr.icp_debug_clk < ICP_CLK_TURBO_HZ && + icp_hw_mgr.icp_debug_clk && + icp_hw_mgr.icp_debug_clk != hw_mgr_clk_info->curr_clk) { + hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_debug_clk; + hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk; + hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_debug_clk; + hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_debug_clk; + CAM_DBG(CAM_ICP, "bc = %d cc = %d", + hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); + return true; + } + + return false; +} + +static bool cam_icp_default_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) +{ + if (icp_hw_mgr.icp_default_clk != hw_mgr_clk_info->curr_clk) { + hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_default_clk; + hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_default_clk; + hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_default_clk; + hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_default_clk; + CAM_DBG(CAM_ICP, "bc = %d cc = %d", + hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); + return true; + } + + return false; +} + +static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_req_internal_v2 *clk_info, + bool busy) +{ + int i, path_index; + bool update_required = true; + + /* + * If current request bandwidth is different from previous frames, then + * recalculate bandwidth of all contexts of same hardware and update + * voting of bandwidth + */ + + for (i = 0; i < clk_info->num_paths; i++) + CAM_DBG(CAM_ICP, "clk_info camnoc = %lld busy = %d", + clk_info->axi_path[i].camnoc_bw, busy); + + if (clk_info->num_paths == ctx_data->clk_info.num_paths) { + update_required = false; + for (i = 0; i < clk_info->num_paths; i++) { + if ((clk_info->axi_path[i].transac_type == + ctx_data->clk_info.axi_path[i].transac_type) && + (clk_info->axi_path[i].path_data_type == + ctx_data->clk_info.axi_path[i].path_data_type) && + (clk_info->axi_path[i].camnoc_bw == + ctx_data->clk_info.axi_path[i].camnoc_bw) && + (clk_info->axi_path[i].mnoc_ab_bw == + ctx_data->clk_info.axi_path[i].mnoc_ab_bw)) { + continue; + } else { + update_required = true; + break; + } + } + } + + if (!update_required) { + CAM_DBG(CAM_ICP, + "Incoming BW hasn't changed, no update required"); + return false; + } + + if (busy) { + for (i = 0; i < clk_info->num_paths; i++) { + if (ctx_data->clk_info.axi_path[i].camnoc_bw > + clk_info->axi_path[i].camnoc_bw) + return false; + } + } + + /* + * Remove previous vote of this context from hw mgr first. + * hw_mgr_clk_info has all valid paths, with each path in its own index + */ + for (i = 0; i < ctx_data->clk_info.num_paths; i++) { + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + /* By assuming BPS has Read-All, Write-All votes only */ + path_index = + ctx_data->clk_info.axi_path[i].transac_type - + CAM_AXI_TRANSACTION_READ; + } else { + path_index = + ctx_data->clk_info.axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IPE_START_OFFSET; + } + + if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_WARN(CAM_ICP, + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i].path_data_type, + CAM_AXI_PATH_DATA_IPE_START_OFFSET, + CAM_ICP_MAX_PER_PATH_VOTES); + continue; + } + + hw_mgr_clk_info->axi_path[path_index].camnoc_bw -= + ctx_data->clk_info.axi_path[i].camnoc_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ib_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ab_bw -= + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ib_bw -= + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + } + + ctx_data->clk_info.num_paths = clk_info->num_paths; + + memcpy(&ctx_data->clk_info.axi_path[0], + &clk_info->axi_path[0], + clk_info->num_paths * sizeof(struct cam_axi_per_path_bw_vote)); + + /* + * Add new vote of this context in hw mgr. + * hw_mgr_clk_info has all paths, with each path in its own index + */ + for (i = 0; i < ctx_data->clk_info.num_paths; i++) { + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + /* By assuming BPS has Read-All, Write-All votes only */ + path_index = + ctx_data->clk_info.axi_path[i].transac_type - + CAM_AXI_TRANSACTION_READ; + } else { + path_index = + ctx_data->clk_info.axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IPE_START_OFFSET; + } + + if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_WARN(CAM_ICP, + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i].path_data_type, + CAM_AXI_PATH_DATA_IPE_START_OFFSET, + CAM_ICP_MAX_PER_PATH_VOTES); + continue; + } + + hw_mgr_clk_info->axi_path[path_index].path_data_type = + ctx_data->clk_info.axi_path[i].path_data_type; + hw_mgr_clk_info->axi_path[path_index].transac_type = + ctx_data->clk_info.axi_path[i].transac_type; + hw_mgr_clk_info->axi_path[path_index].camnoc_bw += + ctx_data->clk_info.axi_path[i].camnoc_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw += + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ib_bw += + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ab_bw += + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ib_bw += + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + + CAM_DBG(CAM_ICP, + "Consolidate Path Vote : Dev[%s] i[%d] path_idx[%d] : [%s %s] [%lld %lld]", + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type), + i, path_index, + cam_cpas_axi_util_trans_type_to_string( + hw_mgr_clk_info->axi_path[path_index].transac_type), + cam_cpas_axi_util_path_type_to_string( + hw_mgr_clk_info->axi_path[path_index].path_data_type), + hw_mgr_clk_info->axi_path[path_index].camnoc_bw, + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw); + } + + if (hw_mgr_clk_info->num_paths < ctx_data->clk_info.num_paths) + hw_mgr_clk_info->num_paths = ctx_data->clk_info.num_paths; + + return true; +} + +static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + bool busy) +{ + int i; + struct cam_icp_hw_ctx_data *ctx; + + /* + * If current request bandwidth is different from previous frames, then + * recalculate bandwidth of all contexts of same hardware and update + * voting of bandwidth + */ + CAM_DBG(CAM_ICP, "ubw ctx = %lld clk_info ubw = %lld busy = %d", + ctx_data->clk_info.uncompressed_bw, + clk_info->uncompressed_bw, busy); + + if ((clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw) && + (ctx_data->clk_info.uncompressed_bw == + hw_mgr_clk_info->uncompressed_bw)) { + CAM_DBG(CAM_ICP, "Update not required bw=%lld", + ctx_data->clk_info.uncompressed_bw); + return false; + } + + if (busy && + (ctx_data->clk_info.uncompressed_bw > + clk_info->uncompressed_bw)) { + CAM_DBG(CAM_ICP, "Busy, Update not req existing=%lld, new=%lld", + ctx_data->clk_info.uncompressed_bw, + clk_info->uncompressed_bw); + return false; + } + + ctx_data->clk_info.uncompressed_bw = clk_info->uncompressed_bw; + ctx_data->clk_info.compressed_bw = clk_info->compressed_bw; + hw_mgr_clk_info->uncompressed_bw = 0; + hw_mgr_clk_info->compressed_bw = 0; + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + ctx = &hw_mgr->ctx_data[i]; + if (ctx->state == CAM_ICP_CTX_STATE_ACQUIRED && + ICP_DEV_TYPE_TO_CLK_TYPE( + ctx->icp_dev_acquire_info->dev_type) == + ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type)) { + hw_mgr_clk_info->uncompressed_bw += + ctx->clk_info.uncompressed_bw; + hw_mgr_clk_info->compressed_bw += + ctx->clk_info.compressed_bw; + CAM_DBG(CAM_ICP, + "Current context=[%lld %lld] Total=[%lld %lld]", + ctx->clk_info.uncompressed_bw, + ctx->clk_info.compressed_bw, + hw_mgr_clk_info->uncompressed_bw, + hw_mgr_clk_info->compressed_bw); + } + } + + return true; +} + +static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int idx) +{ + bool busy, rc = false; + uint32_t base_clk; + struct cam_icp_clk_bw_request *clk_info; + struct hfi_frame_process_info *frame_info; + uint64_t req_id; + struct cam_icp_clk_info *hw_mgr_clk_info; + + cam_icp_ctx_timer_reset(ctx_data); + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_BPS); + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + CAM_DBG(CAM_ICP, "Reset bps timer"); + } else { + cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_IPE); + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + CAM_DBG(CAM_ICP, "Reset ipe timer"); + } + + if (icp_hw_mgr.icp_debug_clk) + return cam_icp_debug_clk_update(hw_mgr_clk_info); + + /* Check is there any pending frames in this context */ + frame_info = &ctx_data->hfi_frame_process; + req_id = frame_info->request_id[idx]; + busy = cam_icp_busy_prev_reqs(frame_info, req_id); + CAM_DBG(CAM_ICP, "busy = %d req_id = %lld", busy, req_id); + + clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; + if (!clk_info->frame_cycles) + return cam_icp_default_clk_update(hw_mgr_clk_info); + + /* Calculate base clk rate */ + base_clk = cam_icp_mgr_calc_base_clk( + clk_info->frame_cycles, clk_info->budget_ns); + ctx_data->clk_info.rt_flag = clk_info->rt_flag; + + if (busy) + rc = cam_icp_update_clk_busy(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + else + rc = cam_icp_update_clk_free(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + + CAM_DBG(CAM_ICP, "bc = %d cc = %d busy = %d overclk = %d uc = %d", + hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk, + busy, hw_mgr_clk_info->over_clked, rc); + + return rc; +} + +static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int idx) +{ + bool busy, bw_updated = false; + int i; + struct cam_icp_clk_bw_request *clk_info; + struct cam_icp_clk_bw_req_internal_v2 *clk_info_v2; + struct cam_icp_clk_info *hw_mgr_clk_info; + struct hfi_frame_process_info *frame_info; + uint64_t req_id; + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + else + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + + frame_info = &ctx_data->hfi_frame_process; + req_id = frame_info->request_id[idx]; + busy = cam_icp_busy_prev_reqs(frame_info, req_id); + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { + clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; + + CAM_DBG(CAM_ICP, + "Ctx[%pK][%d] Req[%lld] Current camno=%lld, mnoc=%lld", + ctx_data, ctx_data->ctx_id, req_id, + hw_mgr_clk_info->uncompressed_bw, + hw_mgr_clk_info->compressed_bw); + + bw_updated = cam_icp_update_bw(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, busy); + } else if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V2) { + clk_info_v2 = &ctx_data->hfi_frame_process.clk_info_v2[idx]; + + bw_updated = cam_icp_update_bw_v2(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info_v2, busy); + + for (i = 0; i < hw_mgr_clk_info->num_paths; i++) { + CAM_DBG(CAM_ICP, + "Final path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", + cam_cpas_axi_util_path_type_to_string( + hw_mgr_clk_info->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + hw_mgr_clk_info->axi_path[i].transac_type), + hw_mgr_clk_info->axi_path[i].camnoc_bw, + hw_mgr_clk_info->axi_path[i].mnoc_ab_bw, + hw_mgr_clk_info->axi_path[i].mnoc_ib_bw, + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type)); + } + } else { + CAM_ERR(CAM_ICP, "Invalid bw config version: %d", + ctx_data->bw_config_version); + return false; + } + + return bw_updated; +} + +static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + uint32_t id; + uint32_t curr_clk_rate; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *dev_intf = NULL; + struct cam_a5_clk_update_cmd clk_upd_cmd; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + dev_intf = bps_dev_intf; + curr_clk_rate = hw_mgr->clk_info[ICP_CLK_HW_BPS].curr_clk; + id = CAM_ICP_BPS_CMD_UPDATE_CLK; + } else { + dev_intf = ipe0_dev_intf; + curr_clk_rate = hw_mgr->clk_info[ICP_CLK_HW_IPE].curr_clk; + id = CAM_ICP_IPE_CMD_UPDATE_CLK; + } + + CAM_DBG(CAM_PERF, "clk_rate %u for dev_type %d", curr_clk_rate, + ctx_data->icp_dev_acquire_info->dev_type); + clk_upd_cmd.curr_clk_rate = curr_clk_rate; + clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; + + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd)); + + if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS) + if (ipe1_dev_intf) + ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, id, + &clk_upd_cmd, + sizeof(struct cam_a5_clk_update_cmd)); + + return 0; +} + +static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + uint32_t id; + int i = 0; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *dev_intf = NULL; + struct cam_icp_clk_info *clk_info; + struct cam_icp_cpas_vote clk_update = {{0}, {0}, 0, 0}; + int device_share_ratio = 1; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + dev_intf = bps_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + id = CAM_ICP_BPS_CMD_VOTE_CPAS; + } else { + dev_intf = ipe0_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + id = CAM_ICP_IPE_CMD_VOTE_CPAS; + } + + /* + * Since there are 2 devices, we assume the load is evenly shared + * between HWs and corresponding AXI paths. So divide total bw by half + * to vote on each device + */ + if ((ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) + device_share_ratio = 2; + + clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC; + clk_update.ahb_vote.vote.freq = 0; + clk_update.ahb_vote_valid = false; + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { + clk_update.axi_vote.num_paths = 1; + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_BPS_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_BPS_DEFAULT_AXI_TRANSAC; + } else { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_IPE_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_IPE_DEFAULT_AXI_TRANSAC; + } + clk_update.axi_vote.axi_path[0].camnoc_bw = + clk_info->uncompressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].mnoc_ab_bw = + clk_info->compressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].mnoc_ib_bw = + clk_info->compressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].ddr_ab_bw = + clk_info->compressed_bw / device_share_ratio; + clk_update.axi_vote.axi_path[0].ddr_ib_bw = + clk_info->compressed_bw / device_share_ratio; + } else { + clk_update.axi_vote.num_paths = clk_info->num_paths; + memcpy(&clk_update.axi_vote.axi_path[0], + &clk_info->axi_path[0], + clk_update.axi_vote.num_paths * + sizeof(struct cam_axi_per_path_bw_vote)); + + if (device_share_ratio > 1) { + for (i = 0; i < clk_update.axi_vote.num_paths; i++) { + clk_update.axi_vote.axi_path[i].camnoc_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].mnoc_ab_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].mnoc_ib_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].ddr_ab_bw /= + device_share_ratio; + clk_update.axi_vote.axi_path[i].ddr_ib_bw /= + device_share_ratio; + } + } + } + + clk_update.axi_vote_valid = true; + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + + /* + * Vote half bandwidth each on both devices. + * Total bw at mnoc - CPAS will take care of adding up. + * camnoc clk calculate is more accurate this way. + */ + if ((ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) + ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + + return 0; +} + +static int cam_icp_mgr_ipe_bps_clk_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int idx) +{ + int rc = 0; + + if (cam_icp_check_clk_update(hw_mgr, ctx_data, idx)) + rc = cam_icp_update_clk_rate(hw_mgr, ctx_data); + + if (cam_icp_check_bw_update(hw_mgr, ctx_data, idx)) + rc |= cam_icp_update_cpas_vote(hw_mgr, ctx_data); + + return rc; +} + +static int cam_icp_mgr_ipe_bps_resume(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + uint32_t core_info_mask = 0; + int rc = 0; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + if (hw_mgr->bps_ctxt_cnt++) + goto end; + if (!hw_mgr->bps_clk_state) { + bps_dev_intf->hw_ops.init( + bps_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = true; + } + if (icp_hw_mgr.ipe_bps_pc_flag) { + bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0); + } + core_info_mask = ICP_PWR_CLP_BPS; + } else { + if (hw_mgr->ipe_ctxt_cnt++) + goto end; + if (!hw_mgr->ipe_clk_state) + ipe0_dev_intf->hw_ops.init( + ipe0_dev_intf->hw_priv, NULL, 0); + if (icp_hw_mgr.ipe_bps_pc_flag) { + ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0); + } + + if ((icp_hw_mgr.ipe1_enable) && + (ipe1_dev_intf) && + (!hw_mgr->ipe_clk_state)) { + ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv, + NULL, 0); + + if (icp_hw_mgr.ipe_bps_pc_flag) { + ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_RESUME, + NULL, 0); + } + } + hw_mgr->ipe_clk_state = true; + + if ((icp_hw_mgr.ipe1_enable) && + (ipe1_dev_intf)) + core_info_mask = (ICP_PWR_CLP_IPE0 | + ICP_PWR_CLP_IPE1); + else + core_info_mask = ICP_PWR_CLP_IPE0; + } + + CAM_DBG(CAM_ICP, "core_info %X", core_info_mask); + if (icp_hw_mgr.ipe_bps_pc_flag) + rc = hfi_enable_ipe_bps_pc(true, core_info_mask); + else + rc = hfi_enable_ipe_bps_pc(false, core_info_mask); +end: + return rc; +} + +static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int dev_type) +{ + int rc = 0, dev; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return -EINVAL; + } + + if (!ctx_data) + dev = dev_type; + else + dev = ctx_data->icp_dev_acquire_info->dev_type; + + if (dev == CAM_ICP_RES_TYPE_BPS) { + CAM_DBG(CAM_ICP, "bps ctx cnt %d", hw_mgr->bps_ctxt_cnt); + if (ctx_data) + --hw_mgr->bps_ctxt_cnt; + + if (hw_mgr->bps_ctxt_cnt) + goto end; + + if (icp_hw_mgr.ipe_bps_pc_flag && + !atomic_read(&hw_mgr->recovery)) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + NULL, 0); + } + + if (hw_mgr->bps_clk_state) { + bps_dev_intf->hw_ops.deinit + (bps_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = false; + } + } else { + CAM_DBG(CAM_ICP, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt); + if (ctx_data) + --hw_mgr->ipe_ctxt_cnt; + + if (hw_mgr->ipe_ctxt_cnt) + goto end; + + if (icp_hw_mgr.ipe_bps_pc_flag && + !atomic_read(&hw_mgr->recovery)) { + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); + } + + if (hw_mgr->ipe_clk_state) + ipe0_dev_intf->hw_ops.deinit( + ipe0_dev_intf->hw_priv, NULL, 0); + + if (ipe1_dev_intf) { + if (icp_hw_mgr.ipe_bps_pc_flag && + !atomic_read(&hw_mgr->recovery)) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + NULL, 0); + } + + if (hw_mgr->ipe_clk_state) + ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv, + NULL, 0); + } + + hw_mgr->ipe_clk_state = false; + } + +end: + return rc; +} + +static int cam_icp_mgr_ipe_bps_get_gdsc_control( + struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong"); + return -EINVAL; + } + + if (icp_hw_mgr.ipe_bps_pc_flag) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + NULL, 0); + + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + NULL, 0); + } + } + + return rc; +} + +static int cam_icp_set_dbg_default_clk(void *data, u64 val) +{ + icp_hw_mgr.icp_debug_clk = val; + return 0; +} + +static int cam_icp_get_dbg_default_clk(void *data, u64 *val) +{ + *val = icp_hw_mgr.icp_debug_clk; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_default_clk, + cam_icp_get_dbg_default_clk, + cam_icp_set_dbg_default_clk, "%16llu"); + +static int cam_icp_set_a5_dbg_lvl(void *data, u64 val) +{ + icp_hw_mgr.a5_dbg_lvl = val; + return 0; +} + +static int cam_icp_get_a5_dbg_lvl(void *data, u64 *val) +{ + *val = icp_hw_mgr.a5_dbg_lvl; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_fs, cam_icp_get_a5_dbg_lvl, + cam_icp_set_a5_dbg_lvl, "%08llu"); + +static int cam_icp_set_a5_dbg_type(void *data, u64 val) +{ + if (val <= NUM_HFI_DEBUG_MODE) + icp_hw_mgr.a5_debug_type = val; + return 0; +} + +static int cam_icp_get_a5_dbg_type(void *data, u64 *val) +{ + *val = icp_hw_mgr.a5_debug_type; + return 0; +} + + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_type_fs, cam_icp_get_a5_dbg_type, + cam_icp_set_a5_dbg_type, "%08llu"); + +static int cam_icp_set_a5_fw_dump_lvl(void *data, u64 val) +{ + if (val < NUM_HFI_DUMP_LVL) + icp_hw_mgr.a5_fw_dump_lvl = val; + return 0; +} + +static int cam_icp_get_a5_fw_dump_lvl(void *data, u64 *val) +{ + *val = icp_hw_mgr.a5_fw_dump_lvl; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_fw_dump, cam_icp_get_a5_fw_dump_lvl, + cam_icp_set_a5_fw_dump_lvl, "%08llu"); + +static int cam_icp_hw_mgr_create_debugfs_entry(void) +{ + int rc = 0; + + icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL); + if (!icp_hw_mgr.dentry) + return -ENOMEM; + + if (!debugfs_create_bool("icp_pc", + 0644, + icp_hw_mgr.dentry, + &icp_hw_mgr.icp_pc_flag)) { + CAM_ERR(CAM_ICP, "failed to create icp_pc entry"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_bool("ipe_bps_pc", + 0644, + icp_hw_mgr.dentry, + &icp_hw_mgr.ipe_bps_pc_flag)) { + CAM_ERR(CAM_ICP, "failed to create ipe_bps_pc entry"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("icp_debug_clk", + 0644, + icp_hw_mgr.dentry, NULL, + &cam_icp_debug_default_clk)) { + CAM_ERR(CAM_ICP, "failed to create icp_debug_clk entry"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_bool("a5_jtag_debug", + 0644, + icp_hw_mgr.dentry, + &icp_hw_mgr.a5_jtag_debug)) { + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("a5_debug_type", + 0644, + icp_hw_mgr.dentry, + NULL, &cam_icp_debug_type_fs)) { + CAM_ERR(CAM_ICP, "failed to create a5_debug_type"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("a5_debug_lvl", + 0644, + icp_hw_mgr.dentry, + NULL, &cam_icp_debug_fs)) { + CAM_ERR(CAM_ICP, "failed to create a5_dbg_lvl"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("a5_fw_dump_lvl", + 0644, + icp_hw_mgr.dentry, + NULL, &cam_icp_debug_fw_dump)) { + CAM_ERR(CAM_ICP, "failed to create a5_fw_dump_lvl"); + rc = -ENOMEM; + goto err; + } + + return rc; +err: + debugfs_remove_recursive(icp_hw_mgr.dentry); + icp_hw_mgr.dentry = NULL; + return rc; +} + +static int cam_icp_mgr_process_cmd(void *priv, void *data) +{ + int rc; + struct hfi_cmd_work_data *task_data = NULL; + struct cam_icp_hw_mgr *hw_mgr; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid params%pK %pK", data, priv); + return -EINVAL; + } + + hw_mgr = priv; + task_data = (struct hfi_cmd_work_data *)data; + + rc = hfi_write_cmd(task_data->data); + + return rc; +} + +static int cam_icp_mgr_cleanup_ctx(struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + struct hfi_frame_process_info *hfi_frame_process; + struct cam_hw_done_event_data buf_data; + + hfi_frame_process = &ctx_data->hfi_frame_process; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) { + if (!hfi_frame_process->request_id[i]) + continue; + buf_data.request_id = hfi_frame_process->request_id[i]; + ctx_data->ctxt_event_cb(ctx_data->context_priv, + false, &buf_data); + hfi_frame_process->request_id[i] = 0; + if (ctx_data->hfi_frame_process.in_resource[i] > 0) { + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_resource[i]); + cam_sync_destroy( + ctx_data->hfi_frame_process.in_resource[i]); + ctx_data->hfi_frame_process.in_resource[i] = 0; + } + hfi_frame_process->fw_process_flag[i] = false; + clear_bit(i, ctx_data->hfi_frame_process.bitmap); + } + + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) { + if (!hfi_frame_process->in_free_resource[i]) + continue; + + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_free_resource[i]); + cam_sync_destroy( + ctx_data->hfi_frame_process.in_free_resource[i]); + ctx_data->hfi_frame_process.in_free_resource[i] = 0; + } + + return 0; +} + +static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) +{ + int i; + uint32_t idx; + uint64_t request_id; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct hfi_frame_process_info *hfi_frame_process; + struct cam_hw_done_event_data buf_data; + uint32_t clk_type; + + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + request_id = ioconfig_ack->user_data2; + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Invalid Context req %llu", request_id); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + cam_icp_ctx_timer_reset(ctx_data); + if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) { + CAM_DBG(CAM_ICP, "ctx %u is in %d state", + ctx_data->ctx_id, ctx_data->state); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + CAM_DBG(CAM_REQ, + "ctx_id : %u, request_id :%lld dev_type: %d", + ctx_data->ctx_id, request_id, + ctx_data->icp_dev_acquire_info->dev_type); + + clk_type = ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type); + cam_icp_device_timer_reset(&icp_hw_mgr, clk_type); + + hfi_frame_process = &ctx_data->hfi_frame_process; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) + if (hfi_frame_process->request_id[i] == request_id) + break; + + if (i >= CAM_FRAME_CMD_MAX) { + CAM_ERR(CAM_ICP, "pkt not found in ctx data for req_id =%lld", + request_id); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + idx = i; + + if (flag == ICP_FRAME_PROCESS_FAILURE) + CAM_ERR(CAM_ICP, "Done with error: ctx_id %d req %llu dev %d", + ctx_data->ctx_id, request_id, + ctx_data->icp_dev_acquire_info->dev_type); + + buf_data.request_id = hfi_frame_process->request_id[idx]; + ctx_data->ctxt_event_cb(ctx_data->context_priv, flag, &buf_data); + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_resource[idx]); + cam_sync_destroy(ctx_data->hfi_frame_process.in_resource[idx]); + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + hfi_frame_process->fw_process_flag[idx] = false; + mutex_unlock(&ctx_data->ctx_mutex); + + return 0; +} + +static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) +{ + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct hfi_msg_frame_process_done *frame_done; + + if (!msg_ptr) { + CAM_ERR(CAM_ICP, "msg ptr is NULL"); + return -EINVAL; + } + + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) { + CAM_ERR(CAM_ICP, "failed with error : %u", + ioconfig_ack->err_type); + cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_FAILURE); + return -EIO; + } + + frame_done = + (struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data; + if (!frame_done) { + cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_FAILURE); + return -EINVAL; + } + + if (frame_done->result) + return cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_FAILURE); + else + return cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_SUCCESS); +} + +static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr) +{ + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct hfi_msg_ipe_config *ipe_config_ack = NULL; + struct hfi_msg_bps_common *bps_config_ack = NULL; + + if (!msg_ptr) { + CAM_ERR(CAM_ICP, "msg ptr is NULL"); + return -EINVAL; + } + + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + + if (ioconfig_ack->opcode == HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO) { + ipe_config_ack = + (struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data); + if (ipe_config_ack->rc) { + CAM_ERR(CAM_ICP, "rc = %d err = %u", + ipe_config_ack->rc, ioconfig_ack->err_type); + return -EIO; + } + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "wrong ctx data from IPE response"); + return -EINVAL; + } + ctx_data->scratch_mem_size = ipe_config_ack->scratch_mem_size; + } else { + bps_config_ack = + (struct hfi_msg_bps_common *)(ioconfig_ack->msg_data); + if (bps_config_ack->rc) { + CAM_ERR(CAM_ICP, "rc : %u, opcode :%u", + bps_config_ack->rc, ioconfig_ack->opcode); + return -EIO; + } + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "wrong ctx data from BPS response"); + return -EINVAL; + } + } + complete(&ctx_data->wait_complete); + + return 0; +} + +static int cam_icp_mgr_process_msg_create_handle(uint32_t *msg_ptr) +{ + struct hfi_msg_create_handle_ack *create_handle_ack = NULL; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + int rc = 0; + + create_handle_ack = (struct hfi_msg_create_handle_ack *)msg_ptr; + if (!create_handle_ack) { + CAM_ERR(CAM_ICP, "Invalid create_handle_ack"); + return -EINVAL; + } + + ctx_data = + (struct cam_icp_hw_ctx_data *)(uintptr_t) + create_handle_ack->user_data1; + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Invalid ctx_data"); + return -EINVAL; + } + + if (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE) { + ctx_data->fw_handle = create_handle_ack->fw_handle; + CAM_DBG(CAM_ICP, "fw_handle = %x", ctx_data->fw_handle); + } else { + CAM_WARN(CAM_ICP, + "This ctx is no longer in use current state: %d", + ctx_data->state); + ctx_data->fw_handle = 0; + rc = -EPERM; + } + complete(&ctx_data->wait_complete); + return rc; +} + +static int cam_icp_mgr_process_msg_ping_ack(uint32_t *msg_ptr) +{ + struct hfi_msg_ping_ack *ping_ack = NULL; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + + ping_ack = (struct hfi_msg_ping_ack *)msg_ptr; + if (!ping_ack) { + CAM_ERR(CAM_ICP, "Empty ping ack message"); + return -EINVAL; + } + + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ping_ack->user_data); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Invalid ctx_data"); + return -EINVAL; + } + + if (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE) + complete(&ctx_data->wait_complete); + + return 0; +} + +static int cam_icp_mgr_process_indirect_ack_msg(uint32_t *msg_ptr) +{ + int rc; + + if (!msg_ptr) { + CAM_ERR(CAM_ICP, "msg ptr is NULL"); + return -EINVAL; + } + + switch (msg_ptr[ICP_PACKET_OPCODE]) { + case HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO: + case HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO: + CAM_DBG(CAM_ICP, "received IPE/BPS_CONFIG_IO:"); + rc = cam_icp_mgr_process_msg_config_io(msg_ptr); + if (rc) + return rc; + break; + + case HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS: + case HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS: + rc = cam_icp_mgr_process_msg_frame_process(msg_ptr); + if (rc) + return rc; + break; + default: + CAM_ERR(CAM_ICP, "Invalid opcode : %u", + msg_ptr[ICP_PACKET_OPCODE]); + rc = -EINVAL; + break; + } + + return rc; +} + +static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) +{ + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + int rc = 0; + + a5_dev_intf = icp_hw_mgr.a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + switch (msg_ptr[ICP_PACKET_OPCODE]) { + case HFI_IPEBPS_CMD_OPCODE_IPE_ABORT: + case HFI_IPEBPS_CMD_OPCODE_BPS_ABORT: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) + complete(&ctx_data->wait_complete); + CAM_DBG(CAM_ICP, "received IPE/BPS/ ABORT: ctx_state =%d", + ctx_data->state); + break; + case HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY: + case HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if ((ctx_data->state == CAM_ICP_CTX_STATE_RELEASE) || + (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE)) { + complete(&ctx_data->wait_complete); + } + CAM_DBG(CAM_ICP, "received IPE/BPS/ DESTROY: ctx_state =%d", + ctx_data->state); + break; + case HFI_IPEBPS_CMD_OPCODE_MEM_MAP: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = + (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; + if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) + complete(&ctx_data->wait_complete); + CAM_DBG(CAM_ICP, + "received IPE/BPS MAP ACK:ctx_state =%d err_status =%u", + ctx_data->state, ioconfig_ack->err_type); + break; + case HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = + (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; + if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) + complete(&ctx_data->wait_complete); + CAM_DBG(CAM_ICP, + "received IPE/BPS UNMAP ACK:ctx_state =%d err_status =%u", + ctx_data->state, ioconfig_ack->err_type); + break; + default: + CAM_ERR(CAM_ICP, "Invalid opcode : %u", + msg_ptr[ICP_PACKET_OPCODE]); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_icp_ipebps_reset(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf; + struct cam_hw_intf *ipe1_dev_intf; + struct cam_hw_intf *bps_dev_intf; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if (hw_mgr->bps_ctxt_cnt) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "bps reset failed"); + } + + if (hw_mgr->ipe_ctxt_cnt) { + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe0 reset failed"); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe1 reset failed"); + } + } + + return 0; +} + +static int cam_icp_mgr_trigger_recovery(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct sfr_buf *sfr_buffer = NULL; + + CAM_DBG(CAM_ICP, "Enter"); + + if (atomic_read(&hw_mgr->recovery)) { + CAM_ERR(CAM_ICP, "Recovery is set"); + return rc; + } + + sfr_buffer = (struct sfr_buf *)icp_hw_mgr.hfi_mem.sfr_buf.kva; + CAM_WARN(CAM_ICP, "SFR:%s", sfr_buffer->msg); + + cam_icp_mgr_ipe_bps_get_gdsc_control(hw_mgr); + cam_icp_ipebps_reset(hw_mgr); + + atomic_set(&hw_mgr->recovery, 1); + CAM_DBG(CAM_ICP, "Done"); + return rc; +} +static int cam_icp_mgr_process_fatal_error( + struct cam_icp_hw_mgr *hw_mgr, uint32_t *msg_ptr) +{ + struct hfi_msg_event_notify *event_notify; + int rc = 0; + + CAM_DBG(CAM_ICP, "Enter"); + + event_notify = (struct hfi_msg_event_notify *)msg_ptr; + if (!event_notify) { + CAM_ERR(CAM_ICP, "Empty event message"); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "evt_id: %u evt_data1: %u evt_data2: %u", + event_notify->event_id, + event_notify->event_data1, + event_notify->event_data2); + + if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { + CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + } + + return rc; +} + +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl) +{ + uint32_t *msg_ptr = NULL, *pkt_ptr = NULL; + struct hfi_msg_debug *dbg_msg; + uint32_t read_len, size_processed = 0; + uint64_t timestamp = 0; + char *dbg_buf; + int rc = 0; + + rc = hfi_read_message(icp_hw_mgr.dbg_buf, Q_DBG, &read_len); + if (rc) + return; + + msg_ptr = (uint32_t *)icp_hw_mgr.dbg_buf; + while (true) { + pkt_ptr = msg_ptr; + if (pkt_ptr[ICP_PACKET_TYPE] == HFI_MSG_SYS_DEBUG) { + dbg_msg = (struct hfi_msg_debug *)pkt_ptr; + dbg_buf = (char *)&dbg_msg->msg_data; + timestamp = ((((uint64_t)(dbg_msg->timestamp_hi) << 32) + | dbg_msg->timestamp_lo) >> 16); + trace_cam_icp_fw_dbg(dbg_buf, timestamp/2); + if (!debug_lvl) + CAM_INFO(CAM_ICP, "FW_DBG:%s", dbg_buf); + } + size_processed += (pkt_ptr[ICP_PACKET_SIZE] >> + BYTE_WORD_SHIFT); + if (size_processed >= read_len) + return; + msg_ptr += (pkt_ptr[ICP_PACKET_SIZE] >> + BYTE_WORD_SHIFT); + pkt_ptr = NULL; + dbg_msg = NULL; + dbg_buf = NULL; + } +} + +static int cam_icp_process_msg_pkt_type( + struct cam_icp_hw_mgr *hw_mgr, + uint32_t *msg_ptr, + uint32_t *msg_processed_len) +{ + int rc = 0; + int size_processed = 0; + + switch (msg_ptr[ICP_PACKET_TYPE]) { + case HFI_MSG_SYS_INIT_DONE: + CAM_DBG(CAM_ICP, "received SYS_INIT_DONE"); + complete(&hw_mgr->a5_complete); + size_processed = ( + (struct hfi_msg_init_done *)msg_ptr)->size; + break; + + case HFI_MSG_SYS_PC_PREP_DONE: + CAM_DBG(CAM_ICP, "HFI_MSG_SYS_PC_PREP_DONE is received\n"); + complete(&hw_mgr->a5_complete); + size_processed = sizeof(struct hfi_msg_pc_prep_done); + break; + + case HFI_MSG_SYS_PING_ACK: + CAM_DBG(CAM_ICP, "received SYS_PING_ACK"); + rc = cam_icp_mgr_process_msg_ping_ack(msg_ptr); + size_processed = sizeof(struct hfi_msg_ping_ack); + break; + + case HFI_MSG_IPEBPS_CREATE_HANDLE_ACK: + CAM_DBG(CAM_ICP, "received IPEBPS_CREATE_HANDLE_ACK"); + rc = cam_icp_mgr_process_msg_create_handle(msg_ptr); + size_processed = sizeof(struct hfi_msg_create_handle_ack); + break; + + case HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK: + CAM_DBG(CAM_ICP, "received ASYNC_INDIRECT_ACK"); + rc = cam_icp_mgr_process_indirect_ack_msg(msg_ptr); + size_processed = ( + (struct hfi_msg_ipebps_async_ack *)msg_ptr)->size; + break; + + case HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK: + CAM_DBG(CAM_ICP, "received ASYNC_DIRECT_ACK"); + rc = cam_icp_mgr_process_direct_ack_msg(msg_ptr); + size_processed = ( + (struct hfi_msg_ipebps_async_ack *)msg_ptr)->size; + break; + + case HFI_MSG_EVENT_NOTIFY: + CAM_DBG(CAM_ICP, "received EVENT_NOTIFY"); + size_processed = ( + (struct hfi_msg_event_notify *)msg_ptr)->size; + rc = cam_icp_mgr_process_fatal_error(hw_mgr, msg_ptr); + if (rc) + CAM_ERR(CAM_ICP, "failed in processing evt notify"); + + break; + + default: + CAM_ERR(CAM_ICP, "invalid msg : %u", + msg_ptr[ICP_PACKET_TYPE]); + rc = -EINVAL; + break; + } + + *msg_processed_len = size_processed; + return rc; +} + +static int32_t cam_icp_mgr_process_msg(void *priv, void *data) +{ + uint32_t read_len, msg_processed_len; + uint32_t *msg_ptr = NULL; + struct hfi_msg_work_data *task_data; + struct cam_icp_hw_mgr *hw_mgr; + int rc = 0; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid data"); + return -EINVAL; + } + + task_data = data; + hw_mgr = priv; + + rc = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG, &read_len); + if (rc) { + CAM_DBG(CAM_ICP, "Unable to read msg q rc %d", rc); + } else { + read_len = read_len << BYTE_WORD_SHIFT; + msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf; + while (true) { + cam_icp_process_msg_pkt_type(hw_mgr, msg_ptr, + &msg_processed_len); + + if (!msg_processed_len) { + CAM_ERR(CAM_ICP, "Failed to read"); + rc = -EINVAL; + break; + } + + read_len -= msg_processed_len; + if (read_len > 0) { + msg_ptr += (msg_processed_len >> + BYTE_WORD_SHIFT); + msg_processed_len = 0; + } else { + break; + } + } + } + + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + + if ((task_data->irq_status & A5_WDT_0) || + (task_data->irq_status & A5_WDT_1)) { + CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5"); + + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + } + + return rc; +} + +int32_t cam_icp_hw_mgr_cb(uint32_t irq_status, void *data) +{ + int32_t rc = 0; + unsigned long flags; + struct cam_icp_hw_mgr *hw_mgr = data; + struct crm_workq_task *task; + struct hfi_msg_work_data *task_data; + + if (!data) { + CAM_ERR(CAM_ICP, "irq cb data is NULL"); + return rc; + } + + spin_lock_irqsave(&hw_mgr->hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + return -ENOMEM; + } + + task_data = (struct hfi_msg_work_data *)task->payload; + task_data->data = hw_mgr; + task_data->irq_status = irq_status; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_mgr_process_msg; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + + return rc; +} + +static void cam_icp_free_hfi_mem(void) +{ + int rc; + + cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl); + rc = cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap); + if (rc) + CAM_ERR(CAM_ICP, "failed to unreserve sec heap"); + + cam_smmu_dealloc_qdss(icp_hw_mgr.iommu_hdl); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); +} + +static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + struct cam_smmu_region_info secheap_info; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + + rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl, + CAM_SMMU_REGION_SECHEAP, + &secheap_info); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get secheap memory info"); + return rc; + } + + alloc.size = secheap_info.iova_len; + alloc.align = 0; + alloc.flags = 0; + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_reserve_memory_region(&alloc, + CAM_SMMU_REGION_SECHEAP, + &out); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to reserve secheap memory"); + return rc; + } + + *secheap = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + +static int cam_icp_alloc_sfr_mem(struct cam_mem_mgr_memory_desc *sfr) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + alloc.size = SZ_8K; + alloc.align = 0; + alloc.flags = CAM_MEM_FLAG_HW_READ_WRITE | + CAM_MEM_FLAG_HW_SHARED_ACCESS; + + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_request_mem(&alloc, &out); + if (rc) + return rc; + + *sfr = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + +static int cam_icp_alloc_shared_mem(struct cam_mem_mgr_memory_desc *qtbl) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + alloc.size = SZ_1M; + alloc.align = 0; + alloc.flags = CAM_MEM_FLAG_HW_READ_WRITE | + CAM_MEM_FLAG_HW_SHARED_ACCESS; + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_request_mem(&alloc, &out); + if (rc) + return rc; + + *qtbl = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + +static int cam_icp_allocate_fw_mem(void) +{ + int rc; + uintptr_t kvaddr; + size_t len; + dma_addr_t iova; + + rc = cam_smmu_alloc_firmware(icp_hw_mgr.iommu_hdl, + &iova, &kvaddr, &len); + if (rc) + return -ENOMEM; + + icp_hw_mgr.hfi_mem.fw_buf.len = len; + icp_hw_mgr.hfi_mem.fw_buf.kva = kvaddr; + icp_hw_mgr.hfi_mem.fw_buf.iova = iova; + icp_hw_mgr.hfi_mem.fw_buf.smmu_hdl = icp_hw_mgr.iommu_hdl; + + CAM_DBG(CAM_ICP, "kva: %zX, iova: %llx, len: %zu", + kvaddr, iova, len); + + return rc; +} + +static int cam_icp_allocate_qdss_mem(void) +{ + int rc; + size_t len; + dma_addr_t iova; + + rc = cam_smmu_alloc_qdss(icp_hw_mgr.iommu_hdl, + &iova, &len); + if (rc) + return rc; + + icp_hw_mgr.hfi_mem.qdss_buf.len = len; + icp_hw_mgr.hfi_mem.qdss_buf.iova = iova; + icp_hw_mgr.hfi_mem.qdss_buf.smmu_hdl = icp_hw_mgr.iommu_hdl; + + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len); + + return rc; +} + +static int cam_icp_get_io_mem_info(void) +{ + int rc; + size_t len; + dma_addr_t iova; + + rc = cam_smmu_get_io_region_info(icp_hw_mgr.iommu_hdl, + &iova, &len); + if (rc) + return rc; + + icp_hw_mgr.hfi_mem.io_mem.iova_len = len; + icp_hw_mgr.hfi_mem.io_mem.iova_start = iova; + + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len); + + return rc; +} + +static int cam_icp_allocate_hfi_mem(void) +{ + int rc; + + rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl, + CAM_SMMU_REGION_SHARED, + &icp_hw_mgr.hfi_mem.shmem); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get shared memory info"); + return rc; + } + + rc = cam_icp_allocate_fw_mem(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate FW memory"); + return rc; + } + + rc = cam_icp_allocate_qdss_mem(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate qdss memory"); + goto fw_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.qtbl); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate qtbl memory"); + goto qtbl_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.cmd_q); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate cmd q memory"); + goto cmd_q_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.msg_q); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate msg q memory"); + goto msg_q_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.dbg_q); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate dbg q memory"); + goto dbg_q_alloc_failed; + } + + rc = cam_icp_alloc_sfr_mem(&icp_hw_mgr.hfi_mem.sfr_buf); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate sfr buffer"); + goto sfr_buf_alloc_failed; + } + + rc = cam_icp_alloc_secheap_mem(&icp_hw_mgr.hfi_mem.sec_heap); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate sec heap memory"); + goto sec_heap_alloc_failed; + } + + rc = cam_icp_get_io_mem_info(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get I/O region info"); + goto get_io_mem_failed; + } + + return rc; +get_io_mem_failed: + cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap); +sec_heap_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); +sfr_buf_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); +dbg_q_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); +msg_q_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q); +cmd_q_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl); +qtbl_alloc_failed: + cam_smmu_dealloc_qdss(icp_hw_mgr.iommu_hdl); +fw_alloc_failed: + cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl); + return rc; +} + +static int cam_icp_mgr_get_free_ctx(struct cam_icp_hw_mgr *hw_mgr) +{ + int i = 0; + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex); + if (hw_mgr->ctx_data[i].state == CAM_ICP_CTX_STATE_FREE) { + hw_mgr->ctx_data[i].state = CAM_ICP_CTX_STATE_IN_USE; + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + break; + } + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + } + + return i; +} + +static void cam_icp_mgr_put_ctx(struct cam_icp_hw_ctx_data *ctx_data) +{ + ctx_data->state = CAM_ICP_CTX_STATE_FREE; +} + +static int cam_icp_mgr_send_pc_prep(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + unsigned long rem_jiffies; + int timeout = 5000; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n"); + return -EINVAL; + } + + reinit_completion(&hw_mgr->a5_complete); + CAM_DBG(CAM_ICP, "Sending HFI init command"); + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, CAM_ICP_A5_CMD_PC_PREP, NULL, 0); + if (rc) + return rc; + + CAM_DBG(CAM_ICP, "Wait for PC_PREP_DONE Message\n"); + rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "PC_PREP response timed out %d\n", rc); + } + CAM_DBG(CAM_ICP, "Done Waiting for PC_PREP Message\n"); + + return rc; +} + +static int cam_ipe_bps_deint(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return 0; + } + + if (ipe1_dev_intf && hw_mgr->ipe_clk_state) { + ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv, + NULL, 0); + } + + if (hw_mgr->ipe_clk_state) + ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0); + if (hw_mgr->bps_clk_state) + bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0); + + + hw_mgr->bps_clk_state = false; + hw_mgr->ipe_clk_state = false; + + return 0; +} + +static int cam_icp_mgr_hw_close_u(void *hw_priv, void *hw_close_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + int rc = 0; + + CAM_DBG(CAM_ICP, "UMD calls close"); + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + rc = cam_icp_mgr_hw_close(hw_mgr, NULL); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_icp_mgr_hw_close_k(void *hw_priv, void *hw_close_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + + CAM_DBG(CAM_ICP, "KMD calls close"); + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + return cam_icp_mgr_hw_close(hw_mgr, NULL); + +} + +static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + + CAM_DBG(CAM_ICP, "ENTER"); + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + if (!hw_mgr->icp_pc_flag || atomic_read(&hw_mgr->recovery)) { + cam_hfi_disable_cpu( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + rc = cam_icp_mgr_hw_close_k(hw_mgr, NULL); + } else { + CAM_DBG(CAM_PERF, "Sending PC prep ICP PC enabled"); + rc = cam_icp_mgr_send_pc_prep(hw_mgr); + cam_hfi_disable_cpu( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + } + a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); + CAM_DBG(CAM_ICP, "EXIT"); + + return rc; +} + +static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct hfi_mem_info hfi_mem; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva; + hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova; + hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len; + CAM_DBG(CAM_ICP, "qtbl kva = %llX IOVA = %X length = %lld\n", + hfi_mem.qtbl.kva, hfi_mem.qtbl.iova, hfi_mem.qtbl.len); + + hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva; + hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova; + hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len; + CAM_DBG(CAM_ICP, "cmd_q kva = %llX IOVA = %X length = %lld\n", + hfi_mem.cmd_q.kva, hfi_mem.cmd_q.iova, hfi_mem.cmd_q.len); + + hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva; + hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova; + hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len; + CAM_DBG(CAM_ICP, "msg_q kva = %llX IOVA = %X length = %lld\n", + hfi_mem.msg_q.kva, hfi_mem.msg_q.iova, hfi_mem.msg_q.len); + + hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva; + hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; + hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; + CAM_DBG(CAM_ICP, "dbg_q kva = %llX IOVA = %X length = %lld\n", + hfi_mem.dbg_q.kva, hfi_mem.dbg_q.iova, hfi_mem.dbg_q.len); + + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + CAM_DBG(CAM_ICP, "sfr kva = %llX IOVA = %X length = %lld\n", + hfi_mem.sfr_buf.kva, hfi_mem.sfr_buf.iova, + hfi_mem.sfr_buf.len); + + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; + hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; + hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; + + hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start; + hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len; + + hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; + hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + CAM_DBG(CAM_ICP, "IO region IOVA = %X length = %lld", + hfi_mem.io_mem.iova, + hfi_mem.io_mem.len); + + return cam_hfi_resume(&hfi_mem, + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, + hw_mgr->a5_jtag_debug); +} + +static int cam_icp_mgr_abort_handle( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + unsigned long rem_jiffies; + size_t packet_size; + int timeout = 1000; + struct hfi_cmd_ipebps_async *abort_cmd; + + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + sizeof(struct hfi_cmd_abort) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + abort_cmd = kzalloc(packet_size, GFP_KERNEL); + CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size); + if (!abort_cmd) { + rc = -ENOMEM; + return rc; + } + + abort_cmd->size = packet_size; + abort_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT; + else + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_ABORT; + + reinit_completion(&ctx_data->wait_complete); + abort_cmd->num_fw_handles = 1; + abort_cmd->fw_handles[0] = ctx_data->fw_handle; + abort_cmd->user_data1 = PTR_TO_U64(ctx_data); + abort_cmd->user_data2 = (uint64_t)0x0; + + rc = hfi_write_cmd(abort_cmd); + if (rc) { + kfree(abort_cmd); + return rc; + } + CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK", + ctx_data->fw_handle, ctx_data); + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + + kfree(abort_cmd); + return rc; +} + +static int cam_icp_mgr_destroy_handle( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + int timeout = 1000; + unsigned long rem_jiffies; + size_t packet_size; + struct hfi_cmd_ipebps_async *destroy_cmd; + + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + sizeof(struct hfi_cmd_abort_destroy) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + destroy_cmd = kzalloc(packet_size, GFP_KERNEL); + if (!destroy_cmd) { + rc = -ENOMEM; + return rc; + } + + destroy_cmd->size = packet_size; + destroy_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + destroy_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY; + else + destroy_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY; + + reinit_completion(&ctx_data->wait_complete); + destroy_cmd->num_fw_handles = 1; + destroy_cmd->fw_handles[0] = ctx_data->fw_handle; + destroy_cmd->user_data1 = PTR_TO_U64(ctx_data); + destroy_cmd->user_data2 = (uint64_t)0x0; + memcpy(destroy_cmd->payload.direct, &ctx_data->temp_payload, + sizeof(uint64_t)); + + rc = hfi_write_cmd(destroy_cmd); + if (rc) { + kfree(destroy_cmd); + return rc; + } + CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK", + ctx_data->fw_handle, ctx_data); + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timeout: %d for %u", + rc, ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + kfree(destroy_cmd); + return rc; +} + +static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id) +{ + int i = 0; + + if (ctx_id >= CAM_ICP_CTX_MAX) { + CAM_ERR(CAM_ICP, "ctx_id is wrong: %d", ctx_id); + return -EINVAL; + } + + mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + if (hw_mgr->ctx_data[ctx_id].state != + CAM_ICP_CTX_STATE_ACQUIRED) { + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + CAM_DBG(CAM_ICP, + "ctx with id: %d not in right state to release: %d", + ctx_id, hw_mgr->ctx_data[ctx_id].state); + return 0; + } + cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, + &hw_mgr->ctx_data[ctx_id], 0); + hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE; + CAM_DBG(CAM_ICP, "E: ctx_id = %d recovery = %d", + ctx_id, atomic_read(&hw_mgr->recovery)); + cam_icp_mgr_abort_handle(&hw_mgr->ctx_data[ctx_id]); + cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]); + cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]); + + hw_mgr->ctx_data[ctx_id].fw_handle = 0; + hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) + clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); + kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); + hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap = NULL; + cam_icp_hw_mgr_clk_info_update(hw_mgr, &hw_mgr->ctx_data[ctx_id]); + hw_mgr->ctx_data[ctx_id].clk_info.curr_fc = 0; + hw_mgr->ctx_data[ctx_id].clk_info.base_clk = 0; + hw_mgr->ctxt_cnt--; + kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info); + hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL; + hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_FREE; + cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[ctx_id]); + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + + CAM_DBG(CAM_ICP, "X: ctx_id = %d", ctx_id); + return 0; +} + +static void cam_icp_mgr_device_deinit(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + a5_dev_intf = hw_mgr->a5_dev_intf; + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return; + } + + if (ipe1_dev_intf) + ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv, NULL, 0); + ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0); + bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0); + a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = false; + hw_mgr->ipe_clk_state = false; +} + +static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct cam_icp_a5_set_irq_cb irq_cb; + struct cam_icp_a5_set_fw_buf_info fw_buf_info; + int rc = 0; + + CAM_DBG(CAM_ICP, "E"); + if (hw_mgr->fw_download == false) { + CAM_DBG(CAM_ICP, "hw mgr is already closed"); + return 0; + } + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_DBG(CAM_ICP, "a5_dev_intf is NULL"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + fw_buf_info.kva = 0; + fw_buf_info.iova = 0; + fw_buf_info.len = 0; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_SET_FW_BUF, + &fw_buf_info, + sizeof(fw_buf_info)); + if (rc) + CAM_ERR(CAM_ICP, "nullify the fw buf failed"); + cam_hfi_deinit( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + irq_cb.icp_hw_mgr_cb = NULL; + irq_cb.data = NULL; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_ICP, "deregister irq call back failed"); + + cam_icp_free_hfi_mem(); + hw_mgr->fw_download = false; + + CAM_DBG(CAM_ICP, "Exit"); + return rc; +} + +static int cam_icp_mgr_device_init(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + a5_dev_intf = hw_mgr->a5_dev_intf; + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong"); + return -EINVAL; + } + + rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0); + if (rc) + goto a5_dev_init_failed; + + rc = bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0); + if (rc) + goto bps_dev_init_failed; + + rc = ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0); + if (rc) + goto ipe0_dev_init_failed; + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv, + NULL, 0); + if (rc) + goto ipe1_dev_init_failed; + } + + hw_mgr->bps_clk_state = true; + hw_mgr->ipe_clk_state = true; + + return rc; +ipe1_dev_init_failed: + ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0); + hw_mgr->ipe_clk_state = false; +ipe0_dev_init_failed: + bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = false; +bps_dev_init_failed: + a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); +a5_dev_init_failed: + return rc; +} + +static int cam_icp_mgr_fw_download(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct cam_icp_a5_set_irq_cb irq_cb; + struct cam_icp_a5_set_fw_buf_info fw_buf_info; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + irq_cb.icp_hw_mgr_cb = cam_icp_hw_mgr_cb; + irq_cb.data = hw_mgr; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + goto set_irq_failed; + + fw_buf_info.kva = icp_hw_mgr.hfi_mem.fw_buf.kva; + fw_buf_info.iova = icp_hw_mgr.hfi_mem.fw_buf.iova; + fw_buf_info.len = icp_hw_mgr.hfi_mem.fw_buf.len; + + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_SET_FW_BUF, + &fw_buf_info, sizeof(fw_buf_info)); + if (rc) + goto set_irq_failed; + + cam_hfi_enable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_FW_DOWNLOAD, + NULL, 0); + if (rc) + goto fw_download_failed; + + return rc; +fw_download_failed: + cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); +set_irq_failed: + return rc; +} + +static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct hfi_mem_info hfi_mem; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva; + hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova; + hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len; + + hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva; + hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova; + hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len; + + hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva; + hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova; + hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len; + + hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva; + hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; + hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; + + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; + hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; + hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; + + hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start; + hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len; + + hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; + hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + return cam_hfi_init(0, &hfi_mem, + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, + hw_mgr->a5_jtag_debug); +} + +static int cam_icp_mgr_send_fw_init(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + unsigned long rem_jiffies; + int timeout = 5000; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + + reinit_completion(&hw_mgr->a5_complete); + CAM_DBG(CAM_ICP, "Sending HFI init command"); + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_SEND_INIT, + NULL, 0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message"); + + return rc; +} + +static int cam_icp_mgr_hw_open_u(void *hw_mgr_priv, void *download_fw_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + int rc = 0; + + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + rc = cam_icp_mgr_hw_open(hw_mgr, download_fw_args); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_icp_mgr_hw_open_k(void *hw_mgr_priv, void *download_fw_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + return cam_icp_mgr_hw_open(hw_mgr, download_fw_args); +} + +static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *a5_dev_intf = NULL; + bool downloadFromResume = true; + + CAM_DBG(CAM_ICP, "Enter"); + a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0]; + + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5 dev intf is wrong"); + return -EINVAL; + } + + if (hw_mgr->fw_download == false) { + CAM_DBG(CAM_ICP, "Downloading FW"); + rc = cam_icp_mgr_hw_open_k(hw_mgr, &downloadFromResume); + CAM_DBG(CAM_ICP, "FW Download Done Exit"); + return rc; + } + + rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0); + if (rc) + return -EINVAL; + + rc = cam_icp_mgr_hfi_resume(hw_mgr); + if (rc) + goto hfi_resume_failed; + + CAM_DBG(CAM_ICP, "Exit"); + return rc; +hfi_resume_failed: + cam_icp_mgr_icp_power_collapse(hw_mgr); + return rc; +} + +static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + bool icp_pc = false; + int rc = 0; + + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "hw_mgr is NULL"); + return -EINVAL; + } + + if (hw_mgr->fw_download) { + CAM_DBG(CAM_ICP, "FW already downloaded"); + return rc; + } + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + rc = cam_icp_allocate_hfi_mem(); + if (rc) + goto alloc_hfi_mem_failed; + + rc = cam_icp_mgr_device_init(hw_mgr); + if (rc) + goto dev_init_fail; + + rc = cam_icp_mgr_fw_download(hw_mgr); + if (rc) + goto fw_download_failed; + + rc = cam_icp_mgr_hfi_init(hw_mgr); + if (rc) + goto hfi_init_failed; + + rc = cam_icp_mgr_send_fw_init(hw_mgr); + if (rc) + goto fw_init_failed; + + hw_mgr->ctxt_cnt = 0; + hw_mgr->fw_download = true; + atomic_set(&hw_mgr->recovery, 0); + + CAM_INFO(CAM_ICP, "FW download done successfully"); + + rc = cam_ipe_bps_deint(hw_mgr); + if (download_fw_args) + icp_pc = *((bool *)download_fw_args); + + if (download_fw_args && icp_pc == true && hw_mgr->icp_pc_flag) { + rc = cam_ipe_bps_deint(hw_mgr); + CAM_DBG(CAM_ICP, "deinit all clocks"); + } + + if (download_fw_args && icp_pc == true) + return rc; + + rc = cam_ipe_bps_deint(hw_mgr); + rc = cam_icp_mgr_icp_power_collapse(hw_mgr); + CAM_DBG(CAM_ICP, "deinit all clocks at boot up"); + + return rc; + +fw_init_failed: + cam_hfi_deinit( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); +hfi_init_failed: + cam_hfi_disable_cpu( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); +fw_download_failed: + cam_icp_mgr_device_deinit(hw_mgr); +dev_init_fail: + cam_icp_free_hfi_mem(); +alloc_hfi_mem_failed: + return rc; +} + +static int cam_icp_mgr_handle_config_err( + struct cam_hw_config_args *config_args, + struct cam_icp_hw_ctx_data *ctx_data, + int idx) +{ + struct cam_hw_done_event_data buf_data; + + buf_data.request_id = *(uint64_t *)config_args->priv; + ctx_data->ctxt_event_cb(ctx_data->context_priv, false, &buf_data); + + ctx_data->hfi_frame_process.request_id[idx] = 0; + ctx_data->hfi_frame_process.fw_process_flag[idx] = false; + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + + return 0; +} + +static int cam_icp_mgr_enqueue_config(struct cam_icp_hw_mgr *hw_mgr, + struct cam_hw_config_args *config_args) +{ + int rc = 0; + uint64_t request_id = 0; + struct crm_workq_task *task; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async *hfi_cmd; + struct cam_hw_update_entry *hw_update_entries; + struct icp_frame_info *frame_info = NULL; + + frame_info = (struct icp_frame_info *)config_args->priv; + request_id = frame_info->request_id; + hw_update_entries = config_args->hw_update_entries; + CAM_DBG(CAM_ICP, "req_id = %lld %pK", request_id, config_args->priv); + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + return -ENOMEM; + } + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)hw_update_entries->addr; + hfi_cmd = (struct hfi_cmd_ipebps_async *)hw_update_entries->addr; + task_data->request_id = request_id; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + + return rc; +} + +static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, + uint32_t io_buf_addr) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async ioconfig_cmd; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + uint32_t size_in_words; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + reinit_completion(&ctx_data->wait_complete); + + ioconfig_cmd.num_fw_handles = 1; + ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd.payload.indirect = io_buf_addr; + ioconfig_cmd.user_data1 = PTR_TO_U64(ctx_data); + ioconfig_cmd.user_data2 = (uint64_t)0x0; + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&ioconfig_cmd; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + size_in_words = (*(uint32_t *)task_data->data) >> 2; + CAM_DBG(CAM_ICP, "size_in_words %u", size_in_words); + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + + return rc; +} + +static int cam_icp_mgr_send_recfg_io(struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, uint64_t req_id) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ioconfig_cmd; + task_data->request_id = req_id; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + return rc; +} + +static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) +{ + int rc = 0; + int idx; + uint64_t req_id; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_config_args *config_args = config_hw_args; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct icp_frame_info *frame_info = NULL; + + if (!hw_mgr || !config_args) { + CAM_ERR(CAM_ICP, "Invalid arguments %pK %pK", + hw_mgr, config_args); + return -EINVAL; + } + + if (!config_args->num_hw_update_entries) { + CAM_ERR(CAM_ICP, "No hw update enteries are available"); + return -EINVAL; + } + + ctx_data = config_args->ctxt_to_hw_map; + mutex_lock(&hw_mgr->hw_mgr_mutex); + mutex_lock(&ctx_data->ctx_mutex); + if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) { + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_ICP, "ctx id :%u is not in use", + ctx_data->ctx_id); + return -EINVAL; + } + + frame_info = (struct icp_frame_info *)config_args->priv; + req_id = frame_info->request_id; + idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id); + + cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); + ctx_data->hfi_frame_process.fw_process_flag[idx] = true; + + CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, + frame_info->io_config); + + if (frame_info->io_config != 0) { + CAM_INFO(CAM_ICP, "Send recfg io"); + rc = cam_icp_mgr_send_recfg_io(ctx_data, + &frame_info->hfi_cfg_io_cmd, req_id); + if (rc) + CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd"); + } + + rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); + if (rc) + goto config_err; + CAM_DBG(CAM_REQ, + "req_id = %lld on ctx_id %u for dev %d queued to FW", + req_id, ctx_data->ctx_id, + ctx_data->icp_dev_acquire_info->dev_type); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return 0; +config_err: + cam_icp_mgr_handle_config_err(config_args, ctx_data, idx); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_icp_mgr_prepare_frame_process_cmd( + struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *hfi_cmd, + uint64_t request_id, + uint32_t fw_cmd_buf_iova_addr) +{ + hfi_cmd->size = sizeof(struct hfi_cmd_ipebps_async); + hfi_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS; + else + hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS; + hfi_cmd->num_fw_handles = 1; + hfi_cmd->fw_handles[0] = ctx_data->fw_handle; + hfi_cmd->payload.indirect = fw_cmd_buf_iova_addr; + hfi_cmd->user_data1 = PTR_TO_U64(ctx_data); + hfi_cmd->user_data2 = request_id; + + CAM_DBG(CAM_ICP, "ctx_data : %pK, request_id :%lld cmd_buf %x", + (void *)ctx_data->context_priv, request_id, + fw_cmd_buf_iova_addr); + + return 0; +} + +static bool cam_icp_mgr_is_valid_inconfig(struct cam_packet *packet) +{ + int i, num_in_map_entries = 0; + bool in_config_valid = false; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + + for (i = 0 ; i < packet->num_io_configs; i++) + if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) + num_in_map_entries++; + + if (num_in_map_entries <= CAM_MAX_IN_RES) { + in_config_valid = true; + } else { + CAM_ERR(CAM_ICP, "In config entries(%u) more than allowed(%u)", + num_in_map_entries, CAM_MAX_IN_RES); + } + + CAM_DBG(CAM_ICP, "number of in_config info: %u %u %u %u", + packet->num_io_configs, IPE_IO_IMAGES_MAX, + num_in_map_entries, CAM_MAX_IN_RES); + + return in_config_valid; +} + +static bool cam_icp_mgr_is_valid_outconfig(struct cam_packet *packet) +{ + int i, num_out_map_entries = 0; + bool out_config_valid = false; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + + for (i = 0 ; i < packet->num_io_configs; i++) + if (io_cfg_ptr[i].direction == CAM_BUF_OUTPUT) + num_out_map_entries++; + + if (num_out_map_entries <= CAM_MAX_OUT_RES) { + out_config_valid = true; + } else { + CAM_ERR(CAM_ICP, "Out config entries(%u) more than allowed(%u)", + num_out_map_entries, CAM_MAX_OUT_RES); + } + + CAM_DBG(CAM_ICP, "number of out_config info: %u %u %u %u", + packet->num_io_configs, IPE_IO_IMAGES_MAX, + num_out_map_entries, CAM_MAX_OUT_RES); + + return out_config_valid; +} + +static int cam_icp_mgr_pkt_validation(struct cam_packet *packet) +{ + if (((packet->header.op_code & 0xff) != + CAM_ICP_OPCODE_IPE_UPDATE) && + ((packet->header.op_code & 0xff) != + CAM_ICP_OPCODE_BPS_UPDATE)) { + CAM_ERR(CAM_ICP, "Invalid Opcode in pkt: %d", + packet->header.op_code & 0xff); + return -EINVAL; + } + + if (packet->num_io_configs > IPE_IO_IMAGES_MAX) { + CAM_ERR(CAM_ICP, "Invalid number of io configs: %d %d", + IPE_IO_IMAGES_MAX, packet->num_io_configs); + return -EINVAL; + } + + if (packet->num_cmd_buf > CAM_ICP_CTX_MAX_CMD_BUFFERS) { + CAM_ERR(CAM_ICP, "Invalid number of cmd buffers: %d %d", + CAM_ICP_CTX_MAX_CMD_BUFFERS, packet->num_cmd_buf); + return -EINVAL; + } + + if (!cam_icp_mgr_is_valid_inconfig(packet) || + !cam_icp_mgr_is_valid_outconfig(packet)) { + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u %u %u", + packet->num_cmd_buf, + packet->num_io_configs, IPE_IO_IMAGES_MAX, + packet->num_patches); + return 0; +} + +static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, + struct cam_packet *packet, struct cam_icp_hw_ctx_data *ctx_data, + uint32_t *fw_cmd_buf_iova_addr) +{ + int rc = 0; + int i, j, k; + int num_cmd_buf = 0; + uint64_t addr; + size_t len; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cpu_addr = 0; + struct ipe_frame_process_data *frame_process_data = NULL; + struct bps_frame_process_data *bps_frame_process_data = NULL; + struct frame_set *ipe_set = NULL; + struct frame_buffer *bps_bufs = NULL; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + + *fw_cmd_buf_iova_addr = 0; + for (i = 0; i < packet->num_cmd_buf; i++, num_cmd_buf++) { + if (cmd_desc[i].type == CAM_CMD_BUF_FW) { + rc = cam_mem_get_io_buf(cmd_desc[i].mem_handle, + hw_mgr->iommu_hdl, &addr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "get cmd buf failed %x", + hw_mgr->iommu_hdl); + + if (num_cmd_buf > 0) + num_cmd_buf--; + return rc; + } + *fw_cmd_buf_iova_addr = addr; + *fw_cmd_buf_iova_addr = + (*fw_cmd_buf_iova_addr + cmd_desc[i].offset); + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &cpu_addr, &len); + if (rc || !cpu_addr) { + CAM_ERR(CAM_ICP, "get cmd buf failed %x", + hw_mgr->iommu_hdl); + *fw_cmd_buf_iova_addr = 0; + + if (num_cmd_buf > 0) + num_cmd_buf--; + return rc; + } + if ((len <= cmd_desc[i].offset) || + (cmd_desc[i].size < cmd_desc[i].length) || + ((len - cmd_desc[i].offset) < + cmd_desc[i].length)) { + CAM_ERR(CAM_ICP, "Invalid offset or length"); + return -EINVAL; + } + cpu_addr = cpu_addr + cmd_desc[i].offset; + } + } + + if (!cpu_addr) { + CAM_ERR(CAM_ICP, "invalid number of cmd buf"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) { + CAM_DBG(CAM_ICP, "cpu addr = %zx", cpu_addr); + frame_process_data = (struct ipe_frame_process_data *)cpu_addr; + CAM_DBG(CAM_ICP, "%u %u %u", frame_process_data->max_num_cores, + frame_process_data->target_time, + frame_process_data->frames_in_batch); + frame_process_data->strip_lib_out_addr = 0; + frame_process_data->iq_settings_addr = 0; + frame_process_data->scratch_buffer_addr = 0; + frame_process_data->ubwc_stats_buffer_addr = 0; + frame_process_data->cdm_buffer_addr = 0; + frame_process_data->cdm_prog_base = 0; + for (i = 0; i < frame_process_data->frames_in_batch; i++) { + ipe_set = &frame_process_data->framesets[i]; + for (j = 0; j < IPE_IO_IMAGES_MAX; j++) { + for (k = 0; k < MAX_NUM_OF_IMAGE_PLANES; k++) { + ipe_set->buffers[j].buf_ptr[k] = 0; + ipe_set->buffers[j].meta_buf_ptr[k] = 0; + } + } + } + } else { + CAM_DBG(CAM_ICP, "cpu addr = %zx", cpu_addr); + bps_frame_process_data = + (struct bps_frame_process_data *)cpu_addr; + CAM_DBG(CAM_ICP, "%u %u", + bps_frame_process_data->max_num_cores, + bps_frame_process_data->target_time); + bps_frame_process_data->ubwc_stats_buffer_addr = 0; + bps_frame_process_data->cdm_buffer_addr = 0; + bps_frame_process_data->iq_settings_addr = 0; + bps_frame_process_data->strip_lib_out_addr = 0; + bps_frame_process_data->cdm_prog_addr = 0; + for (i = 0; i < BPS_IO_IMAGES_MAX; i++) { + bps_bufs = &bps_frame_process_data->buffers[i]; + for (j = 0; j < MAX_NUM_OF_IMAGE_PLANES; j++) { + bps_bufs->buf_ptr[j] = 0; + bps_bufs->meta_buf_ptr[j] = 0; + } + } + } + + return rc; +} + +static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_packet *packet, + struct cam_hw_prepare_update_args *prepare_args, + int32_t index) +{ + int i, j, k, rc = 0; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + int32_t sync_in_obj[CAM_MAX_IN_RES]; + int32_t merged_sync_in_obj; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + prepare_args->num_out_map_entries = 0; + prepare_args->num_in_map_entries = 0; + + for (i = 0, j = 0, k = 0; i < packet->num_io_configs; i++) { + if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) { + sync_in_obj[j++] = io_cfg_ptr[i].fence; + prepare_args->num_in_map_entries++; + } else { + prepare_args->out_map_entries[k++].sync_id = + io_cfg_ptr[i].fence; + prepare_args->num_out_map_entries++; + } + CAM_DBG(CAM_REQ, + "ctx_id: %u req_id: %llu dir[%d]: %u, fence: %u resource_type = %u memh %x", + ctx_data->ctx_id, packet->header.request_id, i, + io_cfg_ptr[i].direction, io_cfg_ptr[i].fence, + io_cfg_ptr[i].resource_type, + io_cfg_ptr[i].mem_handle[0]); + } + + if (prepare_args->num_in_map_entries > 1) + prepare_args->num_in_map_entries = + cam_common_util_remove_duplicate_arr( + sync_in_obj, prepare_args->num_in_map_entries); + + if (prepare_args->num_in_map_entries > 1) { + rc = cam_sync_merge(&sync_in_obj[0], + prepare_args->num_in_map_entries, &merged_sync_in_obj); + if (rc) { + prepare_args->num_out_map_entries = 0; + prepare_args->num_in_map_entries = 0; + return rc; + } + + ctx_data->hfi_frame_process.in_resource[index] = + merged_sync_in_obj; + prepare_args->in_map_entries[0].sync_id = merged_sync_in_obj; + prepare_args->num_in_map_entries = 1; + CAM_DBG(CAM_REQ, "ctx_id: %u req_id: %llu Merged Sync obj: %d", + ctx_data->ctx_id, packet->header.request_id, + merged_sync_in_obj); + } else if (prepare_args->num_in_map_entries == 1) { + prepare_args->in_map_entries[0].sync_id = sync_in_obj[0]; + prepare_args->num_in_map_entries = 1; + ctx_data->hfi_frame_process.in_resource[index] = 0; + } else { + CAM_ERR(CAM_ICP, "No input fences"); + prepare_args->num_in_map_entries = 0; + ctx_data->hfi_frame_process.in_resource[index] = 0; + rc = -EINVAL; + } + + return rc; +} + +static int cam_icp_process_stream_settings( + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_cmd_mem_regions *cmd_mem_regions, + bool map_unmap) +{ + int rc = 0, i = 0; + size_t packet_size, map_cmd_size, len; + uint64_t iova; + unsigned long rem_jiffies; + int timeout = 5000; + struct hfi_cmd_ipe_bps_map *map_cmd; + struct hfi_cmd_ipebps_async *async_direct; + + map_cmd_size = + sizeof(struct hfi_cmd_ipe_bps_map) + + ((cmd_mem_regions->num_regions - 1) * + sizeof(struct mem_map_region_data)); + + map_cmd = kzalloc(map_cmd_size, GFP_KERNEL); + if (!map_cmd) + return -ENOMEM; + + for (i = 0; i < cmd_mem_regions->num_regions; i++) { + rc = cam_mem_get_io_buf( + cmd_mem_regions->map_info_array[i].mem_handle, + icp_hw_mgr.iommu_hdl, &iova, &len); + if (rc) { + CAM_ERR(CAM_ICP, + "Failed to get cmd region iova for handle %u", + cmd_mem_regions->map_info_array[i].mem_handle); + kfree(map_cmd); + return -EINVAL; + } + + map_cmd->mem_map_region_sets[i].start_addr = (uint32_t)iova + + (cmd_mem_regions->map_info_array[i].offset); + map_cmd->mem_map_region_sets[i].len = (uint32_t) len; + + CAM_DBG(CAM_ICP, "Region %u mem_handle %d iova %pK len %u", + (i+1), cmd_mem_regions->map_info_array[i].mem_handle, + (uint32_t)iova, (uint32_t)len); + } + + map_cmd->mem_map_request_num = cmd_mem_regions->num_regions; + map_cmd->user_data = 0; + + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + (sizeof(struct hfi_cmd_ipe_bps_map) + + ((cmd_mem_regions->num_regions - 1) * + sizeof(struct mem_map_region_data))) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + + async_direct = kzalloc(packet_size, GFP_KERNEL); + if (!async_direct) { + kfree(map_cmd); + return -ENOMEM; + } + + async_direct->size = packet_size; + async_direct->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (map_unmap) + async_direct->opcode = HFI_IPEBPS_CMD_OPCODE_MEM_MAP; + else + async_direct->opcode = HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP; + async_direct->num_fw_handles = 1; + async_direct->fw_handles[0] = ctx_data->fw_handle; + async_direct->user_data1 = (uint64_t)ctx_data; + async_direct->user_data2 = (uint64_t)0x0; + memcpy(async_direct->payload.direct, map_cmd, + map_cmd_size); + + reinit_completion(&ctx_data->wait_complete); + rc = hfi_write_cmd(async_direct); + if (rc) { + CAM_ERR(CAM_ICP, "hfi write failed rc %d", rc); + goto end; + } + + CAM_DBG(CAM_ICP, "Sent FW %s cmd", + map_unmap ? "Map" : "Unmap"); + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_hfi_queue_dump(); + } + +end: + kfree(map_cmd); + kfree(async_direct); + return rc; +} + +static int cam_icp_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + struct cam_icp_clk_bw_request *soc_req; + struct cam_icp_clk_bw_request *clk_info; + struct cam_icp_clk_bw_request_v2 *soc_req_v2; + struct cam_icp_clk_bw_req_internal_v2 *clk_info_v2; + struct cam_cmd_mem_regions *cmd_mem_regions; + struct icp_cmd_generic_blob *blob; + struct cam_icp_hw_ctx_data *ctx_data; + uint32_t index; + size_t io_buf_size, clk_update_size; + int rc = 0; + uintptr_t pResource; + + if (!blob_data || (blob_size == 0)) { + CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data, + blob_size); + return -EINVAL; + } + + blob = (struct icp_cmd_generic_blob *)user_data; + ctx_data = blob->ctx; + index = blob->frame_info_idx; + + switch (blob_type) { + case CAM_ICP_CMD_GENERIC_BLOB_CLK: + CAM_WARN(CAM_ICP, + "Using deprecated blob type GENERIC_BLOB_CLK"); + if (blob_size != sizeof(struct cam_icp_clk_bw_request)) { + CAM_ERR(CAM_ICP, "Mismatch blob size %d expected %lu", + blob_size, + sizeof(struct cam_icp_clk_bw_request)); + return -EINVAL; + } + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_UNKNOWN) { + ctx_data->bw_config_version = CAM_ICP_BW_CONFIG_V1; + } else if (ctx_data->bw_config_version != + CAM_ICP_BW_CONFIG_V1) { + CAM_ERR(CAM_ICP, + "Mismatch blob versions %d expected v1 %d, blob_type=%d", + ctx_data->bw_config_version, + CAM_ICP_BW_CONFIG_V1, blob_type); + return -EINVAL; + } + + clk_info = &ctx_data->hfi_frame_process.clk_info[index]; + + soc_req = (struct cam_icp_clk_bw_request *)blob_data; + *clk_info = *soc_req; + CAM_DBG(CAM_ICP, "budget:%llu fc: %llu %d BW %lld %lld", + clk_info->budget_ns, clk_info->frame_cycles, + clk_info->rt_flag, clk_info->uncompressed_bw, + clk_info->compressed_bw); + break; + + case CAM_ICP_CMD_GENERIC_BLOB_CLK_V2: + if (blob_size < sizeof(struct cam_icp_clk_bw_request_v2)) { + CAM_ERR(CAM_ICP, "Mismatch blob size %d expected %lu", + blob_size, + sizeof(struct cam_icp_clk_bw_request_v2)); + return -EINVAL; + } + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_UNKNOWN) { + ctx_data->bw_config_version = CAM_ICP_BW_CONFIG_V2; + } else if (ctx_data->bw_config_version != + CAM_ICP_BW_CONFIG_V2) { + CAM_ERR(CAM_ICP, + "Mismatch blob versions %d expected v2 %d, blob_type=%d", + ctx_data->bw_config_version, + CAM_ICP_BW_CONFIG_V2, blob_type); + return -EINVAL; + } + + soc_req_v2 = (struct cam_icp_clk_bw_request_v2 *)blob_data; + if (soc_req_v2->num_paths > CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_ERR(CAM_ICP, "Invalid num paths: %d", + soc_req_v2->num_paths); + return -EINVAL; + } + + /* Check for integer overflow */ + if (soc_req_v2->num_paths != 1) { + if (sizeof(struct cam_axi_per_path_bw_vote) > + ((UINT_MAX - + sizeof(struct cam_icp_clk_bw_request_v2)) / + (soc_req_v2->num_paths - 1))) { + CAM_ERR(CAM_ICP, + "Size exceeds limit paths:%u size per path:%lu", + soc_req_v2->num_paths - 1, + sizeof( + struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + } + + clk_update_size = sizeof(struct cam_icp_clk_bw_request_v2) + + ((soc_req_v2->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)); + if (blob_size < clk_update_size) { + CAM_ERR(CAM_ICP, "Invalid blob size: %u", + blob_size); + return -EINVAL; + } + + clk_info = &ctx_data->hfi_frame_process.clk_info[index]; + clk_info_v2 = &ctx_data->hfi_frame_process.clk_info_v2[index]; + + memcpy(clk_info_v2, soc_req_v2, clk_update_size); + + /* Use v1 structure for clk fields */ + clk_info->budget_ns = clk_info_v2->budget_ns; + clk_info->frame_cycles = clk_info_v2->frame_cycles; + clk_info->rt_flag = clk_info_v2->rt_flag; + + CAM_DBG(CAM_ICP, "budget=%llu, frame_cycle=%llu, rt_flag=%d", + clk_info_v2->budget_ns, clk_info_v2->frame_cycles, + clk_info_v2->rt_flag); + break; + + case CAM_ICP_CMD_GENERIC_BLOB_CFG_IO: + CAM_DBG(CAM_ICP, "CAM_ICP_CMD_GENERIC_BLOB_CFG_IO"); + pResource = *((uint32_t *)blob_data); + if (copy_from_user(&ctx_data->icp_dev_io_info, + (void __user *)pResource, + sizeof(struct cam_icp_acquire_dev_info))) { + CAM_ERR(CAM_ICP, "Failed in copy from user"); + return -EFAULT; + } + CAM_DBG(CAM_ICP, "buf handle %d", + ctx_data->icp_dev_io_info.io_config_cmd_handle); + rc = cam_mem_get_io_buf( + ctx_data->icp_dev_io_info.io_config_cmd_handle, + icp_hw_mgr.iommu_hdl, + blob->io_buf_addr, &io_buf_size); + if (rc) + CAM_ERR(CAM_ICP, "Failed in blob update"); + else + CAM_DBG(CAM_ICP, "io buf addr %llu", + *blob->io_buf_addr); + break; + + case CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_MAP: + cmd_mem_regions = + (struct cam_cmd_mem_regions *)blob_data; + if (cmd_mem_regions->num_regions <= 0) { + rc = -EINVAL; + CAM_ERR(CAM_ICP, + "Invalid number of regions for FW map %u", + cmd_mem_regions->num_regions); + } else { + CAM_DBG(CAM_ICP, + "Processing blob for mapping %u regions", + cmd_mem_regions->num_regions); + rc = cam_icp_process_stream_settings(ctx_data, + cmd_mem_regions, true); + } + break; + + case CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_UNMAP: + cmd_mem_regions = + (struct cam_cmd_mem_regions *)blob_data; + if (cmd_mem_regions->num_regions <= 0) { + rc = -EINVAL; + CAM_ERR(CAM_ICP, + "Invalid number of regions for FW unmap %u", + cmd_mem_regions->num_regions); + } else { + CAM_DBG(CAM_ICP, + "Processing blob for unmapping %u regions", + cmd_mem_regions->num_regions); + rc = cam_icp_process_stream_settings(ctx_data, + cmd_mem_regions, false); + } + break; + + default: + CAM_WARN(CAM_ICP, "Invalid blob type %d", blob_type); + break; + } + return rc; +} + +static int cam_icp_process_generic_cmd_buffer( + struct cam_packet *packet, + struct cam_icp_hw_ctx_data *ctx_data, + int32_t index, + uint64_t *io_buf_addr) +{ + int i, rc = 0; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct icp_cmd_generic_blob cmd_generic_blob; + + cmd_generic_blob.ctx = ctx_data; + cmd_generic_blob.frame_info_idx = index; + cmd_generic_blob.io_buf_addr = io_buf_addr; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + for (i = 0; i < packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if (cmd_desc[i].meta_data != CAM_ICP_CMD_META_GENERIC_BLOB) + continue; + + rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[i], + cam_icp_packet_generic_blob_handler, &cmd_generic_blob); + if (rc) + CAM_ERR(CAM_ICP, "Failed in processing blobs %d", rc); + } + + return rc; +} + +static int cam_icp_mgr_process_cfg_io_cmd( + struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, + uint64_t request_id, + uint64_t io_config) +{ + ioconfig_cmd->size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + ioconfig_cmd->num_fw_handles = 1; + ioconfig_cmd->fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd->payload.indirect = io_config; + ioconfig_cmd->user_data1 = PTR_TO_U64(ctx_data); + ioconfig_cmd->user_data2 = request_id; + + return 0; +} + +static int cam_icp_mgr_update_hfi_frame_process( + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_packet *packet, + struct cam_hw_prepare_update_args *prepare_args, + int32_t *idx) +{ + int32_t index, rc; + struct hfi_cmd_ipebps_async *hfi_cmd = NULL; + + index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap, + ctx_data->hfi_frame_process.bits); + if (index < 0 || index >= CAM_FRAME_CMD_MAX) { + CAM_ERR(CAM_ICP, "request idx is wrong: %d", index); + return -EINVAL; + } + set_bit(index, ctx_data->hfi_frame_process.bitmap); + + ctx_data->hfi_frame_process.request_id[index] = + packet->header.request_id; + ctx_data->hfi_frame_process.frame_info[index].request_id = + packet->header.request_id; + ctx_data->hfi_frame_process.frame_info[index].io_config = 0; + rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index, + &ctx_data->hfi_frame_process.frame_info[index].io_config); + if (rc) { + clear_bit(index, ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.request_id[index] = -1; + return rc; + } + + if (ctx_data->hfi_frame_process.frame_info[index].io_config) { + hfi_cmd = (struct hfi_cmd_ipebps_async *) + &ctx_data->hfi_frame_process.frame_info[index].hfi_cfg_io_cmd; + rc = cam_icp_mgr_process_cfg_io_cmd(ctx_data, hfi_cmd, + packet->header.request_id, + ctx_data->hfi_frame_process.frame_info[index].io_config); + } + *idx = index; + + return rc; +} + +static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + uint64_t iova_addr; + size_t src_buf_size; + int i; + int j; + int rc = 0; + int32_t mmu_hdl; + + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_ICP, + "Found PF at port: %d mem %x fd: %x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_ICP, "port: %d f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, "get src buf address fail"); + continue; + } + if (iova_addr >> 32) { + CAM_ERR(CAM_ICP, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_ICP, + "pln %d dir %d w %d h %d s %u sh %u sz %d addr 0x%x off 0x%x memh %x", + j, io_cfg[i].direction, + io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + io_cfg[i].planes[j].slice_height, + (int32_t)src_buf_size, + (unsigned int)iova_addr, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + + iova_addr += io_cfg[i].offsets[j]; + + } + } +} + +static int cam_icp_mgr_config_stream_settings( + void *hw_mgr_priv, void *hw_stream_settings) +{ + int rc = 0; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct cam_packet *packet = NULL; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct icp_cmd_generic_blob cmd_generic_blob; + struct cam_hw_stream_setttings *config_args = + hw_stream_settings; + + if ((!hw_stream_settings) || + (!hw_mgr) || (!config_args->packet)) { + CAM_ERR(CAM_ICP, "Invalid input arguments"); + return -EINVAL; + } + + ctx_data = config_args->ctxt_to_hw_map; + mutex_lock(&ctx_data->ctx_mutex); + packet = config_args->packet; + + cmd_generic_blob.ctx = ctx_data; + cmd_generic_blob.frame_info_idx = -1; + cmd_generic_blob.io_buf_addr = NULL; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + + if (!cmd_desc[0].length || + cmd_desc[0].meta_data != CAM_ICP_CMD_META_GENERIC_BLOB) { + CAM_ERR(CAM_ICP, "Invalid cmd buffer length/metadata"); + rc = -EINVAL; + goto end; + } + + rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[0], + cam_icp_packet_generic_blob_handler, &cmd_generic_blob); + if (rc) + CAM_ERR(CAM_ICP, "Failed in processing cmd mem blob %d", rc); + +end: + mutex_unlock(&ctx_data->ctx_mutex); + return rc; +} + +static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc = 0; + int32_t idx; + uint32_t fw_cmd_buf_iova_addr; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct cam_packet *packet = NULL; + struct hfi_cmd_ipebps_async *hfi_cmd = NULL; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_prepare_update_args *prepare_args = + prepare_hw_update_args; + + if ((!prepare_args) || (!hw_mgr) || (!prepare_args->packet)) { + CAM_ERR(CAM_ICP, "Invalid args"); + return -EINVAL; + } + + ctx_data = prepare_args->ctxt_to_hw_map; + mutex_lock(&ctx_data->ctx_mutex); + if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_ICP, "ctx id: %u is not in use", + ctx_data->ctx_id); + return -EINVAL; + } + + packet = prepare_args->packet; + + if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) + return -EINVAL; + + rc = cam_icp_mgr_pkt_validation(packet); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + rc = cam_icp_mgr_process_cmd_desc(hw_mgr, packet, + ctx_data, &fw_cmd_buf_iova_addr); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + prepare_args->pf_data->packet = packet; + + CAM_DBG(CAM_REQ, "req id = %lld for ctx = %u", + packet->header.request_id, ctx_data->ctx_id); + /* Update Buffer Address from handles and patch information */ + rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + rc = cam_icp_mgr_update_hfi_frame_process(ctx_data, packet, + prepare_args, &idx); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + rc = cam_icp_mgr_process_io_cfg(hw_mgr, ctx_data, + packet, prepare_args, idx); + if (rc) { + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) + cam_sync_destroy( + ctx_data->hfi_frame_process.in_resource[idx]); + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.request_id[idx] = -1; + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + hfi_cmd = (struct hfi_cmd_ipebps_async *) + &ctx_data->hfi_frame_process.hfi_frame_cmd[idx]; + cam_icp_mgr_prepare_frame_process_cmd( + ctx_data, hfi_cmd, packet->header.request_id, + fw_cmd_buf_iova_addr); + + prepare_args->num_hw_update_entries = 1; + prepare_args->hw_update_entries[0].addr = (uintptr_t)hfi_cmd; + prepare_args->priv = &ctx_data->hfi_frame_process.frame_info[idx]; + + CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u", + packet->header.request_id, ctx_data->ctx_id); + mutex_unlock(&ctx_data->ctx_mutex); + return rc; +} + +static int cam_icp_mgr_send_abort_status(struct cam_icp_hw_ctx_data *ctx_data) +{ + struct hfi_frame_process_info *hfi_frame_process; + int idx; + + mutex_lock(&ctx_data->ctx_mutex); + hfi_frame_process = &ctx_data->hfi_frame_process; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->request_id[idx]) + continue; + + ctx_data->ctxt_event_cb(ctx_data->context_priv, true, + &hfi_frame_process->request_id[idx]); + + /* now release memory for hfi frame process command */ + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_resource[idx]); + cam_sync_destroy( + ctx_data->hfi_frame_process.in_resource[idx]); + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + } + mutex_unlock(&ctx_data->ctx_mutex); + return 0; +} + +static int cam_icp_mgr_delete_sync(void *priv, void *data) +{ + struct hfi_cmd_work_data *task_data = NULL; + struct cam_icp_hw_ctx_data *ctx_data; + struct hfi_frame_process_info *hfi_frame_process; + int idx; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid params%pK %pK", data, priv); + return -EINVAL; + } + + task_data = (struct hfi_cmd_work_data *)data; + ctx_data = task_data->data; + + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Null Context"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + hfi_frame_process = &ctx_data->hfi_frame_process; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->in_free_resource[idx]) + continue; + //cam_sync_destroy( + //ctx_data->hfi_frame_process.in_free_resource[idx]); + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + mutex_unlock(&ctx_data->ctx_mutex); + return 0; +} + +static int cam_icp_mgr_delete_sync_obj(struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + struct crm_workq_task *task; + struct hfi_cmd_work_data *task_data; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + return -ENOMEM; + } + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ctx_data; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_delete_sync; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + + return rc; +} + +static int cam_icp_mgr_flush_all(struct cam_icp_hw_ctx_data *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + struct hfi_frame_process_info *hfi_frame_process; + int idx; + bool clear_in_resource = false; + + hfi_frame_process = &ctx_data->hfi_frame_process; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->request_id[idx]) + continue; + + /* now release memory for hfi frame process command */ + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + ctx_data->hfi_frame_process.in_free_resource[idx] = + ctx_data->hfi_frame_process.in_resource[idx]; + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + clear_in_resource = true; + } + + if (clear_in_resource) + cam_icp_mgr_delete_sync_obj(ctx_data); + + return 0; +} + +static int cam_icp_mgr_flush_req(struct cam_icp_hw_ctx_data *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + int64_t request_id; + struct hfi_frame_process_info *hfi_frame_process; + int idx; + bool clear_in_resource = false; + + hfi_frame_process = &ctx_data->hfi_frame_process; + request_id = *(int64_t *)flush_args->flush_req_pending[0]; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->request_id[idx]) + continue; + + if (hfi_frame_process->request_id[idx] != request_id) + continue; + + /* now release memory for hfi frame process command */ + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + ctx_data->hfi_frame_process.in_free_resource[idx] = + ctx_data->hfi_frame_process.in_resource[idx]; + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + clear_in_resource = true; + } + + if (clear_in_resource) + cam_icp_mgr_delete_sync_obj(ctx_data); + + return 0; +} + +static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) +{ + struct cam_hw_flush_args *flush_args = hw_flush_args; + struct cam_icp_hw_ctx_data *ctx_data; + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + + if ((!hw_priv) || (!hw_flush_args)) { + CAM_ERR(CAM_ICP, "Input params are Null:"); + return -EINVAL; + } + + ctx_data = flush_args->ctxt_to_hw_map; + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Ctx data is NULL"); + return -EINVAL; + } + + if ((flush_args->flush_type >= CAM_FLUSH_TYPE_MAX) || + (flush_args->flush_type < CAM_FLUSH_TYPE_REQ)) { + CAM_ERR(CAM_ICP, "Invalid lush type: %d", + flush_args->flush_type); + return -EINVAL; + } + + CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d", + ctx_data->ctx_id, flush_args->flush_type); + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_ALL: + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!atomic_read(&hw_mgr->recovery) + && flush_args->num_req_active) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_abort_handle(ctx_data); + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + } + mutex_lock(&ctx_data->ctx_mutex); + cam_icp_mgr_flush_all(ctx_data, flush_args); + mutex_unlock(&ctx_data->ctx_mutex); + break; + case CAM_FLUSH_TYPE_REQ: + mutex_lock(&ctx_data->ctx_mutex); + if (flush_args->num_req_active) { + CAM_ERR(CAM_ICP, "Flush request is not supported"); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + if (flush_args->num_req_pending) + cam_icp_mgr_flush_req(ctx_data, flush_args); + mutex_unlock(&ctx_data->ctx_mutex); + break; + default: + CAM_ERR(CAM_ICP, "Invalid flush type: %d", + flush_args->flush_type); + return -EINVAL; + } + + return 0; +} + +static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) +{ + int rc = 0; + int ctx_id = 0; + struct cam_hw_release_args *release_hw = release_hw_args; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + + if (!release_hw || !hw_mgr) { + CAM_ERR(CAM_ICP, "Invalid args: %pK %pK", release_hw, hw_mgr); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "Enter recovery set %d", + atomic_read(&hw_mgr->recovery)); + ctx_data = release_hw->ctxt_to_hw_map; + if (!ctx_data) { + CAM_ERR(CAM_ICP, "NULL ctx data"); + return -EINVAL; + } + + ctx_id = ctx_data->ctx_id; + if (ctx_id < 0 || ctx_id >= CAM_ICP_CTX_MAX) { + CAM_ERR(CAM_ICP, "Invalid ctx id: %d", ctx_id); + return -EINVAL; + } + + mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + if (hw_mgr->ctx_data[ctx_id].state != CAM_ICP_CTX_STATE_ACQUIRED) { + CAM_DBG(CAM_ICP, "ctx is not in use: %d", ctx_id); + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + return -EINVAL; + } + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!atomic_read(&hw_mgr->recovery) && release_hw->active_req) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_abort_handle(ctx_data); + cam_icp_mgr_send_abort_status(ctx_data); + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id); + if (!hw_mgr->ctxt_cnt) { + CAM_DBG(CAM_ICP, "Last Release"); + cam_icp_mgr_icp_power_collapse(hw_mgr); + cam_icp_hw_mgr_reset_clk_info(hw_mgr); + rc = cam_ipe_bps_deint(hw_mgr); + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + if ((!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)) + cam_icp_device_timer_stop(hw_mgr); + + CAM_DBG(CAM_ICP, "Release done for ctx_id %d", ctx_id); + return rc; +} + +static int cam_icp_mgr_create_handle(uint32_t dev_type, + struct cam_icp_hw_ctx_data *ctx_data) +{ + struct hfi_cmd_create_handle create_handle; + struct hfi_cmd_work_data *task_data; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + int rc = 0; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + create_handle.size = sizeof(struct hfi_cmd_create_handle); + create_handle.pkt_type = HFI_CMD_IPEBPS_CREATE_HANDLE; + create_handle.handle_type = dev_type; + create_handle.user_data1 = PTR_TO_U64(ctx_data); + reinit_completion(&ctx_data->wait_complete); + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&create_handle; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + + if (ctx_data->fw_handle == 0) { + CAM_ERR(CAM_ICP, "Invalid handle created"); + rc = -EINVAL; + } + + return rc; +} + +static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data) +{ + struct hfi_cmd_ping_pkt ping_pkt; + struct hfi_cmd_work_data *task_data; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + int rc = 0; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "No free task to send ping command"); + return -ENOMEM; + } + + ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt); + ping_pkt.pkt_type = HFI_CMD_SYS_PING; + ping_pkt.user_data = PTR_TO_U64(ctx_data); + init_completion(&ctx_data->wait_complete); + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&ping_pkt; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + + return rc; +} + +static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, + struct cam_hw_acquire_args *args, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + int acquire_size; + struct cam_icp_acquire_dev_info icp_dev_acquire_info; + struct cam_icp_res_info *p_icp_out = NULL; + + if (copy_from_user(&icp_dev_acquire_info, + (void __user *)args->acquire_info, + sizeof(struct cam_icp_acquire_dev_info))) { + CAM_ERR(CAM_ICP, "Failed in acquire"); + return -EFAULT; + } + + if (icp_dev_acquire_info.secure_mode > CAM_SECURE_MODE_SECURE) { + CAM_ERR(CAM_ICP, "Invalid mode:%d", + icp_dev_acquire_info.secure_mode); + return -EINVAL; + } + + if ((icp_dev_acquire_info.num_out_res > ICP_MAX_OUTPUT_SUPPORTED) || + (icp_dev_acquire_info.num_out_res <= 0)) { + CAM_ERR(CAM_ICP, "Invalid num of out resources: %u", + icp_dev_acquire_info.num_out_res); + return -EINVAL; + } + + if (icp_dev_acquire_info.dev_type >= CAM_ICP_RES_TYPE_MAX) { + CAM_ERR(CAM_ICP, "Invalid device type: %d", + icp_dev_acquire_info.dev_type); + return -EFAULT; + } + + acquire_size = sizeof(struct cam_icp_acquire_dev_info) + + ((icp_dev_acquire_info.num_out_res - 1) * + sizeof(struct cam_icp_res_info)); + ctx_data->icp_dev_acquire_info = kzalloc(acquire_size, GFP_KERNEL); + if (!ctx_data->icp_dev_acquire_info) + return -ENOMEM; + + if (copy_from_user(ctx_data->icp_dev_acquire_info, + (void __user *)args->acquire_info, acquire_size)) { + CAM_ERR(CAM_ICP, "Failed in acquire: size = %d", acquire_size); + kfree(ctx_data->icp_dev_acquire_info); + ctx_data->icp_dev_acquire_info = NULL; + return -EFAULT; + } + + CAM_DBG(CAM_ICP, "%x %x %x %x %x %x %x", + ctx_data->icp_dev_acquire_info->dev_type, + ctx_data->icp_dev_acquire_info->in_res.format, + ctx_data->icp_dev_acquire_info->in_res.width, + ctx_data->icp_dev_acquire_info->in_res.height, + ctx_data->icp_dev_acquire_info->in_res.fps, + ctx_data->icp_dev_acquire_info->num_out_res, + ctx_data->icp_dev_acquire_info->scratch_mem_size); + + p_icp_out = ctx_data->icp_dev_acquire_info->out_res; + for (i = 0; i < icp_dev_acquire_info.num_out_res; i++) + CAM_DBG(CAM_ICP, "out[i] %x %x %x %x", + p_icp_out[i].format, + p_icp_out[i].width, + p_icp_out[i].height, + p_icp_out[i].fps); + + return 0; +} + +static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) +{ + int rc = 0, bitmap_size = 0; + uint32_t ctx_id = 0; + uint64_t io_buf_addr; + size_t io_buf_size; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct cam_hw_acquire_args *args = acquire_hw_args; + struct cam_icp_acquire_dev_info *icp_dev_acquire_info; + struct cam_cmd_mem_regions cmd_mem_region; + + if ((!hw_mgr_priv) || (!acquire_hw_args)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK %pK", hw_mgr_priv, + acquire_hw_args); + return -EINVAL; + } + + if (args->num_acq > 1) { + CAM_ERR(CAM_ICP, "number of resources are wrong: %u", + args->num_acq); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "ENTER"); + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_id = cam_icp_mgr_get_free_ctx(hw_mgr); + if (ctx_id >= CAM_ICP_CTX_MAX) { + CAM_ERR(CAM_ICP, "No free ctx space in hw_mgr"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -ENOSPC; + } + ctx_data = &hw_mgr->ctx_data[ctx_id]; + ctx_data->ctx_id = ctx_id; + + mutex_lock(&ctx_data->ctx_mutex); + rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data); + if (rc) + goto acquire_info_failed; + + icp_dev_acquire_info = ctx_data->icp_dev_acquire_info; + + CAM_DBG(CAM_ICP, "acquire io buf handle %d", + icp_dev_acquire_info->io_config_cmd_handle); + rc = cam_mem_get_io_buf( + icp_dev_acquire_info->io_config_cmd_handle, + hw_mgr->iommu_hdl, + &io_buf_addr, &io_buf_size); + if (rc) { + CAM_ERR(CAM_ICP, "unable to get src buf info from io desc"); + goto get_io_buf_failed; + } + + CAM_DBG(CAM_ICP, "hdl: %d, addr: %pK, size: %zu", + icp_dev_acquire_info->io_config_cmd_handle, + (void *)io_buf_addr, io_buf_size); + + if (!hw_mgr->ctxt_cnt) { + rc = cam_icp_clk_info_init(hw_mgr, ctx_data); + if (rc) + goto get_io_buf_failed; + + rc = cam_icp_mgr_icp_resume(hw_mgr); + if (rc) + goto get_io_buf_failed; + + if (icp_hw_mgr.a5_debug_type) + hfi_set_debug_level(icp_hw_mgr.a5_debug_type, + icp_hw_mgr.a5_dbg_lvl); + + hfi_set_fw_dump_level(icp_hw_mgr.a5_fw_dump_lvl); + + rc = cam_icp_send_ubwc_cfg(hw_mgr); + if (rc) + goto ubwc_cfg_failed; + } + + + rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data); + if (rc) + goto ipe_bps_resume_failed; + + rc = cam_icp_mgr_send_ping(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, "ping ack not received"); + goto send_ping_failed; + } + CAM_DBG(CAM_ICP, "ping ack received"); + + rc = cam_icp_mgr_create_handle(icp_dev_acquire_info->dev_type, + ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, "create handle failed"); + goto create_handle_failed; + } + + cmd_mem_region.num_regions = 1; + cmd_mem_region.map_info_array[0].mem_handle = + icp_dev_acquire_info->io_config_cmd_handle; + cmd_mem_region.map_info_array[0].offset = 0; + cmd_mem_region.map_info_array[0].size = + icp_dev_acquire_info->io_config_cmd_size; + cmd_mem_region.map_info_array[0].flags = 0; + + rc = cam_icp_process_stream_settings(ctx_data, + &cmd_mem_region, true); + if (rc) { + CAM_ERR(CAM_ICP, + "sending config io mapping failed rc %d", rc); + goto send_map_info_failed; + } + + rc = cam_icp_mgr_send_config_io(ctx_data, io_buf_addr); + if (rc) { + CAM_ERR(CAM_ICP, "IO Config command failed %d", rc); + goto ioconfig_failed; + } + + rc = cam_icp_process_stream_settings(ctx_data, + &cmd_mem_region, false); + if (rc) { + CAM_ERR(CAM_ICP, + "sending config io unmapping failed %d", rc); + goto send_map_info_failed; + } + + ctx_data->context_priv = args->context_data; + args->ctxt_to_hw_map = ctx_data; + + bitmap_size = BITS_TO_LONGS(CAM_FRAME_CMD_MAX) * sizeof(long); + ctx_data->hfi_frame_process.bitmap = + kzalloc(bitmap_size, GFP_KERNEL); + if (!ctx_data->hfi_frame_process.bitmap) + goto ioconfig_failed; + + ctx_data->hfi_frame_process.bits = bitmap_size * BITS_PER_BYTE; + hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb; + icp_dev_acquire_info->scratch_mem_size = ctx_data->scratch_mem_size; + + if (copy_to_user((void __user *)args->acquire_info, + icp_dev_acquire_info, sizeof(struct cam_icp_acquire_dev_info))) + goto copy_to_user_failed; + + cam_icp_ctx_clk_info_init(ctx_data); + ctx_data->state = CAM_ICP_CTX_STATE_ACQUIRED; + mutex_unlock(&ctx_data->ctx_mutex); + CAM_DBG(CAM_ICP, "scratch size = %x fw_handle = %x", + (unsigned int)icp_dev_acquire_info->scratch_mem_size, + (unsigned int)ctx_data->fw_handle); + /* Start device timer*/ + if (((hw_mgr->bps_ctxt_cnt == 1) || (hw_mgr->ipe_ctxt_cnt == 1))) + cam_icp_device_timer_start(hw_mgr); + /* Start context timer*/ + cam_icp_ctx_timer_start(ctx_data); + hw_mgr->ctxt_cnt++; + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_DBG(CAM_ICP, "Acquire Done for ctx_id %u dev name %s dev type %d", + ctx_data->ctx_id, cam_icp_dev_type_to_name( + icp_dev_acquire_info->dev_type), + icp_dev_acquire_info->dev_type); + + return 0; + +copy_to_user_failed: + kfree(ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.bitmap = NULL; +ioconfig_failed: + cam_icp_process_stream_settings(ctx_data, + &cmd_mem_region, false); +send_map_info_failed: + cam_icp_mgr_destroy_handle(ctx_data); +create_handle_failed: +send_ping_failed: + cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, ctx_data, 0); +ipe_bps_resume_failed: +ubwc_cfg_failed: + if (!hw_mgr->ctxt_cnt) + cam_icp_mgr_icp_power_collapse(hw_mgr); +get_io_buf_failed: + kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info); + hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL; +acquire_info_failed: + cam_icp_mgr_put_ctx(ctx_data); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_icp_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) +{ + int rc = 0; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query_cap = hw_caps_args; + + if ((!hw_mgr_priv) || (!hw_caps_args)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK %pK", + hw_mgr_priv, hw_caps_args); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (copy_from_user(&icp_hw_mgr.icp_caps, + u64_to_user_ptr(query_cap->caps_handle), + sizeof(struct cam_icp_query_cap_cmd))) { + CAM_ERR(CAM_ICP, "copy_from_user failed"); + rc = -EFAULT; + goto end; + } + + rc = hfi_get_hw_caps(&icp_hw_mgr.icp_caps); + if (rc) + goto end; + + icp_hw_mgr.icp_caps.dev_iommu_handle.non_secure = hw_mgr->iommu_hdl; + icp_hw_mgr.icp_caps.dev_iommu_handle.secure = hw_mgr->iommu_sec_hdl; + + if (copy_to_user(u64_to_user_ptr(query_cap->caps_handle), + &icp_hw_mgr.icp_caps, sizeof(struct cam_icp_query_cap_cmd))) { + CAM_ERR(CAM_ICP, "copy_to_user failed"); + rc = -EFAULT; + } +end: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_icp_mgr_alloc_devs(struct device_node *of_node) +{ + int rc; + uint32_t num_dev; + + rc = of_property_read_u32(of_node, "num-a5", &num_dev); + if (rc) { + CAM_ERR(CAM_ICP, "getting num of a5 failed"); + goto num_a5_failed; + } + + icp_hw_mgr.devices[CAM_ICP_DEV_A5] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL); + if (!icp_hw_mgr.devices[CAM_ICP_DEV_A5]) { + rc = -ENOMEM; + goto num_a5_failed; + } + + rc = of_property_read_u32(of_node, "num-ipe", &num_dev); + if (rc) { + CAM_ERR(CAM_ICP, "getting number of ipe dev nodes failed"); + goto num_ipe_failed; + } + + if (!icp_hw_mgr.ipe1_enable) + num_dev = 1; + + icp_hw_mgr.devices[CAM_ICP_DEV_IPE] = kcalloc(num_dev, + sizeof(struct cam_hw_intf *), GFP_KERNEL); + if (!icp_hw_mgr.devices[CAM_ICP_DEV_IPE]) { + rc = -ENOMEM; + goto num_ipe_failed; + } + + rc = of_property_read_u32(of_node, "num-bps", &num_dev); + if (rc) { + CAM_ERR(CAM_ICP, "read num bps devices failed"); + goto num_bps_failed; + } + icp_hw_mgr.devices[CAM_ICP_DEV_BPS] = kcalloc(num_dev, + sizeof(struct cam_hw_intf *), GFP_KERNEL); + if (!icp_hw_mgr.devices[CAM_ICP_DEV_BPS]) { + rc = -ENOMEM; + goto num_bps_failed; + } + + icp_hw_mgr.ipe_bps_pc_flag = of_property_read_bool(of_node, + "ipe_bps_pc_en"); + + icp_hw_mgr.icp_pc_flag = of_property_read_bool(of_node, + "icp_pc_en"); + + return 0; +num_bps_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]); +num_ipe_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]); +num_a5_failed: + return rc; +} + +static int cam_icp_mgr_init_devs(struct device_node *of_node) +{ + int rc = 0; + int count, i; + const char *name = NULL; + struct device_node *child_node = NULL; + struct platform_device *child_pdev = NULL; + struct cam_hw_intf *child_dev_intf = NULL; + + rc = cam_icp_mgr_alloc_devs(of_node); + if (rc) + return rc; + + count = of_property_count_strings(of_node, "compat-hw-name"); + if (!count) { + CAM_ERR(CAM_ICP, "no compat hw found in dev tree, cnt = %d", + count); + rc = -EINVAL; + goto compat_hw_name_failed; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "compat-hw-name", + i, &name); + if (rc) { + CAM_ERR(CAM_ICP, "getting dev object name failed"); + goto compat_hw_name_failed; + } + + child_node = of_find_node_by_name(NULL, name); + if (!child_node) { + CAM_ERR(CAM_ICP, "Cannot find node in dtsi %s", name); + rc = -ENODEV; + goto compat_hw_name_failed; + } + + child_pdev = of_find_device_by_node(child_node); + if (!child_pdev) { + CAM_ERR(CAM_ICP, "failed to find device on bus %s", + child_node->name); + rc = -ENODEV; + of_node_put(child_node); + goto compat_hw_name_failed; + } + + child_dev_intf = (struct cam_hw_intf *)platform_get_drvdata( + child_pdev); + if (!child_dev_intf) { + CAM_ERR(CAM_ICP, "no child device"); + of_node_put(child_node); + if (!icp_hw_mgr.ipe1_enable) + continue; + goto compat_hw_name_failed; + } + icp_hw_mgr.devices[child_dev_intf->hw_type] + [child_dev_intf->hw_idx] = child_dev_intf; + + if (!child_dev_intf->hw_ops.process_cmd) + goto compat_hw_name_failed; + + of_node_put(child_node); + } + + icp_hw_mgr.a5_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_A5][0]; + icp_hw_mgr.bps_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_BPS][0]; + icp_hw_mgr.ipe0_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_IPE][0]; + if (icp_hw_mgr.ipe1_enable) + icp_hw_mgr.ipe1_dev_intf = + icp_hw_mgr.devices[CAM_ICP_DEV_IPE][1]; + + return 0; +compat_hw_name_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]); + return rc; +} + +static int cam_icp_mgr_create_wq(void) +{ + int rc; + int i; + + rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK, + &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, + 0); + if (rc) { + CAM_ERR(CAM_ICP, "unable to create a command worker"); + goto cmd_work_failed; + } + + rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK, + &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_ICP, "unable to create a message worker"); + goto msg_work_failed; + } + + rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK, + &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_ICP, "unable to create a timer worker"); + goto timer_work_failed; + } + + icp_hw_mgr.cmd_work_data = + kzalloc(sizeof(struct hfi_cmd_work_data) * ICP_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!icp_hw_mgr.cmd_work_data) + goto cmd_work_data_failed; + + icp_hw_mgr.msg_work_data = + kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!icp_hw_mgr.msg_work_data) + goto msg_work_data_failed; + + icp_hw_mgr.timer_work_data = + kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!icp_hw_mgr.timer_work_data) + goto timer_work_data_failed; + + rc = cam_icp_hw_mgr_create_debugfs_entry(); + if (rc) + goto debugfs_create_failed; + + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) + icp_hw_mgr.msg_work->task.pool[i].payload = + &icp_hw_mgr.msg_work_data[i]; + + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) + icp_hw_mgr.cmd_work->task.pool[i].payload = + &icp_hw_mgr.cmd_work_data[i]; + + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) + icp_hw_mgr.timer_work->task.pool[i].payload = + &icp_hw_mgr.timer_work_data[i]; + return 0; + +debugfs_create_failed: + kfree(icp_hw_mgr.timer_work_data); +timer_work_data_failed: + kfree(icp_hw_mgr.msg_work_data); +msg_work_data_failed: + kfree(icp_hw_mgr.cmd_work_data); +cmd_work_data_failed: + cam_req_mgr_workq_destroy(&icp_hw_mgr.timer_work); +timer_work_failed: + cam_req_mgr_workq_destroy(&icp_hw_mgr.msg_work); +msg_work_failed: + cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work); +cmd_work_failed: + return rc; +} + +static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_icp_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + + break; + default: + CAM_ERR(CAM_ICP, "Invalid cmd"); + } + + return rc; +} + +int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, + int *iommu_hdl) +{ + int i, rc = 0; + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_cpas_query_cap query; + uint32_t cam_caps, camera_hw_version; + + hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl; + if (!of_node || !hw_mgr_intf) { + CAM_ERR(CAM_ICP, "Invalid args of_node %pK hw_mgr %pK", + of_node, hw_mgr_intf); + return -EINVAL; + } + + hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw; + hw_mgr_intf->hw_release = cam_icp_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update; + hw_mgr_intf->hw_config_stream_settings = + cam_icp_mgr_config_stream_settings; + hw_mgr_intf->hw_config = cam_icp_mgr_config_hw; + hw_mgr_intf->hw_open = cam_icp_mgr_hw_open_u; + hw_mgr_intf->hw_close = cam_icp_mgr_hw_close_u; + hw_mgr_intf->hw_flush = cam_icp_mgr_hw_flush; + hw_mgr_intf->hw_cmd = cam_icp_mgr_cmd; + + icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE; + mutex_init(&icp_hw_mgr.hw_mgr_mutex); + spin_lock_init(&icp_hw_mgr.hw_mgr_lock); + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) + mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex); + + cam_cpas_get_hw_info(&query.camera_family, + &query.camera_version, &query.cpas_version, &cam_caps); + cam_cpas_get_cpas_hw_version(&camera_hw_version); + + if (camera_hw_version == CAM_CPAS_TITAN_480_V100) { + if (cam_caps & CPAS_TITAN_480_IPE0_BIT) + icp_hw_mgr.ipe0_enable = true; + if (cam_caps & CPAS_BPS_BIT) + icp_hw_mgr.bps_enable = true; + } else { + if (cam_caps & CPAS_IPE0_BIT) + icp_hw_mgr.ipe0_enable = true; + if (cam_caps & CPAS_IPE1_BIT) + icp_hw_mgr.ipe1_enable = true; + if (cam_caps & CPAS_BPS_BIT) + icp_hw_mgr.bps_enable = true; + } + + rc = cam_icp_mgr_init_devs(of_node); + if (rc) + goto dev_init_failed; + + rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl); + if (rc) { + CAM_ERR(CAM_ICP, "get mmu handle failed: %d", rc); + goto icp_get_hdl_failed; + } + + rc = cam_smmu_get_handle("cam-secure", &icp_hw_mgr.iommu_sec_hdl); + if (rc) { + CAM_ERR(CAM_ICP, "get secure mmu handle failed: %d", rc); + goto secure_hdl_failed; + } + + rc = cam_icp_mgr_create_wq(); + if (rc) + goto icp_wq_create_failed; + + if (iommu_hdl) + *iommu_hdl = icp_hw_mgr.iommu_hdl; + + init_completion(&icp_hw_mgr.a5_complete); + return rc; + +icp_wq_create_failed: + cam_smmu_destroy_handle(icp_hw_mgr.iommu_sec_hdl); + icp_hw_mgr.iommu_sec_hdl = -1; +secure_hdl_failed: + cam_smmu_destroy_handle(icp_hw_mgr.iommu_hdl); + icp_hw_mgr.iommu_hdl = -1; +icp_get_hdl_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]); +dev_init_failed: + mutex_destroy(&icp_hw_mgr.hw_mgr_mutex); + for (i = 0; i < CAM_ICP_CTX_MAX; i++) + mutex_destroy(&icp_hw_mgr.ctx_data[i].ctx_mutex); + + return rc; +} diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h new file mode 100644 index 000000000000..3fa1ee0e0f8f --- /dev/null +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -0,0 +1,397 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_ICP_HW_MGR_H +#define CAM_ICP_HW_MGR_H + +#include +#include +#include +#include "cam_icp_hw_intf.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_a5_hw_intf.h" +#include "hfi_session_defs.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "cam_smmu_api.h" +#include "cam_soc_util.h" +#include "cam_req_mgr_timer.h" + +#define CAM_ICP_ROLE_PARENT 1 +#define CAM_ICP_ROLE_CHILD 2 + +#define CAM_FRAME_CMD_MAX 20 + +#define CAM_MAX_OUT_RES 6 +#define CAM_MAX_IN_RES 8 + +#define ICP_WORKQ_NUM_TASK 100 +#define ICP_WORKQ_TASK_CMD_TYPE 1 +#define ICP_WORKQ_TASK_MSG_TYPE 2 + +#define ICP_PACKET_SIZE 0 +#define ICP_PACKET_TYPE 1 +#define ICP_PACKET_OPCODE 2 +#define ICP_MAX_OUTPUT_SUPPORTED 6 + +#define ICP_FRAME_PROCESS_SUCCESS 0 +#define ICP_FRAME_PROCESS_FAILURE 1 +#define ICP_MSG_BUF_SIZE 256 +#define ICP_DBG_BUF_SIZE 102400 + +#define ICP_CLK_HW_IPE 0x0 +#define ICP_CLK_HW_BPS 0x1 +#define ICP_CLK_HW_MAX 0x2 + +#define ICP_OVER_CLK_THRESHOLD 5 + +#define CPAS_IPE0_BIT 0x1000 +#define CPAS_IPE1_BIT 0x2000 +#define CPAS_BPS_BIT 0x400 +#define CPAS_TITAN_480_IPE0_BIT 0x800 + +#define ICP_PWR_CLP_BPS 0x00000001 +#define ICP_PWR_CLP_IPE0 0x00010000 +#define ICP_PWR_CLP_IPE1 0x00020000 + +#define CAM_ICP_CTX_STATE_FREE 0x0 +#define CAM_ICP_CTX_STATE_IN_USE 0x1 +#define CAM_ICP_CTX_STATE_ACQUIRED 0x2 +#define CAM_ICP_CTX_STATE_RELEASE 0x3 + +#define CAM_ICP_CTX_MAX_CMD_BUFFERS 0x2 + +/* Current appliacble vote paths, based on number of UAPI definitions */ +#define CAM_ICP_MAX_PER_PATH_VOTES 6 + +/** + * struct icp_hfi_mem_info + * @qtbl: Memory info of queue table + * @cmd_q: Memory info of command queue + * @msg_q: Memory info of message queue + * @dbg_q: Memory info of debug queue + * @sec_heap: Memory info of secondary heap + * @fw_buf: Memory info of firmware + * @qdss_buf: Memory info of qdss + * @sfr_buf: Memory info for sfr buffer + * @shmem: Memory info for shared region + * @io_mem: Memory info for io region + */ +struct icp_hfi_mem_info { + struct cam_mem_mgr_memory_desc qtbl; + struct cam_mem_mgr_memory_desc cmd_q; + struct cam_mem_mgr_memory_desc msg_q; + struct cam_mem_mgr_memory_desc dbg_q; + struct cam_mem_mgr_memory_desc sec_heap; + struct cam_mem_mgr_memory_desc fw_buf; + struct cam_mem_mgr_memory_desc qdss_buf; + struct cam_mem_mgr_memory_desc sfr_buf; + struct cam_smmu_region_info shmem; + struct cam_smmu_region_info io_mem; +}; + +/** + * struct hfi_cmd_work_data + * @type: Task type + * @data: Pointer to command data + * @request_id: Request id + */ +struct hfi_cmd_work_data { + uint32_t type; + void *data; + int32_t request_id; +}; + +/** + * struct hfi_msg_work_data + * @type: Task type + * @data: Pointer to message data + * @irq_status: IRQ status + */ +struct hfi_msg_work_data { + uint32_t type; + void *data; + uint32_t irq_status; +}; + +/** + * struct clk_work_data + * @type: Task type + * @data: Pointer to clock info + */ +struct clk_work_data { + uint32_t type; + void *data; +}; + +/* + * struct icp_frame_info + * @request_id: request id + * @io_config: the address of io config + * @hfi_cfg_io_cmd: command struct to be sent to hfi + */ +struct icp_frame_info { + uint64_t request_id; + uint64_t io_config; + struct hfi_cmd_ipebps_async hfi_cfg_io_cmd; +}; + +/** + * struct cam_icp_clk_bw_request_v2 + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @num_paths: Number of paths for per path bw vote + * @axi_path: Per path vote info for IPE/BPS + */ +struct cam_icp_clk_bw_req_internal_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; +}; + +/** + * struct hfi_frame_process_info + * @hfi_frame_cmd: Frame process command info + * @bitmap: Bitmap for hfi_frame_cmd + * @bits: Used in hfi_frame_cmd bitmap + * @lock: Lock for hfi_frame_cmd + * @request_id: Request id list + * @num_out_resources: Number of out syncs + * @out_resource: Out sync info + * @fw_process_flag: Frame process flag + * @clk_info: Clock information for a request + * @clk_info_v2: Clock info for AXI bw voting v2 + * @frame_info: information needed to process request + */ +struct hfi_frame_process_info { + struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX]; + void *bitmap; + size_t bits; + struct mutex lock; + uint64_t request_id[CAM_FRAME_CMD_MAX]; + uint32_t num_out_resources[CAM_FRAME_CMD_MAX]; + uint32_t out_resource[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES]; + uint32_t in_resource[CAM_FRAME_CMD_MAX]; + uint32_t in_free_resource[CAM_FRAME_CMD_MAX]; + uint32_t fw_process_flag[CAM_FRAME_CMD_MAX]; + struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX]; + struct cam_icp_clk_bw_req_internal_v2 clk_info_v2[CAM_FRAME_CMD_MAX]; + struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX]; +}; + +/** + * struct cam_ctx_clk_info + * @curr_fc: Context latest request frame cycles + * @rt_flag: Flag to indicate real time request + * @base_clk: Base clock to process the request + * @reserved: Reserved field + * #uncompressed_bw: Current bandwidth voting + * @compressed_bw: Current compressed bandwidth voting + * @clk_rate: Supported clock rates for the context + * @num_paths: Number of valid AXI paths + * @axi_path: ctx based per path bw vote + */ +struct cam_ctx_clk_info { + uint32_t curr_fc; + uint32_t rt_flag; + uint32_t base_clk; + uint32_t reserved; + uint64_t uncompressed_bw; + uint64_t compressed_bw; + int32_t clk_rate[CAM_MAX_VOTE]; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; +}; +/** + * struct cam_icp_hw_ctx_data + * @context_priv: Context private data + * @ctx_mutex: Mutex for context + * @fw_handle: Firmware handle + * @scratch_mem_size: Scratch memory size + * @acquire_dev_cmd: Acquire command + * @icp_dev_acquire_info: Acquire device info + * @ctxt_event_cb: Context callback function + * @state: context state + * @role: Role of a context in case of chaining + * @chain_ctx: Peer context + * @hfi_frame_process: Frame process command + * @wait_complete: Completion info + * @temp_payload: Payload for destroy handle data + * @ctx_id: Context Id + * @bw_config_version: BW config version indicator + * @clk_info: Current clock info of a context + * @watch_dog: watchdog timer handle + * @watch_dog_reset_counter: Counter for watch dog reset + * @icp_dev_io_info: io config resource + */ +struct cam_icp_hw_ctx_data { + void *context_priv; + struct mutex ctx_mutex; + uint32_t fw_handle; + uint32_t scratch_mem_size; + struct cam_acquire_dev_cmd acquire_dev_cmd; + struct cam_icp_acquire_dev_info *icp_dev_acquire_info; + cam_hw_event_cb_func ctxt_event_cb; + uint32_t state; + uint32_t role; + struct cam_icp_hw_ctx_data *chain_ctx; + struct hfi_frame_process_info hfi_frame_process; + struct completion wait_complete; + struct ipe_bps_destroy temp_payload; + uint32_t ctx_id; + uint32_t bw_config_version; + struct cam_ctx_clk_info clk_info; + struct cam_req_mgr_timer *watch_dog; + uint32_t watch_dog_reset_counter; + struct cam_icp_acquire_dev_info icp_dev_io_info; +}; + +/** + * struct icp_cmd_generic_blob + * @ctx: Current context info + * @frame_info_idx: Index used for frame process info + * @io_buf_addr: pointer to io buffer address + */ +struct icp_cmd_generic_blob { + struct cam_icp_hw_ctx_data *ctx; + uint32_t frame_info_idx; + uint64_t *io_buf_addr; +}; + +/** + * struct cam_icp_clk_info + * @base_clk: Base clock to process request + * @curr_clk: Current clock of hadrware + * @threshold: Threshold for overclk count + * @over_clked: Over clock count + * @uncompressed_bw: Current bandwidth voting + * @compressed_bw: Current compressed bandwidth voting + * @num_paths: Number of AXI vote paths + * @axi_path: Current per path bw vote info + * @hw_type: IPE/BPS device type + * @watch_dog: watchdog timer handle + * @watch_dog_reset_counter: Counter for watch dog reset + */ +struct cam_icp_clk_info { + uint32_t base_clk; + uint32_t curr_clk; + uint32_t threshold; + uint32_t over_clked; + uint64_t uncompressed_bw; + uint64_t compressed_bw; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; + uint32_t hw_type; + struct cam_req_mgr_timer *watch_dog; + uint32_t watch_dog_reset_counter; +}; + +/** + * struct cam_icp_hw_mgr + * @hw_mgr_mutex: Mutex for ICP hardware manager + * @hw_mgr_lock: Spinlock for ICP hardware manager + * @devices: Devices of ICP hardware manager + * @ctx_data: Context data + * @icp_caps: ICP capabilities + * @fw_download: Firmware download state + * @iommu_hdl: Non secure IOMMU handle + * @iommu_sec_hdl: Secure IOMMU handle + * @hfi_mem: Memory for hfi + * @cmd_work: Work queue for hfi commands + * @msg_work: Work queue for hfi messages + * @timer_work: Work queue for timer watchdog + * @msg_buf: Buffer for message data from firmware + * @dbg_buf: Buffer for debug data from firmware + * @a5_complete: Completion info + * @cmd_work_data: Pointer to command work queue task + * @msg_work_data: Pointer to message work queue task + * @timer_work_data: Pointer to timer work queue task + * @ctxt_cnt: Active context count + * @ipe_ctxt_cnt: IPE Active context count + * @bps_ctxt_cnt: BPS Active context count + * @dentry: Debugfs entry + * @a5_debug: A5 debug flag + * @icp_pc_flag: Flag to enable/disable power collapse + * @ipe_bps_pc_flag: Flag to enable/disable + * power collapse for ipe & bps + * @icp_debug_clk: Set clock based on debug value + * @icp_default_clk: Set this clok if user doesn't supply + * @clk_info: Clock info of hardware + * @secure_mode: Flag to enable/disable secure camera + * @a5_jtag_debug: entry to enable A5 JTAG debugging + * @a5_debug_type : entry to enable FW debug message/qdss + * @a5_dbg_lvl : debug level set to FW. + * @a5_fw_dump_lvl : level set for dumping the FW data + * @ipe0_enable: Flag for IPE0 + * @ipe1_enable: Flag for IPE1 + * @bps_enable: Flag for BPS + * @a5_dev_intf : Device interface for A5 + * @ipe0_dev_intf: Device interface for IPE0 + * @ipe1_dev_intf: Device interface for IPE1 + * @bps_dev_intf: Device interface for BPS + * @ipe_clk_state: IPE clock state flag + * @bps_clk_state: BPS clock state flag + * @recovery: Flag to validate if in previous session FW + * reported a fatal error or wdt. If set FW is + * re-downloaded for new camera session. + */ +struct cam_icp_hw_mgr { + struct mutex hw_mgr_mutex; + spinlock_t hw_mgr_lock; + + struct cam_hw_intf **devices[CAM_ICP_DEV_MAX]; + struct cam_icp_hw_ctx_data ctx_data[CAM_ICP_CTX_MAX]; + struct cam_icp_query_cap_cmd icp_caps; + + bool fw_download; + int32_t iommu_hdl; + int32_t iommu_sec_hdl; + struct icp_hfi_mem_info hfi_mem; + struct cam_req_mgr_core_workq *cmd_work; + struct cam_req_mgr_core_workq *msg_work; + struct cam_req_mgr_core_workq *timer_work; + uint32_t msg_buf[ICP_MSG_BUF_SIZE]; + uint32_t dbg_buf[ICP_DBG_BUF_SIZE]; + struct completion a5_complete; + struct hfi_cmd_work_data *cmd_work_data; + struct hfi_msg_work_data *msg_work_data; + struct hfi_msg_work_data *timer_work_data; + uint32_t ctxt_cnt; + uint32_t ipe_ctxt_cnt; + uint32_t bps_ctxt_cnt; + struct dentry *dentry; + bool a5_debug; + bool icp_pc_flag; + bool ipe_bps_pc_flag; + uint64_t icp_debug_clk; + uint64_t icp_default_clk; + struct cam_icp_clk_info clk_info[ICP_CLK_HW_MAX]; + bool secure_mode; + bool a5_jtag_debug; + u64 a5_debug_type; + u64 a5_dbg_lvl; + u64 a5_fw_dump_lvl; + bool ipe0_enable; + bool ipe1_enable; + bool bps_enable; + struct cam_hw_intf *a5_dev_intf; + struct cam_hw_intf *ipe0_dev_intf; + struct cam_hw_intf *ipe1_dev_intf; + struct cam_hw_intf *bps_dev_intf; + bool ipe_clk_state; + bool bps_clk_state; + atomic_t recovery; +}; + +static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args); +static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args); +static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr); +static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr); +#endif /* CAM_ICP_HW_MGR_H */ diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h new file mode 100644 index 000000000000..397592a4410c --- /dev/null +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_A5_HW_INTF_H +#define CAM_A5_HW_INTF_H + +#include +#include +#include +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +enum cam_icp_a5_cmd_type { + CAM_ICP_A5_CMD_FW_DOWNLOAD, + CAM_ICP_A5_CMD_POWER_COLLAPSE, + CAM_ICP_A5_CMD_POWER_RESUME, + CAM_ICP_A5_CMD_SET_FW_BUF, + CAM_ICP_A5_CMD_ACQUIRE, + CAM_ICP_A5_SET_IRQ_CB, + CAM_ICP_A5_TEST_IRQ, + CAM_ICP_A5_SEND_INIT, + CAM_ICP_A5_CMD_VOTE_CPAS, + CAM_ICP_A5_CMD_CPAS_START, + CAM_ICP_A5_CMD_CPAS_STOP, + CAM_ICP_A5_CMD_UBWC_CFG, + CAM_ICP_A5_CMD_PC_PREP, + CAM_ICP_A5_CMD_MAX, +}; + +struct cam_icp_a5_set_fw_buf_info { + uint32_t iova; + uint64_t kva; + uint64_t len; +}; + +/** + * struct cam_icp_a5_query_cap - ICP query device capability payload + * @fw_version: firmware version info + * @api_version: api version info + * @num_ipe: number of ipes + * @num_bps: number of bps + * @num_dev: number of device capabilities in dev_caps + * @reserved: reserved + * @dev_ver: returned device capability array + * @CAM_QUERY_CAP IOCTL + */ +struct cam_icp_a5_query_cap { + struct cam_icp_ver fw_version; + struct cam_icp_ver api_version; + uint32_t num_ipe; + uint32_t num_bps; + uint32_t num_dev; + uint32_t reserved; + struct cam_icp_dev_ver dev_ver[CAM_ICP_DEV_TYPE_MAX]; +}; + +struct cam_icp_a5_acquire_dev { + uint32_t ctx_id; + struct cam_icp_acquire_dev_info icp_acquire_info; + struct cam_icp_res_info icp_out_acquire_info[2]; + uint32_t fw_handle; +}; + +struct cam_icp_a5_set_irq_cb { + int32_t (*icp_hw_mgr_cb)(uint32_t irq_status, void *data); + void *data; +}; + +struct cam_icp_a5_test_irq { + uint32_t test_irq; +}; +#endif /* CAM_A5_HW_INTF_H */ diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h new file mode 100644 index 000000000000..e02022435d8b --- /dev/null +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_BPS_HW_INTF_H +#define CAM_BPS_HW_INTF_H + +#include +#include +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +/* BPS register */ +#define BPS_TOP_RST_CMD 0x1008 +#define BPS_CDM_RST_CMD 0x10 +#define BPS_CDM_IRQ_STATUS 0x44 +#define BPS_TOP_IRQ_STATUS 0x100C + +/* BPS CDM/TOP status register */ +#define BPS_RST_DONE_IRQ_STATUS_BIT 0x1 + +enum cam_icp_bps_cmd_type { + CAM_ICP_BPS_CMD_FW_DOWNLOAD, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + CAM_ICP_BPS_CMD_POWER_RESUME, + CAM_ICP_BPS_CMD_SET_FW_BUF, + CAM_ICP_BPS_CMD_VOTE_CPAS, + CAM_ICP_BPS_CMD_CPAS_START, + CAM_ICP_BPS_CMD_CPAS_STOP, + CAM_ICP_BPS_CMD_UPDATE_CLK, + CAM_ICP_BPS_CMD_DISABLE_CLK, + CAM_ICP_BPS_CMD_RESET, + CAM_ICP_BPS_CMD_MAX, +}; + +#endif /* CAM_BPS_HW_INTF_H */ diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h new file mode 100644 index 000000000000..aadf27fef485 --- /dev/null +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_ICP_HW_INTF_H +#define CAM_ICP_HW_INTF_H + +#define CAM_ICP_CMD_BUF_MAX_SIZE 128 +#define CAM_ICP_MSG_BUF_MAX_SIZE CAM_ICP_CMD_BUF_MAX_SIZE + +#define CAM_ICP_BW_CONFIG_UNKNOWN 0 +#define CAM_ICP_BW_CONFIG_V1 1 +#define CAM_ICP_BW_CONFIG_V2 2 + +enum cam_a5_hw_type { + CAM_ICP_DEV_A5, + CAM_ICP_DEV_IPE, + CAM_ICP_DEV_BPS, + CAM_ICP_DEV_MAX, +}; + +/** + * struct cam_a5_clk_update_cmd - Payload for hw manager command + * + * @curr_clk_rate: clk rate to HW + * @ipe_bps_pc_enable power collpase enable flag + */ +struct cam_a5_clk_update_cmd { + uint32_t curr_clk_rate; + bool ipe_bps_pc_enable; +}; +#endif diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h new file mode 100644 index 000000000000..836a56492447 --- /dev/null +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_IPE_HW_INTF_H +#define CAM_IPE_HW_INTF_H + +#include +#include +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +/* IPE registers */ +#define IPE_TOP_RST_CMD 0x1008 +#define IPE_CDM_RST_CMD 0x10 +#define IPE_CDM_IRQ_STATUS 0x44 +#define IPE_TOP_IRQ_STATUS 0x100C + +/* IPE CDM/TOP status register */ +#define IPE_RST_DONE_IRQ_STATUS_BIT 0x1 + +enum cam_icp_ipe_cmd_type { + CAM_ICP_IPE_CMD_FW_DOWNLOAD, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + CAM_ICP_IPE_CMD_POWER_RESUME, + CAM_ICP_IPE_CMD_SET_FW_BUF, + CAM_ICP_IPE_CMD_VOTE_CPAS, + CAM_ICP_IPE_CMD_CPAS_START, + CAM_ICP_IPE_CMD_CPAS_STOP, + CAM_ICP_IPE_CMD_UPDATE_CLK, + CAM_ICP_IPE_CMD_DISABLE_CLK, + CAM_ICP_IPE_CMD_RESET, + CAM_ICP_IPE_CMD_MAX, +}; + +#endif /* CAM_IPE_HW_INTF_H */ diff --git a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h new file mode 100644 index 000000000000..25fbe2b8f6c5 --- /dev/null +++ b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_ICP_HW_MGR_INTF_H +#define CAM_ICP_HW_MGR_INTF_H + +#include +#include +#include +#include "cam_cpas_api.h" + +#define ICP_CLK_TURBO_HZ 600000000 +#define ICP_CLK_SVS_HZ 400000000 + +#define CAM_ICP_A5_BW_BYTES_VOTE 40000000 + +#define CAM_ICP_CTX_MAX 54 + +#define CPAS_IPE1_BIT 0x2000 + +#define CAM_IPE_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_IPE_WR_VID +#define CAM_IPE_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_WRITE +#define CAM_BPS_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL +#define CAM_BPS_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_WRITE +#define CAM_ICP_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL +#define CAM_ICP_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_READ + +int cam_icp_hw_mgr_init(struct device_node *of_node, + uint64_t *hw_mgr_hdl, int *iommu_hdl); + +/** + * struct cam_icp_cpas_vote + * @ahb_vote: AHB vote info + * @axi_vote: AXI vote info + * @ahb_vote_valid: Flag for ahb vote data + * @axi_vote_valid: flag for axi vote data + */ +struct cam_icp_cpas_vote { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote; + uint32_t ahb_vote_valid; + uint32_t axi_vote_valid; +}; + +#endif /* CAM_ICP_HW_MGR_INTF_H */ diff --git a/drivers/cam_icp/icp_hw/ipe_hw/Makefile b/drivers/cam_icp/icp_hw/ipe_hw/Makefile new file mode 100644 index 000000000000..5055e12dff2a --- /dev/null +++ b/drivers/cam_icp/icp_hw/ipe_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += ipe_dev.o ipe_core.o ipe_soc.o diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c new file mode 100644 index 000000000000..82d0ebe54cc4 --- /dev/null +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "ipe_core.h" +#include "ipe_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_ipe_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 + +static int cam_ipe_cpas_vote(struct cam_ipe_device_core_info *core_info, + struct cam_icp_cpas_vote *cpas_vote) +{ + int rc = 0; + + if (cpas_vote->ahb_vote_valid) + rc = cam_cpas_update_ahb_vote(core_info->cpas_handle, + &cpas_vote->ahb_vote); + if (cpas_vote->axi_vote_valid) + rc = cam_cpas_update_axi_vote(core_info->cpas_handle, + &cpas_vote->axi_vote); + + if (rc) + CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + + return rc; +} + +int cam_ipe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *ipe_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_icp_cpas_vote cpas_vote; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote.axi_vote.num_paths = 1; + cpas_vote.axi_vote.axi_path[0].path_data_type = + CAM_IPE_DEFAULT_AXI_PATH; + cpas_vote.axi_vote.axi_path[0].transac_type = + CAM_IPE_DEFAULT_AXI_TRANSAC; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_ICP, "cpas start failed: %d", rc); + goto error; + } + core_info->cpas_start = true; + + rc = cam_ipe_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ICP, "soc enable is failed : %d", rc); + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } else { + core_info->clk_enable = true; + } + +error: + return rc; +} + +int cam_ipe_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *ipe_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + rc = cam_ipe_disable_soc_resources(soc_info, core_info->clk_enable); + if (rc) + CAM_ERR(CAM_ICP, "soc disable is failed : %d", rc); + core_info->clk_enable = false; + + if (core_info->cpas_start) { + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + + return rc; +} + +static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + hw_info = core_info->ipe_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + if (!(pwr_ctrl & IPE_COLLAPSE_MASK)) { + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x1); + + if (pwr_status >> IPE_PWR_ON_MASK) + CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + pwr_status, pwr_ctrl); + + } + cam_ipe_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return 0; +} + +static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + int rc = 0; + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + hw_info = core_info->ipe_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + if (pwr_ctrl & IPE_COLLAPSE_MASK) { + CAM_DBG(CAM_ICP, "IPE pwr_ctrl set(%x)", pwr_ctrl); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0); + } + + rc = cam_ipe_transfer_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return rc; +} + +static int cam_ipe_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_ipe_device_core_info *core_info) +{ + int pwr_ctrl, pwr_status, rc = 0; + uint32_t status = 0, retry_cnt = 0; + bool reset_ipe_cdm_fail = false; + bool reset_ipe_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_IPE_CMD_RESET"); + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_HFI, "IPE reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + + /* IPE CDM core reset*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + IPE_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_cdm_irq_status = %u", status); + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE CDM rst failed status 0x%x", status); + reset_ipe_cdm_fail = true; + } + + /* IPE reset*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + IPE_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_top_irq_status = %u", status); + + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE top rst failed status 0x%x", status); + reset_ipe_top_fail = true; + } + + cam_ipe_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After)pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_ipe_cdm_fail || reset_ipe_top_fail) + rc = -EAGAIN; + + return rc; +} + +int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *ipe_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_ICP_IPE_CMD_MAX) { + CAM_ERR(CAM_ICP, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + hw_info = core_info->ipe_hw_info; + + switch (cmd_type) { + case CAM_ICP_IPE_CMD_VOTE_CPAS: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) + return -EINVAL; + + cam_ipe_cpas_vote(core_info, cpas_vote); + break; + } + + case CAM_ICP_IPE_CMD_CPAS_START: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) + return -EINVAL; + + if (!core_info->cpas_start) { + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote->ahb_vote, &cpas_vote->axi_vote); + core_info->cpas_start = true; + } + break; + } + + case CAM_ICP_IPE_CMD_CPAS_STOP: + if (core_info->cpas_start) { + cam_cpas_stop(core_info->cpas_handle); + core_info->cpas_start = false; + } + break; + case CAM_ICP_IPE_CMD_POWER_COLLAPSE: + rc = cam_ipe_handle_pc(ipe_dev); + break; + case CAM_ICP_IPE_CMD_POWER_RESUME: + rc = cam_ipe_handle_resume(ipe_dev); + break; + case CAM_ICP_IPE_CMD_UPDATE_CLK: { + struct cam_a5_clk_update_cmd *clk_upd_cmd = + (struct cam_a5_clk_update_cmd *)cmd_args; + uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + + CAM_DBG(CAM_ICP, "ipe_src_clk rate = %d", (int)clk_rate); + if (!core_info->clk_enable) { + if (clk_upd_cmd->ipe_bps_pc_enable) { + cam_ipe_handle_pc(ipe_dev); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x0); + } + rc = cam_ipe_toggle_clk(soc_info, true); + if (rc) + CAM_ERR(CAM_ICP, "Enable failed"); + else + core_info->clk_enable = true; + if (clk_upd_cmd->ipe_bps_pc_enable) { + rc = cam_ipe_handle_resume(ipe_dev); + if (rc) + CAM_ERR(CAM_ICP, "bps resume failed"); + } + } + CAM_DBG(CAM_ICP, "clock rate %d", clk_rate); + + rc = cam_ipe_update_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_ICP, "Failed to update clk"); + } + break; + case CAM_ICP_IPE_CMD_DISABLE_CLK: + if (core_info->clk_enable == true) + cam_ipe_toggle_clk(soc_info, false); + core_info->clk_enable = false; + break; + case CAM_ICP_IPE_CMD_RESET: + rc = cam_ipe_cmd_reset(soc_info, core_info); + break; + default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; + break; + } + return rc; +} + +irqreturn_t cam_ipe_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h new file mode 100644 index 000000000000..1a15e9233896 --- /dev/null +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_IPE_CORE_H +#define CAM_IPE_CORE_H + +#include +#include +#include +#include + +#define IPE_COLLAPSE_MASK 0x1 +#define IPE_PWR_ON_MASK 0x2 + +struct cam_ipe_device_hw_info { + uint32_t hw_idx; + uint32_t pwr_ctrl; + uint32_t pwr_status; + uint32_t reserved; +}; + +struct cam_ipe_device_core_info { + struct cam_ipe_device_hw_info *ipe_hw_info; + uint32_t cpas_handle; + bool cpas_start; + bool clk_enable; +}; + +int cam_ipe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_ipe_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_ipe_irq(int irq_num, void *data); + +#endif /* CAM_IPE_CORE_H */ diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c new file mode 100644 index 000000000000..0390488d92b3 --- /dev/null +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "ipe_core.h" +#include "ipe_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_icp_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static struct cam_ipe_device_hw_info cam_ipe_hw_info[] = { + { + .hw_idx = 0, + .pwr_ctrl = 0x4c, + .pwr_status = 0x48, + .reserved = 0, + }, + { + .hw_idx = 1, + .pwr_ctrl = 0x54, + .pwr_status = 0x50, + .reserved = 0, + }, +}; +EXPORT_SYMBOL(cam_ipe_hw_info); + +static char ipe_dev_name[8]; + +int cam_ipe_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_ipe_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = &soc_info->pdev->dev; + memcpy(cpas_register_params.identifier, "ipe", sizeof("ipe")); + cpas_register_params.cam_cpas_client_cb = NULL; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +int cam_ipe_probe(struct platform_device *pdev) +{ + struct cam_hw_info *ipe_dev = NULL; + struct cam_hw_intf *ipe_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int rc = 0; + struct cam_cpas_query_cap query; + uint32_t cam_caps; + uint32_t hw_idx; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_idx); + + cam_cpas_get_hw_info(&query.camera_family, + &query.camera_version, &query.cpas_version, &cam_caps); + if ((!(cam_caps & CPAS_IPE1_BIT)) && (hw_idx)) { + CAM_ERR(CAM_ICP, "IPE1 hw idx = %d\n", hw_idx); + return -EINVAL; + } + + ipe_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!ipe_dev_intf) + return -ENOMEM; + + ipe_dev_intf->hw_idx = hw_idx; + ipe_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!ipe_dev) { + kfree(ipe_dev_intf); + return -ENOMEM; + } + + memset(ipe_dev_name, 0, sizeof(ipe_dev_name)); + snprintf(ipe_dev_name, sizeof(ipe_dev_name), + "ipe%1u", ipe_dev_intf->hw_idx); + + ipe_dev->soc_info.pdev = pdev; + ipe_dev->soc_info.dev = &pdev->dev; + ipe_dev->soc_info.dev_name = ipe_dev_name; + ipe_dev_intf->hw_priv = ipe_dev; + ipe_dev_intf->hw_ops.init = cam_ipe_init_hw; + ipe_dev_intf->hw_ops.deinit = cam_ipe_deinit_hw; + ipe_dev_intf->hw_ops.process_cmd = cam_ipe_process_cmd; + ipe_dev_intf->hw_type = CAM_ICP_DEV_IPE; + + CAM_DBG(CAM_ICP, "type %d index %d", + ipe_dev_intf->hw_type, + ipe_dev_intf->hw_idx); + + platform_set_drvdata(pdev, ipe_dev_intf); + + ipe_dev->core_info = kzalloc(sizeof(struct cam_ipe_device_core_info), + GFP_KERNEL); + if (!ipe_dev->core_info) { + kfree(ipe_dev); + kfree(ipe_dev_intf); + return -ENOMEM; + } + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_DBG(CAM_ICP, "No ipe hardware info"); + kfree(ipe_dev->core_info); + kfree(ipe_dev); + kfree(ipe_dev_intf); + rc = -EINVAL; + return rc; + } + hw_info = &cam_ipe_hw_info[ipe_dev_intf->hw_idx]; + core_info->ipe_hw_info = hw_info; + + rc = cam_ipe_init_soc_resources(&ipe_dev->soc_info, cam_ipe_irq, + ipe_dev); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed to init_soc"); + kfree(ipe_dev->core_info); + kfree(ipe_dev); + kfree(ipe_dev_intf); + return rc; + } + + CAM_DBG(CAM_ICP, "cam_ipe_init_soc_resources : %pK", + (void *)&ipe_dev->soc_info); + rc = cam_ipe_register_cpas(&ipe_dev->soc_info, + core_info, ipe_dev_intf->hw_idx); + if (rc < 0) { + kfree(ipe_dev->core_info); + kfree(ipe_dev); + kfree(ipe_dev_intf); + return rc; + } + ipe_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&ipe_dev->hw_mutex); + spin_lock_init(&ipe_dev->hw_lock); + init_completion(&ipe_dev->hw_complete); + + CAM_DBG(CAM_ICP, "IPE%d probe successful", + ipe_dev_intf->hw_idx); + + return rc; +} + +static const struct of_device_id cam_ipe_dt_match[] = { + { + .compatible = "qcom,cam-ipe", + .data = &cam_ipe_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_ipe_dt_match); + +static struct platform_driver cam_ipe_driver = { + .probe = cam_ipe_probe, + .driver = { + .name = "cam-ipe", + .owner = THIS_MODULE, + .of_match_table = cam_ipe_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ipe_init_module(void) +{ + return platform_driver_register(&cam_ipe_driver); +} + +static void __exit cam_ipe_exit_module(void) +{ + platform_driver_unregister(&cam_ipe_driver); +} + +module_init(cam_ipe_init_module); +module_exit(cam_ipe_exit_module); +MODULE_DESCRIPTION("CAM IPE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c new file mode 100644 index 000000000000..a33c7b68bf97 --- /dev/null +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "ipe_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + + +int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + + return rc; +} + +int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + + return rc; +} + +static int cam_ipe_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) + CAM_ERR(CAM_ICP, "get ipe dt prop is failed"); + + return rc; +} + +static int cam_ipe_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t ipe_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, ipe_irq_handler, + irq_data); + + return rc; +} + +int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ipe_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_ipe_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + rc = cam_ipe_request_platform_resource(soc_info, ipe_irq_handler, + irq_data); + if (rc < 0) + return rc; + + return rc; +} + +int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, false); + if (rc) { + CAM_ERR(CAM_ICP, "enable platform failed"); + return rc; + } + + return rc; +} + +int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + false); + if (rc) + CAM_ERR(CAM_ICP, "enable platform failed"); + + return rc; +} + +int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate) +{ + int32_t src_clk_idx; + + if (!soc_info) + return -EINVAL; + + src_clk_idx = soc_info->src_clk_idx; + + if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && + (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && + (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { + CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + clk_rate, + soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); + clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; + } + + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); +} + +int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) +{ + int rc = 0; + + if (clk_enable) + rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + else + cam_soc_util_clk_disable_default(soc_info); + + return rc; +} diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h new file mode 100644 index 000000000000..8981b18823ad --- /dev/null +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_IPE_SOC_H +#define CAM_IPE_SOC_H + +#include "cam_soc_util.h" + +int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ipe_irq_handler, void *irq_data); + +int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk); + +int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate); +int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable); +#endif /* CAM_IPE_SOC_H */ diff --git a/drivers/cam_isp/Makefile b/drivers/cam_isp/Makefile new file mode 100644 index 000000000000..069350122c7b --- /dev/null +++ b/drivers/cam_isp/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ + +obj-$(CONFIG_SPECTRA_CAMERA) += isp_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_dev.o cam_isp_context.o diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c new file mode 100644 index 000000000000..7e1fa25910b2 --- /dev/null +++ b/drivers/cam_isp/cam_isp_context.c @@ -0,0 +1,3937 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "cam_mem_mgr.h" +#include "cam_sync_api.h" +#include "cam_req_mgr_dev.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" +#include "cam_context_utils.h" +#include "cam_cdm_util.h" +#include "cam_isp_context.h" +#include "cam_common_util.h" + +static const char isp_dev_name[] = "isp"; + +#define INC_STATE_MONITOR_HEAD(head) \ + (atomic64_add_return(1, head) % \ + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) + +static int cam_isp_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info); + +static void __cam_isp_ctx_update_state_monitor_array( + struct cam_isp_context *ctx_isp, + enum cam_isp_state_change_trigger trigger_type, + uint64_t req_id) +{ + int iterator = INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head); + + ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state = + ctx_isp->substate_activated; + ctx_isp->cam_isp_ctx_state_monitor[iterator].frame_id = + ctx_isp->frame_id; + ctx_isp->cam_isp_ctx_state_monitor[iterator].trigger = + trigger_type; + ctx_isp->cam_isp_ctx_state_monitor[iterator].req_id = + req_id; + ctx_isp->cam_isp_ctx_state_monitor[iterator].evt_time_stamp = + jiffies_to_msecs(jiffies) - ctx_isp->init_timestamp; +} + +static const char *__cam_isp_ctx_substate_val_to_type( + uint32_t type) +{ + switch (type) { + case CAM_ISP_CTX_ACTIVATED_SOF: + return "SOF"; + case CAM_ISP_CTX_ACTIVATED_APPLIED: + return "APPLIED"; + case CAM_ISP_CTX_ACTIVATED_EPOCH: + return "EPOCH"; + case CAM_ISP_CTX_ACTIVATED_BUBBLE: + return "BUBBLE"; + case CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED: + return "BUBBLE_APPLIED"; + case CAM_ISP_CTX_ACTIVATED_HW_ERROR: + return "HW_ERROR"; + case CAM_ISP_CTX_ACTIVATED_HALT: + return "HALT"; + default: + return "CAM_ISP_CTX_INVALID_STATE"; + } +} + +static const char *__cam_isp_hw_evt_val_to_type( + uint32_t evt_id) +{ + switch (evt_id) { + case CAM_ISP_STATE_CHANGE_TRIGGER_ERROR: + return "ERROR"; + case CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED: + return "APPLIED"; + case CAM_ISP_STATE_CHANGE_TRIGGER_SOF: + return "SOF"; + case CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE: + return "REG_UPDATE"; + case CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH: + return "EPOCH"; + case CAM_ISP_STATE_CHANGE_TRIGGER_EOF: + return "EOF"; + case CAM_ISP_STATE_CHANGE_TRIGGER_DONE: + return "DONE"; + case CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH: + return "FLUSH"; + default: + return "CAM_ISP_EVENT_INVALID"; + } +} + +static void __cam_isp_ctx_dump_state_monitor_array( + struct cam_isp_context *ctx_isp) +{ + int i = 0; + int64_t state_head = 0; + uint32_t index, num_entries, oldest_entry; + + state_head = atomic64_read(&ctx_isp->state_monitor_head); + + if (state_head == -1) { + return; + } else if (state_head < CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) { + num_entries = state_head; + oldest_entry = 0; + } else { + num_entries = CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; + oldest_entry = (state_head + 1) % + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; + } + + CAM_ERR(CAM_ISP, + "Dumping state information for preceding requests"); + + index = oldest_entry; + + for (i = 0; i < num_entries; i++) { + CAM_ERR(CAM_ISP, + "Index[%d] time[%d] : State[%s] Frame[%lld] ReqId[%llu] evt_type[%s]", + index, + ctx_isp->cam_isp_ctx_state_monitor[index].evt_time_stamp, + __cam_isp_ctx_substate_val_to_type( + ctx_isp->cam_isp_ctx_state_monitor[index].curr_state), + ctx_isp->cam_isp_ctx_state_monitor[index].frame_id, + ctx_isp->cam_isp_ctx_state_monitor[index].req_id, + __cam_isp_hw_evt_val_to_type( + ctx_isp->cam_isp_ctx_state_monitor[index].trigger)); + + index = (index + 1) % CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; + } +} + +static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) +{ + int i = 0, rc = 0; + size_t len = 0; + uint32_t *buf_addr; + uint32_t *buf_start, *buf_end; + size_t remain_len = 0; + + for (i = 0; i < req_isp->num_cfg; i++) { + rc = cam_packet_util_get_cmd_mem_addr( + req_isp->cfg[i].handle, &buf_addr, &len); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Failed to get_cmd_mem_addr, rc=%d", + rc); + } else { + if (req_isp->cfg[i].offset >= ((uint32_t)len)) { + CAM_ERR(CAM_ISP, + "Invalid offset exp %u actual %u", + req_isp->cfg[i].offset, (uint32_t)len); + return; + } + remain_len = len - req_isp->cfg[i].offset; + + if (req_isp->cfg[i].len > + ((uint32_t)remain_len)) { + CAM_ERR(CAM_ISP, + "Invalid len exp %u remain_len %u", + req_isp->cfg[i].len, + (uint32_t)remain_len); + return; + } + + buf_start = (uint32_t *)((uint8_t *) buf_addr + + req_isp->cfg[i].offset); + buf_end = (uint32_t *)((uint8_t *) buf_start + + req_isp->cfg[i].len - 1); + cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + } + } +} + +static int __cam_isp_ctx_enqueue_request_in_order( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + struct cam_ctx_request *req_current; + struct cam_ctx_request *req_prev; + struct list_head temp_list; + + INIT_LIST_HEAD(&temp_list); + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + } else { + list_for_each_entry_safe_reverse( + req_current, req_prev, &ctx->pending_req_list, list) { + if (req->request_id < req_current->request_id) { + list_del_init(&req_current->list); + list_add(&req_current->list, &temp_list); + continue; + } else if (req->request_id == req_current->request_id) { + CAM_WARN(CAM_ISP, + "Received duplicated request %lld", + req->request_id); + } + break; + } + list_add_tail(&req->list, &ctx->pending_req_list); + + if (!list_empty(&temp_list)) { + list_for_each_entry_safe( + req_current, req_prev, &temp_list, list) { + list_del_init(&req_current->list); + list_add_tail(&req_current->list, + &ctx->pending_req_list); + } + } + } + spin_unlock_bh(&ctx->lock); + return 0; +} + +static int __cam_isp_ctx_enqueue_init_request( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + int rc = 0; + struct cam_ctx_request *req_old; + struct cam_isp_ctx_req *req_isp_old; + struct cam_isp_ctx_req *req_isp_new; + + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + CAM_DBG(CAM_ISP, "INIT packet added req id= %d", + req->request_id); + goto end; + } + + req_old = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + req_isp_old = (struct cam_isp_ctx_req *) req_old->req_priv; + req_isp_new = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp_old->hw_update_data.packet_opcode_type == + CAM_ISP_PACKET_INIT_DEV) { + if ((req_isp_old->num_cfg + req_isp_new->num_cfg) >= + CAM_ISP_CTX_CFG_MAX) { + CAM_WARN(CAM_ISP, "Can not merge INIT pkt"); + rc = -ENOMEM; + } + + if (req_isp_old->num_fence_map_out != 0 || + req_isp_old->num_fence_map_in != 0) { + CAM_WARN(CAM_ISP, "Invalid INIT pkt sequence"); + rc = -EINVAL; + } + + if (!rc) { + memcpy(req_isp_old->fence_map_out, + req_isp_new->fence_map_out, + sizeof(req_isp_new->fence_map_out[0])* + req_isp_new->num_fence_map_out); + req_isp_old->num_fence_map_out = + req_isp_new->num_fence_map_out; + + memcpy(req_isp_old->fence_map_in, + req_isp_new->fence_map_in, + sizeof(req_isp_new->fence_map_in[0])* + req_isp_new->num_fence_map_in); + req_isp_old->num_fence_map_in = + req_isp_new->num_fence_map_in; + + memcpy(&req_isp_old->cfg[req_isp_old->num_cfg], + req_isp_new->cfg, + sizeof(req_isp_new->cfg[0])* + req_isp_new->num_cfg); + req_isp_old->num_cfg += req_isp_new->num_cfg; + + req_old->request_id = req->request_id; + + list_add_tail(&req->list, &ctx->free_req_list); + } + } else { + CAM_WARN(CAM_ISP, + "Received Update pkt before INIT pkt. req_id= %lld", + req->request_id); + rc = -EINVAL; + } +end: + spin_unlock_bh(&ctx->lock); + return rc; +} + +static const char *__cam_isp_resource_handle_id_to_type( + uint32_t resource_handle) +{ + switch (resource_handle) { + case CAM_ISP_IFE_OUT_RES_FULL: + return "FULL"; + case CAM_ISP_IFE_OUT_RES_DS4: + return "DS4"; + case CAM_ISP_IFE_OUT_RES_DS16: + return "DS16"; + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + return "RAW_DUMP"; + case CAM_ISP_IFE_OUT_RES_FD: + return "FD"; + case CAM_ISP_IFE_OUT_RES_PDAF: + return "PDAF"; + case CAM_ISP_IFE_OUT_RES_RDI_0: + return "RDI_0"; + case CAM_ISP_IFE_OUT_RES_RDI_1: + return "RDI_1"; + case CAM_ISP_IFE_OUT_RES_RDI_2: + return "RDI_2"; + case CAM_ISP_IFE_OUT_RES_RDI_3: + return "RDI_3"; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + return "STATS_HDR_BE"; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + return "STATS_HDR_BHIST"; + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + return "STATS_TL_BG"; + case CAM_ISP_IFE_OUT_RES_STATS_BF: + return "STATS_BF"; + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + return "STATS_AWB_BG"; + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + return "STATS_BHIST"; + case CAM_ISP_IFE_OUT_RES_STATS_RS: + return "STATS_RS"; + case CAM_ISP_IFE_OUT_RES_STATS_CS: + return "STATS_CS"; + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + return "STATS_IHIST"; + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + return "FULL_DISP"; + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + return "DS4_DISP"; + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + return "DS16_DISP"; + case CAM_ISP_IFE_OUT_RES_2PD: + return "2PD"; + case CAM_ISP_IFE_OUT_RES_RDI_RD: + return "RDI_RD"; + case CAM_ISP_IFE_OUT_RES_LCR: + return "LCR"; + default: + return "CAM_ISP_Invalid_Resource_Type"; + } +} + +static uint64_t __cam_isp_ctx_get_event_ts(uint32_t evt_id, void *evt_data) +{ + uint64_t ts = 0; + + if (!evt_data) + return 0; + + switch (evt_id) { + case CAM_ISP_HW_EVENT_ERROR: + ts = ((struct cam_isp_hw_error_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_SOF: + ts = ((struct cam_isp_hw_sof_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_REG_UPDATE: + ts = ((struct cam_isp_hw_reg_update_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_EPOCH: + ts = ((struct cam_isp_hw_epoch_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_EOF: + ts = ((struct cam_isp_hw_eof_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_DONE: + break; + default: + CAM_DBG(CAM_ISP, "Invalid Event Type %d", evt_id); + } + + return ts; +} + +static void __cam_isp_ctx_handle_buf_done_fail_log( + uint64_t request_id, struct cam_isp_ctx_req *req_isp) +{ + int i; + + if (req_isp->num_fence_map_out >= CAM_ISP_CTX_RES_MAX) { + CAM_ERR(CAM_ISP, + "Num Resources exceed mMAX %d >= %d ", + req_isp->num_fence_map_out, CAM_ISP_CTX_RES_MAX); + return; + } + + CAM_ERR(CAM_ISP, + "Prev Req[%lld] : num_out=%d, num_acked=%d, bubble : report=%d, detected=%d", + request_id, req_isp->num_fence_map_out, req_isp->num_acked, + req_isp->bubble_report, req_isp->bubble_detected); + CAM_ERR(CAM_ISP, + "Resource Handles that fail to generate buf_done in prev frame"); + for (i = 0; i < req_isp->num_fence_map_out; i++) { + if (req_isp->fence_map_out[i].sync_id != -1) + CAM_ERR(CAM_ISP, + "Resource_Handle: [%s][0x%x] Sync_ID: [0x%x]", + __cam_isp_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle), + req_isp->fence_map_out[i].resource_handle, + req_isp->fence_map_out[i].sync_id); + } +} + +static int __cam_isp_ctx_handle_buf_done_in_activated_state( + struct cam_isp_context *ctx_isp, + struct cam_isp_hw_done_event_data *done, + uint32_t bubble_state) +{ + int rc = 0; + int i, j; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + uint64_t buf_done_req_id; + + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "Buf done with no active request!"); + goto end; + } + + CAM_DBG(CAM_ISP, "Enter with bubble_state %d", bubble_state); + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + + trace_cam_buf_done("ISP", ctx, req); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + for (i = 0; i < done->num_handles; i++) { + for (j = 0; j < req_isp->num_fence_map_out; j++) { + if (done->resource_handle[i] == + req_isp->fence_map_out[j].resource_handle) + break; + } + + if (j == req_isp->num_fence_map_out) { + CAM_ERR(CAM_ISP, + "Can not find matching lane handle 0x%x!", + done->resource_handle[i]); + rc = -EINVAL; + continue; + } + + if (req_isp->fence_map_out[j].sync_id == -1) { + __cam_isp_ctx_handle_buf_done_fail_log( + req->request_id, req_isp); + continue; + } + + if (!req_isp->bubble_detected) { + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_SUCCESS); + if (rc) + CAM_DBG(CAM_ISP, "Sync failed with rc = %d", + rc); + } else if (!req_isp->bubble_report) { + CAM_ERR(CAM_ISP, + "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc) + CAM_ERR(CAM_ISP, "Sync failed with rc = %d", + rc); + } else { + /* + * Ignore the buffer done if bubble detect is on + * Increment the ack number here, and queue the + * request back to pending list whenever all the + * buffers are done. + */ + req_isp->num_acked++; + CAM_DBG(CAM_ISP, + "buf done with bubble state %d recovery %d", + bubble_state, req_isp->bubble_report); + continue; + } + + CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u", + req->request_id, + req_isp->fence_map_out[j].sync_id, ctx->ctx_id); + if (!rc) { + req_isp->num_acked++; + req_isp->fence_map_out[j].sync_id = -1; + } + } + + if (req_isp->num_acked > req_isp->num_fence_map_out) { + /* Should not happen */ + CAM_ERR(CAM_ISP, + "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u", + req->request_id, req_isp->num_acked, + req_isp->num_fence_map_out, ctx->ctx_id); + WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); + } + + if (req_isp->num_acked != req_isp->num_fence_map_out) + return rc; + + ctx_isp->active_req_cnt--; + buf_done_req_id = req->request_id; + + if (req_isp->bubble_detected && req_isp->bubble_report) { + req_isp->num_acked = 0; + req_isp->bubble_detected = false; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); + + CAM_DBG(CAM_REQ, + "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } else { + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", + buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); +end: + return rc; +} + +static void __cam_isp_ctx_send_sof_boot_timestamp( + struct cam_isp_context *ctx_isp, uint64_t request_id, + uint32_t sof_event_status) +{ + struct cam_req_mgr_message req_msg; + + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; + req_msg.u.frame_msg.request_id = request_id; + req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp; + req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.frame_msg.sof_status = sof_event_status; + + CAM_DBG(CAM_ISP, + "request id:%lld frame number:%lld boot time stamp:0x%llx", + request_id, ctx_isp->frame_id, + ctx_isp->boot_timestamp); + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS, + V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the boot time for req id:%lld", + request_id); +} + + +static void __cam_isp_ctx_send_sof_timestamp( + struct cam_isp_context *ctx_isp, uint64_t request_id, + uint32_t sof_event_status) +{ + struct cam_req_mgr_message req_msg; + + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; + req_msg.u.frame_msg.request_id = request_id; + req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val; + req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.frame_msg.sof_status = sof_event_status; + + CAM_DBG(CAM_ISP, + "request id:%lld frame number:%lld SOF time stamp:0x%llx", + request_id, ctx_isp->frame_id, + ctx_isp->sof_timestamp_val); + CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status); + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the sof time for req id:%lld", + request_id); + + __cam_isp_ctx_send_sof_boot_timestamp(ctx_isp, + request_id, sof_event_status); + +} + +static int __cam_isp_ctx_reg_upd_in_epoch_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + if (ctx_isp->frame_id == 1) + CAM_DBG(CAM_ISP, "Reg update for early PCR"); + else + CAM_WARN(CAM_ISP, + "Unexpected reg update in activated substate:%d for frame_id:%lld", + ctx_isp->substate_activated, ctx_isp->frame_id); + return 0; +} + +static int __cam_isp_ctx_reg_upd_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto end; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + request_id = req->request_id; + CAM_DBG(CAM_REQ, + "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_ISP, + "move active request %lld to free list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } + + /* + * This function only called directly from applied and bubble applied + * state so change substate here. + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, request_id); + +end: + return rc; +} + +static int __cam_isp_ctx_notify_sof_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_req_mgr_trigger_notify notify; + struct cam_context *ctx = ctx_isp->base; + struct cam_ctx_request *req; + uint64_t request_id = 0; + + /* + * notify reqmgr with sof signal. Note, due to scheduling delay + * we can run into situation that two active requests has already + * be in the active queue while we try to do the notification. + * In this case, we need to skip the current notification. This + * helps the state machine to catch up the delay. + */ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); + } + + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_BUBBLE) + request_id = 0; + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, + request_id); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify SOF to CRM for ctx %u", + ctx->ctx_id); + rc = -EFAULT; + } + + return 0; +} + +static int __cam_isp_ctx_notify_eof_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_req_mgr_trigger_notify notify; + struct cam_context *ctx = ctx_isp->base; + + if (!(ctx_isp->subscribe_event & CAM_TRIGGER_POINT_EOF)) + return rc; + + /* notify reqmgr with eof signal */ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_EOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM EOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EOF, 0); + } else { + CAM_ERR(CAM_ISP, "Can not notify EOF to CRM for ctx %u", + ctx->ctx_id); + rc = -EFAULT; + } + + return rc; +} + +static int __cam_isp_ctx_reg_upd_in_hw_error( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + return 0; +} + +static int __cam_isp_ctx_sof_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req = NULL; + struct cam_context *ctx = ctx_isp->base; + uint64_t request_id = 0; + + /* First check if there is a valid request in active list */ + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + break; + } + } + + /* + * If nothing in active list, current request might have not moved + * from wait to active list. This could happen if REG_UPDATE to sw + * is coming immediately after SOF + */ + if (request_id == 0) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + if (req) + request_id = req->request_id; + } + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, request_id); + + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id); + + return rc; +} + +static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) { + CAM_DBG(CAM_ISP, "invalid RUP"); + goto end; + } + + /* + * This is for the first update. The initial setting will + * cause the reg_upd in the first frame. + */ + if (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out == req_isp->num_acked) + list_add_tail(&req->list, &ctx->free_req_list); + else + CAM_ERR(CAM_ISP, + "receive rup in unexpected state"); + } + if (req != NULL) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + /* + * If no wait req in epoch, this is an error case. + * The recovery is to go back to sof state + */ + CAM_ERR(CAM_ISP, "No wait request"); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + /* Send SOF event as empty frame*/ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + goto end; + } + + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + req_isp->bubble_detected = true; + + CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); + if (req_isp->bubble_report && ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_err) { + struct cam_req_mgr_error_notify notify; + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = req->request_id; + notify.error = CRM_KMD_ERR_BUBBLE; + ctx->ctx_crm_intf->notify_err(¬ify); + atomic_set(&ctx_isp->process_bubble, 1); + CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld, ctx %u", + ctx_isp->frame_id, ctx->ctx_id); + } else { + req_isp->bubble_report = 0; + } + + /* + * Always move the request to active list. Let buf done + * function handles the rest. + */ + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + ctx_isp->active_req_cnt++; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + } + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_ERROR); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + CAM_DBG(CAM_ISP, "next substate %d", + ctx_isp->substate_activated); +end: + if (request_id == 0) { + req = list_last_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id); + } else { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, request_id); + } + return 0; +} + + +static int __cam_isp_ctx_buf_done_in_applied(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + return rc; +} + + +static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + if (list_empty(&ctx->active_req_list)) + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + else + CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); + + req = list_last_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + if (req) + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, + req->request_id); + + CAM_DBG(CAM_ISP, "next substate %d", + ctx_isp->substate_activated); + + return rc; +} + +static int __cam_isp_ctx_buf_done_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + return rc; +} + +static int __cam_isp_ctx_buf_done_in_bubble( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); + return rc; +} + +static int __cam_isp_ctx_epoch_in_bubble_applied( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + uint64_t request_id = 0; + + /* + * This means we missed the reg upd ack. So we need to + * transition to BUBBLE state again. + */ + + if (list_empty(&ctx->wait_req_list)) { + /* + * If no pending req in epoch, this is an error case. + * Just go back to the bubble state. + */ + CAM_ERR(CAM_ISP, "No pending request."); + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + goto end; + } + + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + req_isp->bubble_detected = true; + + if (req_isp->bubble_report && ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_err) { + struct cam_req_mgr_error_notify notify; + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = req->request_id; + notify.error = CRM_KMD_ERR_BUBBLE; + ctx->ctx_crm_intf->notify_err(¬ify); + atomic_set(&ctx_isp->process_bubble, 1); + CAM_DBG(CAM_REQ, + "Notify CRM about Bubble req_id %llu frame %lld, ctx %u", + req->request_id, ctx_isp->frame_id, ctx->ctx_id); + } else { + req_isp->bubble_report = 0; + } + + /* + * Always move the request to active list. Let buf done + * function handles the rest. + */ + CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d) ctx %u", + req->request_id, ctx_isp->active_req_cnt); + ctx_isp->active_req_cnt++; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + + if (!req_isp->bubble_report) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_ERROR); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); +end: + req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, + list); + if (req) + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id); + return 0; +} + +static int __cam_isp_ctx_buf_done_in_bubble_applied( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); + + return rc; +} + +static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + uint32_t i = 0; + bool found = 0; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_to_report = NULL; + struct cam_ctx_request *req_to_dump = NULL; + struct cam_ctx_request *req_temp; + struct cam_isp_ctx_req *req_isp = NULL; + struct cam_isp_ctx_req *req_isp_to_report = NULL; + struct cam_req_mgr_error_notify notify; + uint64_t error_request_id; + struct cam_hw_fence_map_entry *fence_map_out = NULL; + struct cam_req_mgr_message req_msg; + + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_error_event_data *error_event_data = + (struct cam_isp_hw_error_event_data *)evt_data; + + uint32_t error_type = error_event_data->error_type; + + CAM_DBG(CAM_ISP, "Enter error_type = %d", error_type); + if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) || + (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW)) + notify.error = CRM_KMD_ERR_OVERFLOW; + + /* + * The error is likely caused by first request on the active list. + * If active list is empty check wait list (maybe error hit as soon + * as RUP and we handle error before RUP. + */ + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, + "handling error with no active request"); + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Error with no active/wait request"); + goto end; + } else { + req_to_dump = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + } + } else { + req_to_dump = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + } + + req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv; + + if (error_event_data->enable_req_dump) + cam_isp_ctx_dump_req(req_isp); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (!req_isp->bubble_report) { + for (i = 0; i < req_isp->num_fence_map_out; i++) { + fence_map_out = + &req_isp->fence_map_out[i]; + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", + req->request_id, + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); + if (req_isp->fence_map_out[i].sync_id != -1) { + rc = cam_sync_signal( + fence_map_out->sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + fence_map_out->sync_id = -1; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + ctx_isp->active_req_cnt--; + } else { + found = 1; + break; + } + } + + if (found) + goto move_to_pending; + + list_for_each_entry_safe(req, req_temp, + &ctx->wait_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (!req_isp->bubble_report) { + for (i = 0; i < req_isp->num_fence_map_out; i++) { + fence_map_out = + &req_isp->fence_map_out[i]; + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", + req->request_id, + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); + if (req_isp->fence_map_out[i].sync_id != -1) { + rc = cam_sync_signal( + fence_map_out->sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + fence_map_out->sync_id = -1; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + ctx_isp->active_req_cnt--; + } else { + found = 1; + break; + } + } + +move_to_pending: + /* + * If bubble recovery is enabled on any request we need to move that + * request and all the subsequent requests to the pending list. + * Note: + * We need to traverse the active list in reverse order and add + * to head of pending list. + * e.g. pending current state: 10, 11 | active current state: 8, 9 + * intermittent for loop iteration- pending: 9, 10, 11 | active: 8 + * final state - pending: 8, 9, 10, 11 | active: NULL + */ + if (found) { + list_for_each_entry_safe_reverse(req, req_temp, + &ctx->active_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + ctx_isp->active_req_cnt--; + } + list_for_each_entry_safe_reverse(req, req_temp, + &ctx->wait_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + ctx_isp->active_req_cnt--; + } + } + +end: + do { + if (list_empty(&ctx->pending_req_list)) { + error_request_id = ctx_isp->last_applied_req_id + 1; + req_isp = NULL; + break; + } + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + error_request_id = ctx_isp->last_applied_req_id; + + if (req_isp->bubble_report) { + req_to_report = req; + req_isp_to_report = req_to_report->req_priv; + break; + } + + for (i = 0; i < req_isp->num_fence_map_out; i++) { + if (req_isp->fence_map_out[i].sync_id != -1) + rc = cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + req_isp->fence_map_out[i].sync_id = -1; + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + + } while (req->request_id < ctx_isp->last_applied_req_id); + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = error_request_id; + + if (req_isp_to_report && req_isp_to_report->bubble_report) { + if (error_event_data->recovery_enabled) + notify.error = CRM_KMD_ERR_BUBBLE; + } else { + notify.error = CRM_KMD_ERR_FATAL; + } + + CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld ctx %u", + error_request_id, ctx_isp->frame_id, ctx->ctx_id); + + ctx->ctx_crm_intf->notify_err(¬ify); + + /* + * Need to send error occurred in KMD + * This will help UMD to take necessary action + * and to dump relevant info + */ + + if (notify.error == CRM_KMD_ERR_OVERFLOW) { + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.err_msg.request_id = error_request_id; + req_msg.u.err_msg.resource_size = 0x0; + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, + V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the error time for req id:%lld ctx %u", + ctx_isp->last_applied_req_id, + ctx->ctx_id); + } + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify ERRROR to CRM for ctx %u", + ctx->ctx_id); + rc = -EFAULT; + } + + CAM_DBG(CAM_ISP, "Exit"); + + return rc; +} + +static int __cam_isp_ctx_fs2_sof_in_sof_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (!(list_empty(&ctx->wait_req_list))) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, request_id); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + +end: + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + struct cam_context *ctx = ctx_isp->base; + int prev_active_req_cnt = 0; + int curr_req_id = 0; + struct cam_ctx_request *req; + + prev_active_req_cnt = ctx_isp->active_req_cnt; + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + if (req) + curr_req_id = req->request_id; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + + if (prev_active_req_cnt == ctx_isp->active_req_cnt + 1) { + if (list_empty(&ctx->wait_req_list) && + list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "No request, move to SOF"); + ctx_isp->substate_activated = + CAM_ISP_CTX_ACTIVATED_SOF; + if (ctx_isp->reported_req_id < curr_req_id) { + ctx_isp->reported_req_id = curr_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + curr_req_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } + } + } + + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_applied( + struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) { + CAM_DBG(CAM_ISP, "invalid RUP"); + goto end; + } + + /* + * This is for the first update. The initial setting will + * cause the reg_upd in the first frame. + */ + if (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out == req_isp->num_acked) + list_add_tail(&req->list, &ctx->free_req_list); + else + CAM_ERR(CAM_ISP, + "receive rup in unexpected state"); + } + if (req != NULL) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto end; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + } + + /* + * This function only called directly from applied and bubble applied + * state so change substate here. + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + if (req_isp->num_fence_map_out != 1) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); +end: + if (req != NULL && !rc) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } + return rc; +} + +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_sof, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_epoch_in_applied, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_epoch, + __cam_isp_ctx_reg_upd_in_epoch_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + NULL, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* Bubble Applied */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_epoch_in_bubble_applied, + NULL, + __cam_isp_ctx_buf_done_in_bubble_applied, + }, + }, + /* HW ERROR */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_hw_error, + NULL, + NULL, + NULL, + }, + }, + /* HALT */ + { + }, +}; + +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_fs2_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_fs2_reg_upd_in_sof, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_notify_eof_in_activated_state, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_fs2_reg_upd_in_applied_state, + __cam_isp_ctx_epoch_in_applied, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_epoch, + __cam_isp_ctx_reg_upd_in_epoch_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + NULL, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* Bubble Applied */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_epoch_in_bubble_applied, + NULL, + __cam_isp_ctx_buf_done_in_bubble_applied, + }, + }, + /* HW ERROR */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_hw_error, + NULL, + NULL, + NULL, + }, + }, + /* HALT */ + { + }, +}; + +static int __cam_isp_ctx_apply_req_in_activated_state( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply, + uint32_t next_state) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_ctx_request *active_req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_ctx_req *active_req_isp; + struct cam_isp_context *ctx_isp = NULL; + struct cam_hw_config_args cfg; + + if (list_empty(&ctx->pending_req_list)) { + CAM_ERR(CAM_ISP, "No available request for Apply id %lld", + apply->request_id); + rc = -EFAULT; + goto end; + } + + /* + * When the pipeline has issue, the requests can be queued up in the + * pipeline. In this case, we should reject the additional request. + * The maximum number of request allowed to be outstanding is 2. + * + */ + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + + if (atomic_read(&ctx_isp->process_bubble)) { + CAM_DBG(CAM_ISP, + "Processing bubble cannot apply Request Id %llu", + apply->request_id); + rc = -EAGAIN; + goto end; + } + + spin_lock_bh(&ctx->lock); + req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + list); + spin_unlock_bh(&ctx->lock); + + /* + * Check whether the request id is matching the tip, if not, this means + * we are in the middle of the error handling. Need to reject this apply + */ + if (req->request_id != apply->request_id) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid Request Id asking %llu existing %llu", + apply->request_id, req->request_id); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u", + req->request_id, ctx_isp->substate_activated, ctx->ctx_id); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (ctx_isp->active_req_cnt >= 2) { + CAM_ERR(CAM_ISP, + "Reject apply request (id %lld) due to congestion(cnt = %d) ctx %u", + req->request_id, + ctx_isp->active_req_cnt, + ctx->ctx_id); + + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->active_req_list)) + active_req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + else + CAM_ERR_RATE_LIMIT(CAM_ISP, + "WARNING: should not happen (cnt = %d) but active_list empty", + ctx_isp->active_req_cnt); + spin_unlock_bh(&ctx->lock); + + if (active_req) { + active_req_isp = + (struct cam_isp_ctx_req *) active_req->req_priv; + __cam_isp_ctx_handle_buf_done_fail_log( + active_req->request_id, active_req_isp); + } + + rc = -EFAULT; + goto end; + } + req_isp->bubble_report = apply->report_if_bubble; + + cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; + cfg.request_id = req->request_id; + cfg.hw_update_entries = req_isp->cfg; + cfg.num_hw_update_entries = req_isp->num_cfg; + cfg.priv = &req_isp->hw_update_data; + cfg.init_packet = 0; + + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration"); + } else { + spin_lock_bh(&ctx->lock); + ctx_isp->substate_activated = next_state; + ctx_isp->last_applied_req_id = apply->request_id; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->wait_req_list); + CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld", + next_state, ctx_isp->last_applied_req_id); + spin_unlock_bh(&ctx->lock); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_apply_req_in_sof( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current substate %d", + ctx_isp->substate_activated); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_APPLIED); + CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + + return rc; +} + +static int __cam_isp_ctx_apply_req_in_epoch( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current substate %d", + ctx_isp->substate_activated); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_APPLIED); + CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + + return rc; +} + +static int __cam_isp_ctx_apply_req_in_bubble( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current substate %d", + ctx_isp->substate_activated); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED); + CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + + return rc; +} + +static int __cam_isp_ctx_flush_req(struct cam_context *ctx, + struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req) +{ + int i, rc, tmp = 0; + uint32_t cancel_req_id_found = 0; + struct cam_ctx_request *req; + struct cam_ctx_request *req_temp; + struct cam_isp_ctx_req *req_isp; + struct list_head flush_list; + struct cam_isp_context *ctx_isp = NULL; + + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + + INIT_LIST_HEAD(&flush_list); + if (list_empty(req_list)) { + CAM_DBG(CAM_ISP, "request list is empty"); + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + CAM_ERR(CAM_ISP, "no request to cancel"); + return -EINVAL; + } else + return 0; + } + + CAM_DBG(CAM_REQ, "Flush [%u] in progress for req_id %llu", + flush_req->type, flush_req->req_id); + list_for_each_entry_safe(req, req_temp, req_list, list) { + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + if (req->request_id != flush_req->req_id) { + continue; + } else { + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + cancel_req_id_found = 1; + __cam_isp_ctx_update_state_monitor_array( + ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH, + req->request_id); + break; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH, req->request_id); + } + + list_for_each_entry_safe(req, req_temp, &flush_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + for (i = 0; i < req_isp->num_fence_map_out; i++) { + if (req_isp->fence_map_out[i].sync_id != -1) { + CAM_DBG(CAM_ISP, "Flush req 0x%llx, fence %d", + req->request_id, + req_isp->fence_map_out[i].sync_id); + rc = cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc) { + tmp = req_isp->fence_map_out[i].sync_id; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "signal fence %d failed", tmp); + } + req_isp->fence_map_out[i].sync_id = -1; + } + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_ISP, + "Flush request id:%lld is not found in the list", + flush_req->req_id); + + return 0; +} + +static int __cam_isp_ctx_flush_req_in_top_state( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + struct cam_isp_context *ctx_isp; + + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + CAM_INFO(CAM_ISP, "Last request id to flush is %lld", + flush_req->req_id); + ctx->last_flush_req = flush_req->req_id; + } + + CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); + + atomic_set(&ctx_isp->process_bubble, 0); + return rc; +} + +static int __cam_isp_ctx_flush_req_in_ready( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + + CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + + /* if nothing is in pending req list, change state to acquire */ + if (list_empty(&ctx->pending_req_list)) + ctx->state = CAM_CTX_ACQUIRED; + spin_unlock_bh(&ctx->lock); + + trace_cam_context_state("ISP", ctx); + + CAM_DBG(CAM_ISP, "Flush request in ready state. next state %d", + ctx->state); + return rc; +} + +static struct cam_ctx_ops + cam_isp_ctx_activated_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_sof, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_epoch, + }, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_bubble, + }, + .irq_ops = NULL, + }, + /* Bubble Applied */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +static struct cam_ctx_ops + cam_isp_ctx_fs2_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_sof, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_epoch, + }, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_bubble, + }, + .irq_ops = NULL, + }, + /* Bubble Applied */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +static int __cam_isp_ctx_rdi_only_sof_in_top_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + uint64_t request_id = 0; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + /* + * notify reqmgr with sof signal. Note, due to scheduling delay + * we can run into situation that two active requests has already + * be in the active queue while we try to do the notification. + * In this case, we need to skip the current notification. This + * helps the state machine to catch up the delay. + */ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + + /* + * It is idle frame with out any applied request id, send + * request id as zero + */ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + } + + if (list_empty(&ctx->active_req_list)) + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + else + CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); + + CAM_DBG(CAM_ISP, "next substate %d", + ctx_isp->substate_activated); + return rc; +} + +static int __cam_isp_ctx_rdi_only_sof_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED; + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + + return 0; +} + +static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + uint64_t request_id = 0; + + /* + * Sof in bubble applied state means, reg update not received. + * before increment frame id and override time stamp value, send + * the previous sof time stamp that got captured in the + * sof in applied state. + */ + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (list_empty(&ctx->wait_req_list)) { + /* + * If no pending req in epoch, this is an error case. + * The recovery is to go back to sof state + */ + CAM_ERR(CAM_ISP, "No wait request"); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + /* Send SOF event as empty frame*/ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + goto end; + } + + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + req_isp->bubble_detected = true; + + CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); + if (req_isp->bubble_report && ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_err) { + struct cam_req_mgr_error_notify notify; + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = req->request_id; + notify.error = CRM_KMD_ERR_BUBBLE; + ctx->ctx_crm_intf->notify_err(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld", + ctx_isp->frame_id); + } else { + req_isp->bubble_report = 0; + } + + /* + * Always move the request to active list. Let buf done + * function handles the rest. + */ + ctx_isp->active_req_cnt++; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + + if (!req_isp->bubble_report) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_ERROR); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + /* change the state to bubble, as reg update has not come */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); +end: + return 0; +} + +static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + uint32_t i; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_isp_ctx_req *req_isp; + uint64_t request_id = 0; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + /* + * Signal all active requests with error and move the all the active + * requests to free list + */ + while (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in active list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + ctx_isp->active_req_cnt--; + } + + /* notify reqmgr with sof signal */ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + + } else { + CAM_ERR(CAM_ISP, "Can not notify SOF to CRM"); + } + + /* + * It is idle frame with out any applied request id, send + * request id as zero + */ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + CAM_DBG(CAM_ISP, "next substate %d", + ctx_isp->substate_activated); + + return 0; +} + +static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + /* notify reqmgr with sof signal*/ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto error; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + request_id = + (req_isp->hw_update_data.packet_opcode_type == + CAM_ISP_PACKET_INIT_DEV) ? + 0 : req->request_id; + + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_ISP, + "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + /* if packet has buffers, set correct request id */ + request_id = req->request_id; + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_ISP, + "move active req %lld to free list(cnt=%d)", + req->request_id, ctx_isp->active_req_cnt); + } + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } else { + CAM_ERR(CAM_ISP, "Can not notify SOF to CRM"); + } + if (request_id) + ctx_isp->reported_req_id = request_id; + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + + return 0; +error: + /* Send SOF event as idle frame*/ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + /* + * There is no request in the pending list, move the sub state machine + * to SOF sub state + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + return 0; +} + +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_rdi_only_activated_state_machine_irq + [CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_rdi_only_sof_in_top_state, + __cam_isp_ctx_reg_upd_in_sof, + NULL, + NULL, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_applied_state, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_top_state, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_epoch, + }, + }, + /* BUBBLE*/ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_bubble_state, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* BUBBLE APPLIED ie PRE_BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_bubble_applied, + __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_bubble_applied, + }, + }, + /* HW ERROR */ + { + }, + /* HALT */ + { + }, +}; + +static int __cam_isp_ctx_rdi_only_apply_req_top_state( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current substate %d", + ctx_isp->substate_activated); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_APPLIED); + CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + + return rc; +} + +static struct cam_ctx_ops + cam_isp_ctx_rdi_only_activated_state_machine + [CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_rdi_only_apply_req_top_state, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_rdi_only_apply_req_top_state, + }, + .irq_ops = NULL, + }, + /* PRE BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, + void *cmd) +{ + int rc = 0; + struct cam_hw_release_args rel_arg; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_req_mgr_flush_request flush_req; + + if (ctx_isp->hw_ctx) { + rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &rel_arg); + ctx_isp->hw_ctx = NULL; + } else { + CAM_ERR(CAM_ISP, "No hw resources acquired for this ctx"); + } + + ctx->last_flush_req = 0; + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->hw_acquired = false; + ctx_isp->init_received = false; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + /* + * Ideally, we should never have any active request here. + * But we still add some sanity check code here to help the debug + */ + if (!list_empty(&ctx->active_req_list)) + CAM_WARN(CAM_ISP, "Active list is not empty"); + + /* Flush all the pending request list */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_ACQUIRED; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); + return rc; +} + +/* top level state machine */ +static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_release_args rel_arg; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_req_mgr_flush_request flush_req; + + if (cmd && ctx_isp->hw_ctx) { + CAM_ERR(CAM_ISP, "releasing hw"); + __cam_isp_ctx_release_hw_in_top_state(ctx, NULL); + } + + if (ctx_isp->hw_ctx) { + rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &rel_arg); + ctx_isp->hw_ctx = NULL; + } + + ctx->session_hdl = -1; + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->hw_acquired = false; + ctx_isp->init_received = false; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + /* + * Ideally, we should never have any active request here. + * But we still add some sanity check code here to help the debug + */ + if (!list_empty(&ctx->active_req_list)) + CAM_ERR(CAM_ISP, "Active list is not empty"); + + /* Flush all the pending request list */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_AVAILABLE; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); + return rc; +} + +static int __cam_isp_ctx_config_dev_in_top_state( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd) +{ + int rc = 0, i; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + uintptr_t packet_addr; + struct cam_packet *packet; + size_t len = 0; + size_t remain_len = 0; + struct cam_hw_prepare_update_args cfg; + struct cam_req_mgr_add_request add_req; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "get free request object......"); + + /* get free request */ + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->free_req_list)) { + req = list_first_entry(&ctx->free_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + } + spin_unlock_bh(&ctx->lock); + + if (!req) { + CAM_ERR(CAM_ISP, "No more request obj free"); + return -ENOMEM; + } + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + /* for config dev, only memory handle is supported */ + /* map packet from the memhandle */ + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Can not get packet address"); + rc = -EINVAL; + goto free_req; + } + + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_ISP, "invalid buff length: %zu or offset", len); + rc = -EINVAL; + goto free_req; + } + + remain_len -= (size_t)cmd->offset; + packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset); + CAM_DBG(CAM_ISP, "pack_handle %llx", cmd->packet_handle); + CAM_DBG(CAM_ISP, "packet address is 0x%zx", packet_addr); + CAM_DBG(CAM_ISP, "packet with length %zu, offset 0x%llx", + len, cmd->offset); + CAM_DBG(CAM_ISP, "Packet request id %lld", + packet->header.request_id); + CAM_DBG(CAM_ISP, "Packet size 0x%x", packet->header.size); + CAM_DBG(CAM_ISP, "packet op %d", packet->header.op_code); + + if ((((packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_UPDATE_DEV) + && (packet->header.request_id <= ctx->last_flush_req)) { + CAM_INFO(CAM_ISP, + "request %lld has been flushed, reject packet", + packet->header.request_id); + rc = -EINVAL; + goto free_req; + } + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.remain_len = remain_len; + cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; + cfg.max_hw_update_entries = CAM_ISP_CTX_CFG_MAX; + cfg.hw_update_entries = req_isp->cfg; + cfg.max_out_map_entries = CAM_ISP_CTX_RES_MAX; + cfg.max_in_map_entries = CAM_ISP_CTX_RES_MAX; + cfg.out_map_entries = req_isp->fence_map_out; + cfg.in_map_entries = req_isp->fence_map_in; + cfg.priv = &req_isp->hw_update_data; + cfg.pf_data = &(req->pf_data); + + CAM_DBG(CAM_ISP, "try to prepare config packet......"); + + rc = ctx->hw_mgr_intf->hw_prepare_update( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Prepare config packet failed in HW layer"); + rc = -EFAULT; + goto free_req; + } + req_isp->num_cfg = cfg.num_hw_update_entries; + req_isp->num_fence_map_out = cfg.num_out_map_entries; + req_isp->num_fence_map_in = cfg.num_in_map_entries; + req_isp->num_acked = 0; + req_isp->bubble_detected = false; + + for (i = 0; i < req_isp->num_fence_map_out; i++) { + rc = cam_sync_get_obj_ref(req_isp->fence_map_out[i].sync_id); + if (rc) { + CAM_ERR(CAM_ISP, "Can't get ref for fence %d", + req_isp->fence_map_out[i].sync_id); + goto put_ref; + } + } + + CAM_DBG(CAM_ISP, "num_entry: %d, num fence out: %d, num fence in: %d", + req_isp->num_cfg, req_isp->num_fence_map_out, + req_isp->num_fence_map_in); + + req->request_id = packet->header.request_id; + req->status = 1; + + CAM_DBG(CAM_ISP, "Packet request id %lld packet opcode:%d", + packet->header.request_id, + req_isp->hw_update_data.packet_opcode_type); + + if (req_isp->hw_update_data.packet_opcode_type == + CAM_ISP_PACKET_INIT_DEV) { + if (ctx->state < CAM_CTX_ACTIVATED) { + rc = __cam_isp_ctx_enqueue_init_request(ctx, req); + if (rc) + CAM_ERR(CAM_ISP, "Enqueue INIT pkt failed"); + ctx_isp->init_received = true; + } else { + rc = -EINVAL; + CAM_ERR(CAM_ISP, "Recevied INIT pkt in wrong state"); + } + } else { + if (ctx->state >= CAM_CTX_READY && ctx->ctx_crm_intf->add_req) { + add_req.link_hdl = ctx->link_hdl; + add_req.dev_hdl = ctx->dev_hdl; + add_req.req_id = req->request_id; + add_req.skip_before_applying = 0; + rc = ctx->ctx_crm_intf->add_req(&add_req); + if (rc) { + CAM_ERR(CAM_ISP, "Add req failed: req id=%llu", + req->request_id); + } else { + __cam_isp_ctx_enqueue_request_in_order( + ctx, req); + } + } else { + rc = -EINVAL; + CAM_ERR(CAM_ISP, "Recevied Update in wrong state"); + } + } + if (rc) + goto put_ref; + + CAM_DBG(CAM_REQ, + "Preprocessing Config req_id %lld successful on ctx %u", + req->request_id, ctx->ctx_id); + + return rc; + +put_ref: + for (--i; i >= 0; i--) { + if (cam_sync_put_obj_ref(req_isp->fence_map_out[i].sync_id)) + CAM_ERR(CAM_CTXT, "Failed to put ref of fence %d", + req_isp->fence_map_out[i].sync_id); + } +free_req: + spin_lock_bh(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + + return rc; +} + +static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_acquire_args param; + struct cam_isp_resource *isp_res = NULL; + struct cam_create_dev_hdl req_hdl_param; + struct cam_hw_release_args release; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_ISP, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_ISP, + "session_hdl 0x%x, num_resources %d, hdl type %d, res %lld", + cmd->session_handle, cmd->num_resources, + cmd->handle_type, cmd->resource_hdl); + + if (cmd->num_resources == CAM_API_COMPAT_CONSTANT) { + ctx_isp->split_acquire = true; + CAM_DBG(CAM_ISP, "Acquire dev handle"); + goto get_dev_handle; + } + + if (cmd->num_resources > CAM_ISP_CTX_RES_MAX) { + CAM_ERR(CAM_ISP, "Too much resources in the acquire"); + rc = -ENOMEM; + goto end; + } + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_ISP, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + isp_res = kzalloc( + sizeof(*isp_res)*cmd->num_resources, GFP_KERNEL); + if (!isp_res) { + rc = -ENOMEM; + goto end; + } + + CAM_DBG(CAM_ISP, "start copy %d resources from user", + cmd->num_resources); + + if (copy_from_user(isp_res, u64_to_user_ptr(cmd->resource_hdl), + sizeof(*isp_res)*cmd->num_resources)) { + rc = -EFAULT; + goto free_res; + } + + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = cmd->num_resources; + param.acquire_info = (uintptr_t) isp_res; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Acquire device failed"); + goto free_res; + } + + /* Query the context has rdi only resource */ + hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_hw; + } + + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { + /* + * this context has rdi only resource assign rdi only + * state machine + */ + CAM_DBG(CAM_ISP, "RDI only session Context"); + + ctx_isp->substate_machine_irq = + cam_isp_ctx_rdi_only_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; + } else { + CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_activated_state_machine; + } + + ctx_isp->hw_ctx = param.ctxt_to_hw_map; + ctx_isp->hw_acquired = true; + ctx_isp->split_acquire = false; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + kfree(isp_res); + isp_res = NULL; + +get_dev_handle: + + req_hdl_param.session_hdl = cmd->session_handle; + /* bridge is not ready for these flags. so false for now */ + req_hdl_param.v4l2_sub_dev_flag = 0; + req_hdl_param.media_entity_flag = 0; + req_hdl_param.ops = ctx->crm_ctx_intf; + req_hdl_param.priv = ctx; + + CAM_DBG(CAM_ISP, "get device handle form bridge"); + ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); + if (ctx->dev_hdl <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_ISP, "Can not create device handle"); + goto free_hw; + } + cmd->dev_handle = ctx->dev_hdl; + + /* store session information */ + ctx->session_hdl = cmd->session_handle; + ctx->state = CAM_CTX_ACQUIRED; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%x num_rsrces %d ctx %u", + cmd->session_handle, cmd->num_resources, ctx->ctx_id); + + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx_isp->hw_ctx; + if (ctx_isp->hw_acquired) + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &release); + ctx_isp->hw_ctx = NULL; + ctx_isp->hw_acquired = false; +free_res: + kfree(isp_res); +end: + return rc; +} + +static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, + void *args) +{ + int rc = 0; + struct cam_acquire_hw_cmd_v1 *cmd = + (struct cam_acquire_hw_cmd_v1 *)args; + struct cam_hw_acquire_args param; + struct cam_hw_release_args release; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_acquire_hw_info *acquire_hw_info = NULL; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_ISP, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_ISP, + "session_hdl 0x%x, hdl type %d, res %lld", + cmd->session_handle, cmd->handle_type, cmd->resource_hdl); + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_ISP, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + if (cmd->data_size < sizeof(*acquire_hw_info)) { + CAM_ERR(CAM_ISP, "data_size is not a valid value"); + goto end; + } + + acquire_hw_info = kzalloc(cmd->data_size, GFP_KERNEL); + if (!acquire_hw_info) { + rc = -ENOMEM; + goto end; + } + + CAM_DBG(CAM_ISP, "start copy resources from user"); + + if (copy_from_user(acquire_hw_info, (void __user *)cmd->resource_hdl, + cmd->data_size)) { + rc = -EFAULT; + goto free_res; + } + + memset(¶m, 0, sizeof(param)); + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = CAM_API_COMPAT_CONSTANT; + param.acquire_info_size = cmd->data_size; + param.acquire_info = (uint64_t) acquire_hw_info; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Acquire device failed"); + goto free_res; + } + + /* Query the context has rdi only resource */ + hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_hw; + } + + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { + /* + * this context has rdi only resource assign rdi only + * state machine + */ + CAM_DBG(CAM_ISP, "RDI only session Context"); + + ctx_isp->substate_machine_irq = + cam_isp_ctx_rdi_only_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; + } else { + CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_activated_state_machine; + } + + ctx_isp->hw_ctx = param.ctxt_to_hw_map; + ctx_isp->hw_acquired = true; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", + ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id); + kfree(acquire_hw_info); + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); + ctx_isp->hw_ctx = NULL; + ctx_isp->hw_acquired = false; +free_res: + kfree(acquire_hw_info); +end: + return rc; +} + +static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, + void *args) +{ + int rc = 0, i, j; + struct cam_acquire_hw_cmd_v2 *cmd = + (struct cam_acquire_hw_cmd_v2 *)args; + struct cam_hw_acquire_args param; + struct cam_hw_release_args release; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_acquire_hw_info *acquire_hw_info = NULL; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_ISP, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_ISP, + "session_hdl 0x%x, hdl type %d, res %lld", + cmd->session_handle, cmd->handle_type, cmd->resource_hdl); + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_ISP, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + if (cmd->data_size < sizeof(*acquire_hw_info)) { + CAM_ERR(CAM_ISP, "data_size is not a valid value"); + goto end; + } + + acquire_hw_info = kzalloc(cmd->data_size, GFP_KERNEL); + if (!acquire_hw_info) { + rc = -ENOMEM; + goto end; + } + + CAM_DBG(CAM_ISP, "start copy resources from user"); + + if (copy_from_user(acquire_hw_info, (void __user *)cmd->resource_hdl, + cmd->data_size)) { + rc = -EFAULT; + goto free_res; + } + + memset(¶m, 0, sizeof(param)); + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = CAM_API_COMPAT_CONSTANT; + param.acquire_info_size = cmd->data_size; + param.acquire_info = (uint64_t) acquire_hw_info; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Acquire device failed"); + goto free_res; + } + + /* Query the context has rdi only resource */ + hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_hw; + } + + if (param.valid_acquired_hw) { + for (i = 0; i < CAM_MAX_ACQ_RES; i++) + cmd->hw_info.acquired_hw_id[i] = + param.acquired_hw_id[i]; + + for (i = 0; i < CAM_MAX_ACQ_RES; i++) + for (j = 0; j < CAM_MAX_HW_SPLIT; j++) + cmd->hw_info.acquired_hw_path[i][j] = + param.acquired_hw_path[i][j]; + } + cmd->hw_info.valid_acquired_hw = + param.valid_acquired_hw; + + cmd->hw_info.valid_acquired_hw = param.valid_acquired_hw; + + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { + /* + * this context has rdi only resource assign rdi only + * state machine + */ + CAM_DBG(CAM_ISP, "RDI only session Context"); + + ctx_isp->substate_machine_irq = + cam_isp_ctx_rdi_only_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; + } else { + CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_activated_state_machine; + } + + ctx_isp->hw_ctx = param.ctxt_to_hw_map; + ctx_isp->hw_acquired = true; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", + ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id); + kfree(acquire_hw_info); + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); + ctx_isp->hw_ctx = NULL; + ctx_isp->hw_acquired = false; +free_res: + kfree(acquire_hw_info); +end: + return rc; +} + + +static int __cam_isp_ctx_acquire_hw_in_acquired(struct cam_context *ctx, + void *args) +{ + int rc = -EINVAL; + uint32_t api_version; + + if (!ctx || !args) { + CAM_ERR(CAM_ISP, "Invalid input pointer"); + return rc; + } + + api_version = *((uint32_t *)args); + if (api_version == 1) + rc = __cam_isp_ctx_acquire_hw_v1(ctx, args); + else if (api_version == 2) + rc = __cam_isp_ctx_acquire_hw_v2(ctx, args); + else + CAM_ERR(CAM_ISP, "Unsupported api version %d", api_version); + + return rc; +} + +static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + if (!ctx_isp->hw_acquired) { + CAM_ERR(CAM_ISP, "HW is not acquired, reject packet"); + return -EINVAL; + } + + rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd); + + if (!rc && (ctx->link_hdl >= 0)) { + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ISP", ctx); + } + + CAM_DBG(CAM_ISP, "next state %d", ctx->state); + return rc; +} + +static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "Enter........."); + + ctx->link_hdl = link->link_hdl; + ctx->ctx_crm_intf = link->crm_cb; + ctx_isp->subscribe_event = link->subscribe_event; + + /* change state only if we had the init config */ + if (ctx_isp->init_received) { + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ISP", ctx); + } + + CAM_DBG(CAM_ISP, "next state %d", ctx->state); + + return rc; +} + +static int __cam_isp_ctx_unlink_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + + return rc; +} + +static int __cam_isp_ctx_get_dev_info_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_device_info *dev_info) +{ + int rc = 0; + + dev_info->dev_hdl = ctx->dev_hdl; + strlcpy(dev_info->name, CAM_ISP_DEV_NAME, sizeof(dev_info->name)); + dev_info->dev_id = CAM_REQ_MGR_DEVICE_IFE; + dev_info->p_delay = 1; + dev_info->trigger = CAM_TRIGGER_POINT_SOF; + + return rc; +} + +static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_isp_start_args start_isp; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + if (cmd->session_handle != ctx->session_hdl || + cmd->dev_handle != ctx->dev_hdl) { + rc = -EPERM; + goto end; + } + + if (list_empty(&ctx->pending_req_list)) { + /* should never happen */ + CAM_ERR(CAM_ISP, "Start device with empty configuration"); + rc = -EFAULT; + goto end; + } else { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + } + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (!ctx_isp->hw_ctx) { + CAM_ERR(CAM_ISP, "Wrong hw context pointer."); + rc = -EFAULT; + goto end; + } + + start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; + start_isp.hw_config.request_id = req->request_id; + start_isp.hw_config.hw_update_entries = req_isp->cfg; + start_isp.hw_config.num_hw_update_entries = req_isp->num_cfg; + start_isp.hw_config.priv = &req_isp->hw_update_data; + start_isp.hw_config.init_packet = 1; + start_isp.start_only = false; + + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->substate_activated = ctx_isp->rdi_only_context ? + CAM_ISP_CTX_ACTIVATED_APPLIED : + (req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH : + CAM_ISP_CTX_ACTIVATED_SOF; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + /* + * Only place to change state before calling the hw due to + * hardware tasklet has higher priority that can cause the + * irq handling comes early + */ + ctx->state = CAM_CTX_ACTIVATED; + trace_cam_context_state("ISP", ctx); + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &start_isp); + if (rc) { + /* HW failure. user need to clean up the resource */ + CAM_ERR(CAM_ISP, "Start HW failed"); + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ISP", ctx); + goto end; + } + CAM_DBG(CAM_ISP, "start device success ctx %u", ctx->ctx_id); + + list_del_init(&req->list); + + if (req_isp->num_fence_map_out) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + } else { + list_add_tail(&req->list, &ctx->wait_req_list); + } +end: + return rc; +} + +static int __cam_isp_ctx_unlink_in_ready(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ISP", ctx); + + return rc; +} + +static int __cam_isp_ctx_stop_dev_in_activated_unlock( + struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd) +{ + int rc = 0; + uint32_t i; + struct cam_hw_stop_args stop; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_isp_stop_args stop_isp; + + /* Mask off all the incoming hardware events */ + spin_lock_bh(&ctx->lock); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + + /* stop hw first */ + if (ctx_isp->hw_ctx) { + stop.ctxt_to_hw_map = ctx_isp->hw_ctx; + + if (stop_cmd) + stop_isp.hw_stop_cmd = + CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; + else + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + + stop_isp.stop_only = false; + stop.args = (void *) &stop_isp; + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop); + } + + while (!list_empty(&ctx->pending_req_list)) { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in pending list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in wait list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in active list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + atomic_set(&ctx_isp->process_bubble, 0); + atomic64_set(&ctx_isp->state_monitor_head, -1); + + CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", + ctx->state, ctx->ctx_id); + + if (!stop_cmd) { + rc = __cam_isp_ctx_unlink_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Unlink failed rc=%d", rc); + } + return rc; +} + +static int __cam_isp_ctx_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *)ctx->ctx_priv; + + __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, cmd); + ctx_isp->init_received = false; + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ISP", ctx); + return rc; +} + +static int __cam_isp_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Stop device failed rc=%d", rc); + + rc = __cam_isp_ctx_release_dev_in_top_state(ctx, cmd); + if (rc) + CAM_ERR(CAM_ISP, "Release device failed rc=%d", rc); + + return rc; +} + +static int __cam_isp_ctx_release_hw_in_activated(struct cam_context *ctx, + void *cmd) +{ + int rc = 0; + + rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Stop device failed rc=%d", rc); + + rc = __cam_isp_ctx_release_hw_in_top_state(ctx, cmd); + if (rc) + CAM_ERR(CAM_ISP, "Release hw failed rc=%d", rc); + + return rc; +} + +static int __cam_isp_ctx_link_pause(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_PAUSE_HW; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + +static int __cam_isp_ctx_link_resume(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_RESUME_HW; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + +static int __cam_isp_ctx_handle_sof_freeze_evt( + struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_SOF_DEBUG; + isp_hw_cmd_args.u.sof_irq_enable = 1; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + +static int __cam_isp_ctx_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *link_evt_data) +{ + int rc = 0; + + switch (link_evt_data->evt_type) { + case CAM_REQ_MGR_LINK_EVT_ERR: + /* No need to handle this message now */ + break; + case CAM_REQ_MGR_LINK_EVT_PAUSE: + __cam_isp_ctx_link_pause(ctx); + break; + case CAM_REQ_MGR_LINK_EVT_RESUME: + __cam_isp_ctx_link_resume(ctx); + break; + case CAM_REQ_MGR_LINK_EVT_SOF_FREEZE: + __cam_isp_ctx_handle_sof_freeze_evt(ctx); + break; + default: + CAM_WARN(CAM_ISP, "Unknown event from CRM"); + break; + } + return rc; +} + +static int __cam_isp_ctx_unlink_in_activated(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + CAM_WARN(CAM_ISP, + "Received unlink in activated state. It's unexpected"); + + rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL); + if (rc) + CAM_WARN(CAM_ISP, "Stop device failed rc=%d", rc); + + rc = __cam_isp_ctx_unlink_in_ready(ctx, unlink); + if (rc) + CAM_ERR(CAM_ISP, "Unlink failed rc=%d", rc); + + return rc; +} + +static int __cam_isp_ctx_apply_req(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_ctx_ops *ctx_ops = NULL; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + trace_cam_apply_req("ISP", apply->request_id); + CAM_DBG(CAM_ISP, "Enter: apply req in Substate %d request _id:%lld", + ctx_isp->substate_activated, apply->request_id); + ctx_ops = &ctx_isp->substate_machine[ctx_isp->substate_activated]; + if (ctx_ops->crm_ops.apply_req) { + rc = ctx_ops->crm_ops.apply_req(ctx, apply); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No handle function in activated substate %d", + ctx_isp->substate_activated); + rc = -EFAULT; + } + + if (rc) + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Apply failed in active substate %d", + ctx_isp->substate_activated); + return rc; +} + + + +static int __cam_isp_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc = 0; + struct cam_isp_ctx_irq_ops *irq_ops = NULL; + struct cam_context *ctx = (struct cam_context *)context; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *)ctx->ctx_priv; + + spin_lock(&ctx->lock); + + trace_cam_isp_activated_irq(ctx, ctx_isp->substate_activated, evt_id, + __cam_isp_ctx_get_event_ts(evt_id, evt_data)); + + CAM_DBG(CAM_ISP, "Enter: State %d, Substate %d, evt id %d", + ctx->state, ctx_isp->substate_activated, evt_id); + irq_ops = &ctx_isp->substate_machine_irq[ctx_isp->substate_activated]; + if (irq_ops->irq_ops[evt_id]) { + rc = irq_ops->irq_ops[evt_id](ctx_isp, evt_data); + } else { + CAM_DBG(CAM_ISP, "No handle function for substate %d", + ctx_isp->substate_activated); + __cam_isp_ctx_dump_state_monitor_array(ctx_isp); + } + + CAM_DBG(CAM_ISP, "Exit: State %d Substate %d", + ctx->state, ctx_isp->substate_activated); + spin_unlock(&ctx->lock); + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_isp_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_isp_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .acquire_hw = __cam_isp_ctx_acquire_hw_in_acquired, + .release_dev = __cam_isp_ctx_release_dev_in_top_state, + .config_dev = __cam_isp_ctx_config_dev_in_acquired, + .release_hw = __cam_isp_ctx_release_hw_in_top_state, + }, + .crm_ops = { + .link = __cam_isp_ctx_link_in_acquired, + .unlink = __cam_isp_ctx_unlink_in_acquired, + .get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired, + .flush_req = __cam_isp_ctx_flush_req_in_top_state, + }, + .irq_ops = NULL, + .pagefault_ops = cam_isp_context_dump_active_request, + }, + /* Ready */ + { + .ioctl_ops = { + .start_dev = __cam_isp_ctx_start_dev_in_ready, + .release_dev = __cam_isp_ctx_release_dev_in_top_state, + .config_dev = __cam_isp_ctx_config_dev_in_top_state, + .release_hw = __cam_isp_ctx_release_hw_in_top_state, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_ready, + .flush_req = __cam_isp_ctx_flush_req_in_ready, + }, + .irq_ops = NULL, + .pagefault_ops = cam_isp_context_dump_active_request, + }, + /* Activated */ + { + .ioctl_ops = { + .stop_dev = __cam_isp_ctx_stop_dev_in_activated, + .release_dev = __cam_isp_ctx_release_dev_in_activated, + .config_dev = __cam_isp_ctx_config_dev_in_top_state, + .release_hw = __cam_isp_ctx_release_hw_in_activated, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_activated, + .apply_req = __cam_isp_ctx_apply_req, + .flush_req = __cam_isp_ctx_flush_req_in_top_state, + .process_evt = __cam_isp_ctx_process_evt, + }, + .irq_ops = __cam_isp_ctx_handle_irq_in_activated, + .pagefault_ops = cam_isp_context_dump_active_request, + }, +}; + + +static int cam_isp_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info) +{ + + struct cam_context *ctx = (struct cam_context *)data; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_temp = NULL; + struct cam_isp_ctx_req *req_isp = NULL; + struct cam_isp_prepare_hw_update_data *hw_update_data = NULL; + struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL; + bool mem_found = false; + int rc = 0; + + struct cam_isp_context *isp_ctx = + (struct cam_isp_context *)ctx->ctx_priv; + + if (!isp_ctx) { + CAM_ERR(CAM_ISP, "Invalid isp ctx"); + return -EINVAL; + } + + CAM_INFO(CAM_ISP, "iommu fault handler for isp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + hw_update_data = &req_isp->hw_update_data; + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ISP, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &mem_found); + if (rc) + CAM_ERR(CAM_ISP, "Failed to dump pf info"); + + if (mem_found) + CAM_ERR(CAM_ISP, "Found page fault in req %lld %d", + req->request_id, rc); + } + + CAM_INFO(CAM_ISP, "Iterating over wait_list of isp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->wait_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + hw_update_data = &req_isp->hw_update_data; + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ISP, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &mem_found); + if (rc) + CAM_ERR(CAM_ISP, "Failed to dump pf info"); + + if (mem_found) + CAM_ERR(CAM_ISP, "Found page fault in req %lld %d", + req->request_id, rc); + } + + return rc; +} + +int cam_isp_context_init(struct cam_isp_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) + +{ + int rc = -1; + int i; + + if (!ctx || !ctx_base) { + CAM_ERR(CAM_ISP, "Invalid Context"); + goto err; + } + + /* ISP context setup */ + memset(ctx, 0, sizeof(*ctx)); + + ctx->base = ctx_base; + ctx->frame_id = 0; + ctx->active_req_cnt = 0; + ctx->reported_req_id = 0; + ctx->hw_ctx = NULL; + ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + ctx->substate_machine = cam_isp_ctx_activated_state_machine; + ctx->substate_machine_irq = cam_isp_ctx_activated_state_machine_irq; + ctx->init_timestamp = jiffies_to_msecs(jiffies); + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + ctx->req_base[i].req_priv = &ctx->req_isp[i]; + ctx->req_isp[i].base = &ctx->req_base[i]; + } + + /* camera context setup */ + rc = cam_context_init(ctx_base, isp_dev_name, CAM_ISP, ctx_id, + crm_node_intf, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_ISP, "Camera Context Base init failed"); + goto err; + } + + /* link camera context with isp context */ + ctx_base->state_machine = cam_isp_ctx_top_state_machine; + ctx_base->ctx_priv = ctx; + + /* initializing current state for error logging */ + for (i = 0; i < CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; i++) { + ctx->cam_isp_ctx_state_monitor[i].curr_state = + CAM_ISP_CTX_ACTIVATED_MAX; + } + atomic64_set(&ctx->state_monitor_head, -1); +err: + return rc; +} + +int cam_isp_context_deinit(struct cam_isp_context *ctx) +{ + int rc = 0; + + if (ctx->base) + cam_context_deinit(ctx->base); + + if (ctx->substate_activated != CAM_ISP_CTX_ACTIVATED_SOF) + CAM_ERR(CAM_ISP, "ISP context substate is invalid"); + + memset(ctx, 0, sizeof(*ctx)); + return rc; +} diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h new file mode 100644 index 000000000000..bbf39b5617cf --- /dev/null +++ b/drivers/cam_isp/cam_isp_context.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_CONTEXT_H_ +#define _CAM_ISP_CONTEXT_H_ + + +#include +#include +#include + +#include "cam_context.h" +#include "cam_isp_hw_mgr_intf.h" + +/* + * Maximum hw resource - This number is based on the maximum + * output port resource. The current maximum resource number + * is 24. + */ +#define CAM_ISP_CTX_RES_MAX 24 + +/* + * Maximum configuration entry size - This is based on the + * worst case DUAL IFE use case plus some margin. + */ +#define CAM_ISP_CTX_CFG_MAX 22 + +/* + * Maximum entries in state monitoring array for error logging + */ +#define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES 40 + +/* forward declaration */ +struct cam_isp_context; + +/* cam isp context irq handling function type */ +typedef int (*cam_isp_hw_event_cb_func)(struct cam_isp_context *ctx_isp, + void *evt_data); + +/** + * enum cam_isp_ctx_activated_substate - sub states for activated + * + */ +enum cam_isp_ctx_activated_substate { + CAM_ISP_CTX_ACTIVATED_SOF, + CAM_ISP_CTX_ACTIVATED_APPLIED, + CAM_ISP_CTX_ACTIVATED_EPOCH, + CAM_ISP_CTX_ACTIVATED_BUBBLE, + CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED, + CAM_ISP_CTX_ACTIVATED_HW_ERROR, + CAM_ISP_CTX_ACTIVATED_HALT, + CAM_ISP_CTX_ACTIVATED_MAX, +}; + +/** + * enum cam_isp_state_change_trigger - Different types of ISP events + * + */ +enum cam_isp_state_change_trigger { + CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, + CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, + CAM_ISP_STATE_CHANGE_TRIGGER_DONE, + CAM_ISP_STATE_CHANGE_TRIGGER_EOF, + CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH, + CAM_ISP_STATE_CHANGE_TRIGGER_MAX +}; + +/** + * struct cam_isp_ctx_irq_ops - Function table for handling IRQ callbacks + * + * @irq_ops: Array of handle function pointers. + * + */ +struct cam_isp_ctx_irq_ops { + cam_isp_hw_event_cb_func irq_ops[CAM_ISP_HW_EVENT_MAX]; +}; + +/** + * struct cam_isp_ctx_req - ISP context request object + * + * @base: Common request object ponter + * @cfg: ISP hardware configuration array + * @num_cfg: Number of ISP hardware configuration entries + * @fence_map_out: Output fence mapping array + * @num_fence_map_out: Number of the output fence map + * @fence_map_in: Input fence mapping array + * @num_fence_map_in: Number of input fence map + * @num_acked: Count to track acked entried for output. + * If count equals the number of fence out, it means + * the request has been completed. + * @bubble_report: Flag to track if bubble report is active on + * current request + * @hw_update_data: HW update data for this request + * + */ +struct cam_isp_ctx_req { + struct cam_ctx_request *base; + + struct cam_hw_update_entry cfg[CAM_ISP_CTX_CFG_MAX]; + uint32_t num_cfg; + struct cam_hw_fence_map_entry fence_map_out + [CAM_ISP_CTX_RES_MAX]; + uint32_t num_fence_map_out; + struct cam_hw_fence_map_entry fence_map_in[CAM_ISP_CTX_RES_MAX]; + uint32_t num_fence_map_in; + uint32_t num_acked; + int32_t bubble_report; + struct cam_isp_prepare_hw_update_data hw_update_data; + bool bubble_detected; +}; + +/** + * struct cam_isp_context_state_monitor - ISP context state + * monitoring for + * debug purposes + * + * @curr_state: Current sub state that received req + * @trigger: Event type of incoming req + * @req_id: Request id + * @frame_id: Frame id based on SOFs + * @evt_time_stamp Current time stamp + * + */ +struct cam_isp_context_state_monitor { + enum cam_isp_ctx_activated_substate curr_state; + enum cam_isp_state_change_trigger trigger; + uint64_t req_id; + int64_t frame_id; + unsigned int evt_time_stamp; +}; + +/** + * struct cam_isp_context - ISP context object + * + * @base: Common context object pointer + * @frame_id: Frame id tracking for the isp context + * @substate_actiavted: Current substate for the activated state. + * @process_bubble: Atomic variable to check if ctx is still + * processing bubble. + * @substate_machine: ISP substate machine for external interface + * @substate_machine_irq: ISP substate machine for irq handling + * @req_base: Common request object storage + * @req_isp: ISP private request object storage + * @hw_ctx: HW object returned by the acquire device command + * @sof_timestamp_val: Captured time stamp value at sof hw event + * @boot_timestamp: Boot time stamp for a given req_id + * @active_req_cnt: Counter for the active request + * @reported_req_id: Last reported request id + * @subscribe_event: The irq event mask that CRM subscribes to, IFE + * will invoke CRM cb at those event. + * @last_applied_req_id: Last applied request id + * @state_monitor_head: Write index to the state monitoring array + * @cam_isp_ctx_state_monitor: State monitoring array + * @rdi_only_context: Get context type information. + * true, if context is rdi only context + * @hw_acquired: Indicate whether HW resources are acquired + * @init_received: Indicate whether init config packet is received + * @split_acquire: Indicate whether a separate acquire is expected + * @init_timestamp: Timestamp at which this context is initialized + * + */ +struct cam_isp_context { + struct cam_context *base; + + int64_t frame_id; + uint32_t substate_activated; + atomic_t process_bubble; + struct cam_ctx_ops *substate_machine; + struct cam_isp_ctx_irq_ops *substate_machine_irq; + + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; + + void *hw_ctx; + uint64_t sof_timestamp_val; + uint64_t boot_timestamp; + int32_t active_req_cnt; + int64_t reported_req_id; + uint32_t subscribe_event; + int64_t last_applied_req_id; + atomic64_t state_monitor_head; + struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; + bool rdi_only_context; + bool hw_acquired; + bool init_received; + bool split_acquire; + unsigned int init_timestamp; +}; + +/** + * cam_isp_context_init() + * + * @brief: Initialization function for the ISP context + * + * @ctx: ISP context obj to be initialized + * @bridge_ops: Bridge call back funciton + * @hw_intf: ISP hw manager interface + * @ctx_id: ID for this context + * + */ +int cam_isp_context_init(struct cam_isp_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *bridge_ops, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); + +/** + * cam_isp_context_deinit() + * + * @brief: Deinitialize function for the ISP context + * + * @ctx: ISP context obj to be deinitialized + * + */ +int cam_isp_context_deinit(struct cam_isp_context *ctx); + + +#endif /* __CAM_ISP_CONTEXT_H__ */ diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c new file mode 100644 index 000000000000..b93ae3fd5b82 --- /dev/null +++ b/drivers/cam_isp/cam_isp_dev.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "cam_isp_dev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_node.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +static struct cam_isp_dev g_isp_dev; + +static void cam_isp_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_ISP, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static const struct of_device_id cam_isp_dt_match[] = { + { + .compatible = "qcom,cam-isp" + }, + {} +}; + +static int cam_isp_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + mutex_lock(&g_isp_dev.isp_mutex); + g_isp_dev.open_cnt++; + mutex_unlock(&g_isp_dev.isp_mutex); + + return 0; +} + +static int cam_isp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_node *node = v4l2_get_subdevdata(sd); + + mutex_lock(&g_isp_dev.isp_mutex); + if (g_isp_dev.open_cnt <= 0) { + CAM_DBG(CAM_ISP, "ISP subdev is already closed"); + rc = -EINVAL; + goto end; + } + + g_isp_dev.open_cnt--; + if (!node) { + CAM_ERR(CAM_ISP, "Node ptr is NULL"); + rc = -EINVAL; + goto end; + } + + if (g_isp_dev.open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&g_isp_dev.isp_mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_isp_subdev_internal_ops = { + .close = cam_isp_subdev_close, + .open = cam_isp_subdev_open, +}; + +static int cam_isp_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + int i; + + /* clean up resources */ + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_isp_context_deinit(&g_isp_dev.ctx_isp[i]); + if (rc) + CAM_ERR(CAM_ISP, "ISP context %d deinit failed", + i); + } + + rc = cam_subdev_remove(&g_isp_dev.sd); + if (rc) + CAM_ERR(CAM_ISP, "Unregister failed"); + + memset(&g_isp_dev, 0, sizeof(g_isp_dev)); + return 0; +} + +static int cam_isp_dev_probe(struct platform_device *pdev) +{ + int rc = -1; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + int iommu_hdl = -1; + + g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops; + /* Initialize the v4l2 subdevice first. (create cam_node) */ + rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, + CAM_IFE_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_ISP, "ISP cam_subdev_probe failed!"); + goto err; + } + node = (struct cam_node *) g_isp_dev.sd.token; + + memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf)); + rc = cam_isp_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf, &iommu_hdl); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Can not initialized ISP HW manager!"); + goto unregister; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_isp_context_init(&g_isp_dev.ctx_isp[i], + &g_isp_dev.ctx[i], + &node->crm_node_intf, + &node->hw_mgr_intf, + i); + if (rc) { + CAM_ERR(CAM_ISP, "ISP context init failed!"); + goto unregister; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_isp_dev.ctx, CAM_CTX_MAX, + CAM_ISP_DEV_NAME); + if (rc) { + CAM_ERR(CAM_ISP, "ISP node init failed!"); + goto unregister; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_isp_dev_iommu_fault_handler, node); + + mutex_init(&g_isp_dev.isp_mutex); + + CAM_INFO(CAM_ISP, "Camera ISP probe complete"); + + return 0; +unregister: + rc = cam_subdev_remove(&g_isp_dev.sd); +err: + return rc; +} + + +static struct platform_driver isp_driver = { + .probe = cam_isp_dev_probe, + .remove = cam_isp_dev_remove, + .driver = { + .name = "cam_isp", + .owner = THIS_MODULE, + .of_match_table = cam_isp_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_isp_dev_init_module(void) +{ + return platform_driver_register(&isp_driver); +} + +static void __exit cam_isp_dev_exit_module(void) +{ + platform_driver_unregister(&isp_driver); +} + +module_init(cam_isp_dev_init_module); +module_exit(cam_isp_dev_exit_module); +MODULE_DESCRIPTION("MSM ISP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/cam_isp_dev.h b/drivers/cam_isp/cam_isp_dev.h new file mode 100644 index 000000000000..cf9140eb8c88 --- /dev/null +++ b/drivers/cam_isp/cam_isp_dev.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_DEV_H_ +#define _CAM_ISP_DEV_H_ + +#include "cam_subdev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_context.h" +#include "cam_isp_context.h" + +/** + * struct cam_isp_dev - Camera ISP V4l2 device node + * + * @sd: Commone camera subdevice node + * @ctx: Isp base context storage + * @ctx_isp: Isp private context storage + * @isp_mutex: ISP dev mutex + * @open_cnt: Open device count + */ +struct cam_isp_dev { + struct cam_subdev sd; + struct cam_context ctx[CAM_CTX_MAX]; + struct cam_isp_context ctx_isp[CAM_CTX_MAX]; + struct mutex isp_mutex; + int32_t open_cnt; +}; + +#endif /* __CAM_ISP_DEV_H__ */ diff --git a/drivers/cam_isp/isp_hw_mgr/Makefile b/drivers/cam_isp/isp_hw_mgr/Makefile new file mode 100644 index 000000000000..33b808c934e3 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += hw_utils/ isp_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o cam_ife_hw_mgr.o diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c new file mode 100644 index 000000000000..cb0b341b981f --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -0,0 +1,6280 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_smmu_api.h" +#include "cam_req_mgr_workq.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_vfe_hw_intf.h" +#include "cam_isp_packet_parser.h" +#include "cam_ife_hw_mgr.h" +#include "cam_cdm_intf_api.h" +#include "cam_packet_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_mem_mgr_api.h" +#include "cam_common_util.h" + +#define CAM_IFE_HW_ENTRIES_MAX 20 + +#define TZ_SVC_SMMU_PROGRAM 0x15 +#define TZ_SAFE_SYSCALL_ID 0x3 +#define CAM_IFE_SAFE_DISABLE 0 +#define CAM_IFE_SAFE_ENABLE 1 +#define SMMU_SE_IFE 0 + +#define CAM_ISP_PACKET_META_MAX \ + (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) + +#define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ + (CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 + 1) + +static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { + CAM_ISP_HW_CMD_GET_HFR_UPDATE, + CAM_ISP_HW_CMD_CLOCK_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE, + CAM_ISP_HW_CMD_UBWC_UPDATE, + CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG, + CAM_ISP_HW_CMD_UBWC_UPDATE_V2, + CAM_ISP_HW_CMD_CORE_CONFIG, + CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE_V2, +}; + +static struct cam_ife_hw_mgr g_ife_hw_mgr; + +static int cam_ife_hw_mgr_event_handler( + void *priv, + uint32_t evt_id, + void *evt_info); + +static int cam_ife_notify_safe_lut_scm(bool safe_trigger) +{ + uint32_t camera_hw_version, rc = 0; + struct scm_desc desc = {0}; + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (!rc) { + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_175_V100: + + desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); + desc.args[0] = SMMU_SE_IFE; + desc.args[1] = safe_trigger; + + CAM_DBG(CAM_ISP, "Safe scm call %d", safe_trigger); + if (scm_call2(SCM_SIP_FNID(TZ_SVC_SMMU_PROGRAM, + TZ_SAFE_SYSCALL_ID), &desc)) { + CAM_ERR(CAM_ISP, + "scm call to Enable Safe failed"); + rc = -EINVAL; + } + break; + default: + break; + } + } + + return rc; +} + +static int cam_ife_mgr_get_hw_caps(void *hw_mgr_priv, + void *hw_caps_args) +{ + int rc = 0; + int i; + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query = hw_caps_args; + struct cam_isp_query_cap_cmd query_isp; + + CAM_DBG(CAM_ISP, "enter"); + + if (copy_from_user(&query_isp, + u64_to_user_ptr(query->caps_handle), + sizeof(struct cam_isp_query_cap_cmd))) { + rc = -EFAULT; + return rc; + } + + query_isp.device_iommu.non_secure = hw_mgr->mgr_common.img_iommu_hdl; + query_isp.device_iommu.secure = hw_mgr->mgr_common.img_iommu_hdl_secure; + query_isp.cdm_iommu.non_secure = hw_mgr->mgr_common.cmd_iommu_hdl; + query_isp.cdm_iommu.secure = hw_mgr->mgr_common.cmd_iommu_hdl_secure; + query_isp.num_dev = 2; + for (i = 0; i < query_isp.num_dev; i++) { + query_isp.dev_caps[i].hw_type = CAM_ISP_HW_IFE; + query_isp.dev_caps[i].hw_version.major = 1; + query_isp.dev_caps[i].hw_version.minor = 7; + query_isp.dev_caps[i].hw_version.incr = 0; + query_isp.dev_caps[i].hw_version.reserved = 0; + } + + if (copy_to_user(u64_to_user_ptr(query->caps_handle), + &query_isp, sizeof(struct cam_isp_query_cap_cmd))) + rc = -EFAULT; + + CAM_DBG(CAM_ISP, "exit rc :%d", rc); + + return rc; +} + +static int cam_ife_hw_mgr_is_rdi_res(uint32_t res_id) +{ + int rc = 0; + + switch (res_id) { + case CAM_ISP_IFE_OUT_RES_RDI_0: + case CAM_ISP_IFE_OUT_RES_RDI_1: + case CAM_ISP_IFE_OUT_RES_RDI_2: + case CAM_ISP_IFE_OUT_RES_RDI_3: + rc = 1; + break; + default: + break; + } + + return rc; +} + +static int cam_ife_hw_mgr_reset_csid_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + int rc = 0; + struct cam_hw_intf *hw_intf; + struct cam_csid_reset_cfg_args csid_reset_args; + + csid_reset_args.reset_type = CAM_IFE_CSID_RESET_PATH; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + csid_reset_args.node_res = isp_hw_res->hw_res[i]; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + CAM_DBG(CAM_ISP, "Resetting csid hardware %d", + hw_intf->hw_idx); + if (hw_intf->hw_ops.reset) { + rc = hw_intf->hw_ops.reset(hw_intf->hw_priv, + &csid_reset_args, + sizeof(struct cam_csid_reset_cfg_args)); + if (rc <= 0) + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "RESET HW res failed: (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static int cam_ife_hw_mgr_init_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + int rc = -1; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + CAM_DBG(CAM_ISP, "enabled vfe hardware %d", + hw_intf->hw_idx); + if (hw_intf->hw_ops.init) { + rc = hw_intf->hw_ops.init(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "INIT HW res failed: (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static int cam_ife_hw_mgr_start_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res, + struct cam_ife_hw_mgr_ctx *ctx) +{ + int i; + int rc = -1; + struct cam_hw_intf *hw_intf; + + /* Start slave (which is right split) first */ + for (i = CAM_ISP_HW_SPLIT_MAX - 1; i >= 0; i--) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.start) { + isp_hw_res->hw_res[i]->rdi_only_ctx = + ctx->is_rdi_only_context; + rc = hw_intf->hw_ops.start(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start HW resources"); + goto err; + } + CAM_DBG(CAM_ISP, "Start HW %d Res %d", hw_intf->hw_idx, + isp_hw_res->hw_res[i]->res_id); + } else { + CAM_ERR(CAM_ISP, "function null"); + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "Start hw res failed (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static void cam_ife_hw_mgr_stop_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + struct cam_hw_intf *hw_intf; + uint32_t dummy_args; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.stop) + hw_intf->hw_ops.stop(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + else + CAM_ERR(CAM_ISP, "stop null"); + if (hw_intf->hw_ops.process_cmd && + isp_hw_res->res_type == CAM_IFE_HW_MGR_RES_IFE_OUT) { + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, + &dummy_args, sizeof(dummy_args)); + } + } +} + +static void cam_ife_hw_mgr_deinit_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.deinit) + hw_intf->hw_ops.deinit(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + } +} + +static void cam_ife_hw_mgr_deinit_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int i = 0; + + if (!ctx->init_done) { + CAM_WARN(CAM_ISP, "ctx is not in init state"); + return; + } + + /* Deinit IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE CSID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deint IFE MUX(SRC) */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deint IFE RD */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE OUT */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); + + ctx->init_done = false; +} + +static int cam_ife_hw_mgr_init_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int rc = 0, i; + + CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d", + ctx->ctx_index); + /* INIT IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d", + ctx->ctx_index); + + /* INIT IFE csid */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + /* INIT IFE SRC */ + CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + /* INIT IFE BUS RD */ + CAM_DBG(CAM_ISP, "INIT IFE BUS RD in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not IFE BUS RD (%d)", + hw_mgr_res->res_id); + return rc; + } + } + + /* INIT IFE OUT */ + CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", + ctx->ctx_index); + + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)", + ctx->res_list_ife_out[i].res_id); + goto deinit; + } + } + + return rc; +deinit: + ctx->init_done = true; + cam_ife_hw_mgr_deinit_hw(ctx); + return rc; +} + +static int cam_ife_hw_mgr_put_res( + struct list_head *src_list, + struct cam_ife_hw_mgr_res **res) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *res_ptr = NULL; + + res_ptr = *res; + if (res_ptr) + list_add_tail(&res_ptr->list, src_list); + + return rc; +} + +static int cam_ife_hw_mgr_get_res( + struct list_head *src_list, + struct cam_ife_hw_mgr_res **res) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *res_ptr = NULL; + + if (!list_empty(src_list)) { + res_ptr = list_first_entry(src_list, + struct cam_ife_hw_mgr_res, list); + list_del_init(&res_ptr->list); + } else { + CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx"); + rc = -1; + } + *res = res_ptr; + + return rc; +} + +static int cam_ife_hw_mgr_free_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int rc = 0; + int i; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.release) { + rc = hw_intf->hw_ops.release(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) + CAM_ERR(CAM_ISP, + "Release hw resource id %d failed", + isp_hw_res->res_id); + isp_hw_res->hw_res[i] = NULL; + } else + CAM_ERR(CAM_ISP, "Release null"); + } + /* caller should make sure the resource is in a list */ + list_del_init(&isp_hw_res->list); + memset(isp_hw_res, 0, sizeof(*isp_hw_res)); + INIT_LIST_HEAD(&isp_hw_res->list); + + return 0; +} + +static int cam_ife_mgr_csid_stop_hw( + struct cam_ife_hw_mgr_ctx *ctx, struct list_head *stop_list, + uint32_t base_idx, uint32_t stop_cmd) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *isp_res; + struct cam_isp_resource_node *stop_res[CAM_IFE_PIX_PATH_RES_MAX - 1]; + struct cam_csid_hw_stop_args stop; + struct cam_hw_intf *hw_intf; + uint32_t i, cnt; + + cnt = 0; + list_for_each_entry(hw_mgr_res, stop_list, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + isp_res = hw_mgr_res->hw_res[i]; + if (isp_res->hw_intf->hw_idx != base_idx) + continue; + CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u", + base_idx, isp_res->res_id, cnt); + stop_res[cnt] = isp_res; + cnt++; + } + } + + if (cnt) { + hw_intf = stop_res[0]->hw_intf; + stop.num_res = cnt; + stop.node_res = stop_res; + stop.stop_cmd = stop_cmd; + hw_intf->hw_ops.stop(hw_intf->hw_priv, &stop, sizeof(stop)); + } + + return 0; +} + +static int cam_ife_hw_mgr_release_hw_for_ctx( + struct cam_ife_hw_mgr_ctx *ife_ctx) +{ + uint32_t i; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp; + + /* ife leaf resource */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_out[i]); + + /* ife bus rd resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife source resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife csid resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_csid, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife cid resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_cid, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife root node */ + if (ife_ctx->res_list_ife_in.res_type != CAM_IFE_HW_MGR_RES_UNINIT) + cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_in); + + /* clean up the callback function */ + ife_ctx->common.cb_priv = NULL; + memset(ife_ctx->common.event_cb, 0, sizeof(ife_ctx->common.event_cb)); + + CAM_DBG(CAM_ISP, "release context completed ctx id:%d", + ife_ctx->ctx_index); + + return 0; +} + + +static int cam_ife_hw_mgr_put_ctx( + struct list_head *src_list, + struct cam_ife_hw_mgr_ctx **ife_ctx) +{ + int rc = 0; + struct cam_ife_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + ctx_ptr = *ife_ctx; + if (ctx_ptr) + list_add_tail(&ctx_ptr->list, src_list); + *ife_ctx = NULL; + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + return rc; +} + +static int cam_ife_hw_mgr_get_ctx( + struct list_head *src_list, + struct cam_ife_hw_mgr_ctx **ife_ctx) +{ + int rc = 0; + struct cam_ife_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + if (!list_empty(src_list)) { + ctx_ptr = list_first_entry(src_list, + struct cam_ife_hw_mgr_ctx, list); + list_del_init(&ctx_ptr->list); + } else { + CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx"); + rc = -1; + } + *ife_ctx = ctx_ptr; + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + + return rc; +} + +static void cam_ife_mgr_add_base_info( + struct cam_ife_hw_mgr_ctx *ctx, + enum cam_isp_hw_split_id split_id, + uint32_t base_idx) +{ + uint32_t i; + + if (!ctx->num_base) { + ctx->base[0].split_id = split_id; + ctx->base[0].idx = base_idx; + ctx->num_base++; + CAM_DBG(CAM_ISP, + "Add split id = %d for base idx = %d num_base=%d", + split_id, base_idx, ctx->num_base); + } else { + /*Check if base index already exists in the list */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == base_idx) { + if (split_id != CAM_ISP_HW_SPLIT_MAX && + ctx->base[i].split_id == + CAM_ISP_HW_SPLIT_MAX) + ctx->base[i].split_id = split_id; + + break; + } + } + + if (i == ctx->num_base) { + ctx->base[ctx->num_base].split_id = split_id; + ctx->base[ctx->num_base].idx = base_idx; + ctx->num_base++; + CAM_DBG(CAM_ISP, + "Add split_id=%d for base idx=%d num_base=%d", + split_id, base_idx, ctx->num_base); + } + } +} + +static int cam_ife_mgr_process_base_info( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res = NULL; + uint32_t i; + + if (list_empty(&ctx->res_list_ife_src)) { + CAM_ERR(CAM_ISP, "Mux List empty"); + return -ENODEV; + } + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + cam_ife_mgr_add_base_info(ctx, i, + res->hw_intf->hw_idx); + CAM_DBG(CAM_ISP, "add base info for hw %d", + res->hw_intf->hw_idx); + } + } + CAM_DBG(CAM_ISP, "ctx base num = %d", ctx->num_base); + + return 0; +} + +static int cam_ife_hw_mgr_acquire_res_bus_rd( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_ife_hw_mgr_res *ife_in_rd_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *ife_src_res; + int i; + + CAM_DBG(CAM_ISP, "Enter"); + + list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { + if (ife_src_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_in_rd_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd, + &ife_in_rd_res); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.priv = ife_ctx; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!ife_src_res->hw_res[i]) + continue; + + hw_intf = ife_src_res->hw_res[i]->hw_intf; + if (i == CAM_ISP_HW_SPLIT_LEFT) { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_LEFT; + if (ife_src_res->is_dual_vfe) { + /*TBD */ + vfe_acquire.vfe_out.is_master = 1; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } else { + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + 0; + } + } else { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_RIGHT; + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire out resource 0x%x", + vfe_acquire.rsrc_type); + goto err; + } + + ife_in_rd_res->hw_res[i] = + vfe_acquire.vfe_out.rsrc_node; + CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", + ife_in_rd_res->hw_res[i]->res_type, + ife_in_rd_res->hw_res[i]->res_id); + + } + ife_in_rd_res->is_dual_vfe = in_port->usage_type; + ife_in_rd_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_VFE_BUS_RD; + } + + return 0; +err: + CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc); + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_ife_hw_mgr_res *ife_src_res, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_isp_out_port_generic_info *out_port = NULL; + struct cam_ife_hw_mgr_res *ife_out_res; + struct cam_hw_intf *hw_intf; + uint32_t i, vfe_out_res_id, vfe_in_res_id; + + /* take left resource */ + vfe_in_res_id = ife_src_res->hw_res[0]->res_id; + + switch (vfe_in_res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_0; + break; + case CAM_ISP_HW_VFE_IN_RDI1: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_1; + break; + case CAM_ISP_HW_VFE_IN_RDI2: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_2; + break; + case CAM_ISP_HW_VFE_IN_RDI3: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_3; + break; + default: + CAM_ERR(CAM_ISP, "invalid resource type"); + goto err; + } + CAM_DBG(CAM_ISP, "vfe_in_res_id = %d, vfe_out_red_id = %d", + vfe_in_res_id, vfe_out_res_id); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + + ife_out_res = &ife_ctx->res_list_ife_out[vfe_out_res_id & 0xFF]; + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + + CAM_DBG(CAM_ISP, "i = %d, vfe_out_res_id = %d, out_port: %d", + i, vfe_out_res_id, out_port->res_type); + + if (vfe_out_res_id != out_port->res_type) + continue; + + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.priv = ife_ctx; + vfe_acquire.vfe_out.out_port_info = out_port; + vfe_acquire.vfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.vfe_out.is_dual = 0; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + hw_intf = ife_src_res->hw_res[0]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, "Can not acquire out resource 0x%x", + out_port->res_type); + goto err; + } + break; + } + + if (i == in_port->num_out_res) { + CAM_ERR(CAM_ISP, + "Cannot acquire out resource, i=%d, num_out_res=%d", + i, in_port->num_out_res); + goto err; + } + + ife_out_res->hw_res[0] = vfe_acquire.vfe_out.rsrc_node; + ife_out_res->is_dual_vfe = 0; + ife_out_res->res_id = vfe_out_res_id; + ife_out_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_VFE_OUT; + ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); + + return 0; +err: + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_ife_hw_mgr_res *ife_src_res, + struct cam_isp_in_port_generic_info *in_port, + bool acquire_lcr) +{ + int rc = -1; + uint32_t i, j, k; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_isp_out_port_generic_info *out_port; + struct cam_ife_hw_mgr_res *ife_out_res; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + k = out_port->res_type & 0xFF; + if (k >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "invalid output resource type 0x%x", + out_port->res_type); + continue; + } + + if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + continue; + + if ((acquire_lcr && + out_port->res_type != CAM_ISP_IFE_OUT_RES_LCR) || + (!acquire_lcr && + out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR)) + continue; + + if ((out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD && + ife_src_res->res_id != CAM_ISP_HW_VFE_IN_PDLIB) || + (ife_src_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB && + out_port->res_type != CAM_ISP_IFE_OUT_RES_2PD)) + continue; + + CAM_DBG(CAM_ISP, "res_type 0x%x", out_port->res_type); + + ife_out_res = &ife_ctx->res_list_ife_out[k]; + ife_out_res->is_dual_vfe = in_port->usage_type; + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.priv = ife_ctx; + vfe_acquire.vfe_out.out_port_info = out_port; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!ife_src_res->hw_res[j]) + continue; + + hw_intf = ife_src_res->hw_res[j]->hw_intf; + + if (j == CAM_ISP_HW_SPLIT_LEFT) { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_LEFT; + if (ife_src_res->is_dual_vfe) { + /*TBD */ + vfe_acquire.vfe_out.is_master = 1; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } else { + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + 0; + } + } else { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_RIGHT; + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire out resource 0x%x", + out_port->res_type); + goto err; + } + + ife_out_res->hw_res[j] = + vfe_acquire.vfe_out.rsrc_node; + CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", + ife_out_res->hw_res[j]->res_type, + ife_out_res->hw_res[j]->res_id); + + } + ife_out_res->res_type = + (enum cam_ife_hw_mgr_res_type)CAM_ISP_RESOURCE_VFE_OUT; + ife_out_res->res_id = out_port->res_type; + ife_out_res->parent = ife_src_res; + ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); + } + + return 0; +err: + /* release resource at the entry function */ + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_out( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + struct cam_ife_hw_mgr_res *ife_src_res; + + list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { + if (ife_src_res->num_children) + continue; + + switch (ife_src_res->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_RD: + rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx, + ife_src_res, in_port, false); + break; + case CAM_ISP_HW_VFE_IN_LCR: + rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx, + ife_src_res, in_port, true); + break; + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + rc = cam_ife_hw_mgr_acquire_res_ife_out_rdi(ife_ctx, + ife_src_res, in_port); + break; + default: + CAM_ERR(CAM_ISP, "Unknown IFE SRC resource: %d", + ife_src_res->res_id); + break; + } + if (rc) + goto err; + } + + return 0; +err: + /* release resource on entry function */ + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_rd_src( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -1; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + int vfe_idx = -1, i = 0; + + ife_hw_mgr = ife_ctx->hw_mgr; + + CAM_DBG(CAM_ISP, "Enter"); + list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) { + if (csid_res->res_id != CAM_IFE_PIX_PATH_RES_RDI_0) { + CAM_DBG(CAM_ISP, "not RDI0: %d", csid_res->res_id); + continue; + } + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, + &ife_src_res); + + CAM_DBG(CAM_ISP, "csid_res_id %d", csid_res->res_id); + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RD; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + + ife_src_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_id = vfe_acquire.vfe_in.res_id; + ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + + hw_intf = + ife_hw_mgr->ife_devices[csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx]; + + vfe_idx = csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx; + + /* + * fill in more acquire information as needed + */ + if (ife_src_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT] = + vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_type, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_id); + + if (!ife_src_res->is_dual_vfe) + goto acq; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + CAM_DBG(CAM_ISP, "vfe_idx %d is acquired", + vfe_idx); + continue; + } + + hw_intf = ife_hw_mgr->ife_devices[i]; + + /* fill in more acquire information as needed */ + if (i == CAM_ISP_HW_SPLIT_RIGHT) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[i]->res_type, + ife_src_res->hw_res[i]->res_id); + } +acq: + /* + * It should be one to one mapping between + * csid resource and ife source resource + */ + csid_res->child[0] = ife_src_res; + ife_src_res->parent = csid_res; + csid_res->child[csid_res->num_children++] = ife_src_res; + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", + csid_res->res_id, csid_res->num_children, + ife_src_res->res_id); + } + +err: + /* release resource at the entry function */ + CAM_DBG(CAM_ISP, "Exit rc %d", rc); + return rc; +} + +static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx) +{ + if (hw_idx == 0) + return CAM_ISP_IFE0_HW; + else if (hw_idx == 1) + return CAM_ISP_IFE1_HW; + else if (hw_idx == 2) + return CAM_ISP_IFE0_LITE_HW; + else if (hw_idx == 3) + return CAM_ISP_IFE1_LITE_HW; + else if (hw_idx == 4) + return CAM_ISP_IFE2_LITE_HW; + return 0; +} + +static int cam_convert_res_id_to_hw_path(int path, bool acquire_lcr) +{ + if (path == CAM_IFE_PIX_PATH_RES_IPP && acquire_lcr) + return CAM_ISP_LCR_PATH; + else if (path == CAM_IFE_PIX_PATH_RES_PPP) + return CAM_ISP_PPP_PATH; + else if (path == CAM_IFE_PIX_PATH_RES_IPP) + return CAM_ISP_PXL_PATH; + else if (path == CAM_IFE_PIX_PATH_RES_RDI_0) + return CAM_ISP_RDI0_PATH; + else if (path == CAM_IFE_PIX_PATH_RES_RDI_1) + return CAM_ISP_RDI1_PATH; + else if (path == CAM_IFE_PIX_PATH_RES_RDI_2) + return CAM_ISP_RDI2_PATH; + else if (path == CAM_IFE_PIX_PATH_RES_RDI_3) + return CAM_ISP_RDI3_PATH; + return 0; +} + +static int cam_ife_hw_mgr_acquire_res_ife_src( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + bool acquire_lcr, uint32_t *acquired_hw_id, + uint32_t *acquired_hw_path) +{ + int rc = -1; + int i; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + + ife_hw_mgr = ife_ctx->hw_mgr; + + list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) { + if (csid_res->num_children && !acquire_lcr) + continue; + + if (acquire_lcr && csid_res->res_id != CAM_IFE_PIX_PATH_RES_IPP) + continue; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, + &ife_src_res); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.priv = ife_ctx; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + + switch (csid_res->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (!acquire_lcr) + vfe_acquire.vfe_in.res_id = + CAM_ISP_HW_VFE_IN_CAMIF; + else + vfe_acquire.vfe_in.res_id = + CAM_ISP_HW_VFE_IN_LCR; + if (csid_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + else + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_NONE; + + break; + case CAM_IFE_PIX_PATH_RES_PPP: + vfe_acquire.vfe_in.res_id = + CAM_ISP_HW_VFE_IN_PDLIB; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI0; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_IFE_PIX_PATH_RES_RDI_1: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI1; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_IFE_PIX_PATH_RES_RDI_2: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI2; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_IFE_PIX_PATH_RES_RDI_3: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI3; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + default: + CAM_ERR(CAM_ISP, "Wrong IFE CSID Resource Node"); + goto err; + } + ife_src_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_id = vfe_acquire.vfe_in.res_id; + ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!csid_res->hw_res[i]) + continue; + + hw_intf = ife_hw_mgr->ife_devices[ + csid_res->hw_res[i]->hw_intf->hw_idx]; + + /* fill in more acquire information as needed */ + /* slave Camif resource, */ + if (i == CAM_ISP_HW_SPLIT_RIGHT && + ife_src_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + + *acquired_hw_id |= + cam_convert_hw_idx_to_ife_hw_num( + hw_intf->hw_idx); + + if (i >= CAM_MAX_HW_SPLIT) { + CAM_ERR(CAM_ISP, "HW split is invalid: %d", i); + return -EINVAL; + } + + acquired_hw_path[i] |= cam_convert_res_id_to_hw_path( + ife_src_res->hw_res[i]->res_id, acquire_lcr); + + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[i]->res_type, + ife_src_res->hw_res[i]->res_id); + + } + + ife_src_res->parent = csid_res; + csid_res->child[csid_res->num_children++] = ife_src_res; + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", + csid_res->res_id, csid_res->num_children, + ife_src_res->res_id); + } + + return 0; +err: + /* release resource at the entry function */ + return rc; +} + +static int cam_ife_mgr_acquire_cid_res( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + struct cam_ife_hw_mgr_res **cid_res, + enum cam_ife_pix_path_res_id path_res_id) +{ + int rc = -1; + int i, j; + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *cid_res_temp, *cid_res_iterator; + struct cam_csid_hw_reserve_resource_args csid_acquire; + uint32_t acquired_cnt = 0; + struct cam_isp_out_port_generic_info *out_port = NULL; + + ife_hw_mgr = ife_ctx->hw_mgr; + *cid_res = NULL; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, cid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + cid_res_temp = *cid_res; + + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + csid_acquire.res_id = path_res_id; + CAM_DBG(CAM_ISP, "path_res_id %d", path_res_id); + + if (in_port->num_out_res) + out_port = &(in_port->data[0]); + + /* Try acquiring CID resource from previously acquired HW */ + list_for_each_entry(cid_res_iterator, &ife_ctx->res_list_ife_cid, + list) { + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!cid_res_iterator->hw_res[i]) + continue; + + if (in_port->num_out_res && + ((cid_res_iterator->is_secure == 1 && + out_port->secure_mode == 0) || + (cid_res_iterator->is_secure == 0 && + out_port->secure_mode == 1))) + continue; + + if (!in_port->num_out_res && + cid_res_iterator->is_secure == 1) + continue; + + hw_intf = cid_res_iterator->hw_res[i]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_DBG(CAM_ISP, + "No ife cid resource from hw %d", + hw_intf->hw_idx); + continue; + } + + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + + CAM_DBG(CAM_ISP, + "acquired from old csid(%s)=%d CID rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); + + if (in_port->usage_type && acquired_cnt == 1 && + path_res_id == CAM_IFE_PIX_PATH_RES_IPP) + /* + * Continue to acquire Right for IPP. + * Dual IFE for RDI and PPP is not currently + * supported. + */ + + continue; + + if (acquired_cnt) + /* + * If successfully acquired CID from + * previously acquired HW, skip the next + * part + */ + goto acquire_successful; + } + } + + /* Acquire Left if not already acquired */ + if (ife_ctx->is_fe_enable) { + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } + } else { + for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + if (i == -1 || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } + } + + +acquire_successful: + CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", + in_port->usage_type); + + cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID; + /* CID(DT_ID) value of acquire device, require for path */ + cid_res_temp->res_id = csid_acquire.node_res->res_id; + cid_res_temp->is_dual_vfe = in_port->usage_type; + ife_ctx->is_dual = (bool)in_port->usage_type; + + if (in_port->num_out_res) + cid_res_temp->is_secure = out_port->secure_mode; + + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, cid_res); + + /* + * Acquire Right if not already acquired. + * Dual IFE for RDI and PPP is not currently supported. + */ + if (cid_res_temp->is_dual_vfe && path_res_id + == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) { + csid_acquire.node_res = NULL; + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + for (j = 0; j < CAM_IFE_CSID_HW_NUM_MAX; j++) { + if (!ife_hw_mgr->csid_devices[j]) + continue; + + if (j == cid_res_temp->hw_res[0]->hw_intf->hw_idx) + continue; + + hw_intf = ife_hw_mgr->csid_devices[j]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else + break; + } + + if (j == CAM_IFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, + "Can not acquire ife csid rdi resource"); + goto end; + } + cid_res_temp->hw_res[1] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d", + in_port->usage_type); + } + cid_res_temp->parent = &ife_ctx->res_list_ife_in; + ife_ctx->res_list_ife_in.child[ + ife_ctx->res_list_ife_in.num_children++] = cid_res_temp; + CAM_DBG(CAM_ISP, "IFE IN num_children = %d", + ife_ctx->res_list_ife_in.num_children); + + return 0; +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, cid_res); +end: + return rc; + +} + +static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + bool is_ipp, + bool crop_enable) +{ + int rc = -1; + int i; + int master_idx = -1; + + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *cid_res; + struct cam_hw_intf *hw_intf; + struct cam_csid_hw_reserve_resource_args csid_acquire; + enum cam_ife_pix_path_res_id path_res_id; + + ife_hw_mgr = ife_ctx->hw_mgr; + /* get cid resource */ + if (is_ipp) + path_res_id = CAM_IFE_PIX_PATH_RES_IPP; + else + path_res_id = CAM_IFE_PIX_PATH_RES_PPP; + + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, + path_res_id); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); + goto end; + } + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + csid_res->res_type = + (enum cam_ife_hw_mgr_res_type)CAM_ISP_RESOURCE_PIX_PATH; + + csid_res->res_id = path_res_id; + + if (in_port->usage_type && is_ipp) + csid_res->is_dual_vfe = 1; + else { + csid_res->is_dual_vfe = 0; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + } + + CAM_DBG(CAM_ISP, "CSID Acq: E"); + /* IPP resource needs to be from same HW as CID resource */ + for (i = 0; i <= csid_res->is_dual_vfe; i++) { + CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe); + + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = path_res_id; + csid_acquire.cid = cid_res->hw_res[i]->res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = in_port->data; + csid_acquire.node_res = NULL; + csid_acquire.crop_enable = crop_enable; + + hw_intf = cid_res->hw_res[i]->hw_intf; + + if (csid_res->is_dual_vfe) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + master_idx = hw_intf->hw_idx; + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + } else { + if (master_idx == -1) { + CAM_ERR(CAM_ISP, + "No Master found"); + goto put_res; + } + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + csid_acquire.master_idx = master_idx; + } + } + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_ERR(CAM_ISP, + "Cannot acquire ife csid pxl path rsrc %s", + (is_ipp) ? "IPP" : "PPP"); + goto put_res; + } + + csid_res->hw_res[i] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, + "acquired csid(%s)=%d pxl path rsrc %s successfully", + (i == 0) ? "left" : "right", hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP"); + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = csid_res; + + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); + return 0; +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: + return rc; +} + +static enum cam_ife_pix_path_res_id + cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + uint32_t out_port_type) +{ + enum cam_ife_pix_path_res_id path_id; + CAM_DBG(CAM_ISP, "out_port_type %x", out_port_type); + + switch (out_port_type) { + case CAM_ISP_IFE_OUT_RES_RDI_0: + path_id = CAM_IFE_PIX_PATH_RES_RDI_0; + break; + case CAM_ISP_IFE_OUT_RES_RDI_1: + path_id = CAM_IFE_PIX_PATH_RES_RDI_1; + break; + case CAM_ISP_IFE_OUT_RES_RDI_2: + path_id = CAM_IFE_PIX_PATH_RES_RDI_2; + break; + case CAM_ISP_IFE_OUT_RES_RDI_3: + path_id = CAM_IFE_PIX_PATH_RES_RDI_3; + break; + default: + path_id = CAM_IFE_PIX_PATH_RES_MAX; + CAM_DBG(CAM_ISP, "maximum rdi output type exceeded"); + break; + } + + CAM_DBG(CAM_ISP, "out_port %x path_id %d", out_port_type, path_id); + + return path_id; +} + +static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + int i; + + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *cid_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_out_port_generic_info *out_port; + struct cam_csid_hw_reserve_resource_args csid_acquire; + enum cam_ife_pix_path_res_id path_res_id; + + ife_hw_mgr = ife_ctx->hw_mgr; + + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + path_res_id = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + out_port->res_type); + if (path_res_id == CAM_IFE_PIX_PATH_RES_MAX) + continue; + + /* get cid resource */ + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, + path_res_id); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); + goto end; + } + + /* For each RDI we need CID + PATH resource */ + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &csid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + memset(&csid_acquire, 0, sizeof(csid_acquire)); + csid_acquire.res_id = path_res_id; + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.cid = cid_res->hw_res[0]->res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = out_port; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + csid_acquire.node_res = NULL; + + /* Enable RDI crop for single ife use case only */ + if (in_port->usage_type) + csid_acquire.crop_enable = false; + else + csid_acquire.crop_enable = true; + + hw_intf = cid_res->hw_res[0]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_ERR(CAM_ISP, + "CSID Path reserve failed hw=%d rc=%d cid=%d", + hw_intf->hw_idx, rc, + cid_res->hw_res[0]->res_id); + + goto put_res; + } + + if (csid_acquire.node_res == NULL) { + CAM_ERR(CAM_ISP, "Acquire CSID RDI rsrc failed"); + + goto put_res; + } + + csid_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_id = csid_acquire.res_id; + csid_res->is_dual_vfe = 0; + csid_res->hw_res[0] = csid_acquire.node_res; + csid_res->hw_res[1] = NULL; + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = + csid_res; + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + } + + return 0; +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_root( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -1; + + if (ife_ctx->res_list_ife_in.res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + /* first acquire */ + ife_ctx->res_list_ife_in.res_type = CAM_IFE_HW_MGR_RES_ROOT; + ife_ctx->res_list_ife_in.res_id = in_port->res_type; + ife_ctx->res_list_ife_in.is_dual_vfe = in_port->usage_type; + } else if ((ife_ctx->res_list_ife_in.res_id != + in_port->res_type) && (!ife_ctx->is_fe_enable)) { + CAM_ERR(CAM_ISP, "No Free resource for this context"); + goto err; + } else { + /* else do nothing */ + } + return 0; +err: + /* release resource in entry function */ + return rc; +} + +static int cam_ife_mgr_check_and_update_fe_v0( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + int i; + struct cam_isp_in_port_info *in_port = NULL; + uint32_t in_port_length = 0; + uint32_t total_in_port_length = 0; + + in_port = (struct cam_isp_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || + (in_port->num_out_res <= 0)) { + CAM_ERR(CAM_ISP, "Invalid num output res %u", + in_port->num_out_res); + return -EINVAL; + } + + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + total_in_port_length += in_port_length; + + if (total_in_port_length > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + return -EINVAL; + } + CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, + in_port->res_type); + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_ctx->is_fe_enable = true; + break; + } + + in_port = (struct cam_isp_in_port_info *)((uint8_t *)in_port + + in_port_length); + } + CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + + return 0; +} + +static int cam_ife_mgr_check_and_update_fe_v2( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + int i; + struct cam_isp_in_port_info_v2 *in_port = NULL; + uint32_t in_port_length = 0; + uint32_t total_in_port_length = 0; + + in_port = (struct cam_isp_in_port_info_v2 *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || + (in_port->num_out_res <= 0)) { + CAM_ERR(CAM_ISP, "Invalid num output res %u", + in_port->num_out_res); + return -EINVAL; + } + + in_port_length = sizeof(struct cam_isp_in_port_info_v2) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info_v2); + total_in_port_length += in_port_length; + + if (total_in_port_length > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + return -EINVAL; + } + CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, + in_port->res_type); + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_ctx->is_fe_enable = true; + break; + } + + in_port = (struct cam_isp_in_port_info_v2 *) + ((uint8_t *)in_port + in_port_length); + } + CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + + return 0; +} + +static int cam_ife_mgr_check_and_update_fe( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + uint32_t major_ver = 0, minor_ver = 0; + + if (acquire_hw_info == NULL || ife_ctx == NULL) + return -EINVAL; + + major_ver = (acquire_hw_info->common_info_version >> 12) & 0xF; + minor_ver = (acquire_hw_info->common_info_version) & 0xFFF; + + switch (major_ver) { + case 1: + return cam_ife_mgr_check_and_update_fe_v0( + ife_ctx, acquire_hw_info); + case 2: + return cam_ife_mgr_check_and_update_fe_v2( + ife_ctx, acquire_hw_info); + break; + default: + CAM_ERR(CAM_ISP, "Invalid ver of common info from user"); + return -EINVAL; + } + + return 0; +} + +static int cam_ife_hw_mgr_preprocess_port( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + int *ipp_count, + int *rdi_count, + int *ppp_count, + int *ife_rd_count, + int *lcr_count) +{ + int ipp_num = 0; + int rdi_num = 0; + int ppp_num = 0; + int ife_rd_num = 0; + int lcr_num = 0; + uint32_t i; + struct cam_isp_out_port_generic_info *out_port; + struct cam_ife_hw_mgr *ife_hw_mgr; + + ife_hw_mgr = ife_ctx->hw_mgr; + + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_rd_num++; + } else { + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + rdi_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) + ppp_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR) + lcr_num++; + else { + CAM_DBG(CAM_ISP, "out_res_type %d", + out_port->res_type); + ipp_num++; + } + } + } + + *ipp_count = ipp_num; + *rdi_count = rdi_num; + *ppp_count = ppp_num; + *ife_rd_count = ife_rd_num; + *lcr_count = lcr_num; + + CAM_DBG(CAM_ISP, "rdi: %d ipp: %d ppp: %d ife_rd: %d lcr: %d", + rdi_num, ipp_num, ppp_num, ife_rd_num, lcr_num); + + return 0; +} + +static int cam_ife_mgr_acquire_hw_for_ctx( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + uint32_t *num_pix_port, uint32_t *num_rdi_port, + uint32_t *acquired_hw_id, uint32_t *acquired_hw_path) +{ + int rc = -1; + int is_dual_vfe = 0; + int ipp_count = 0; + int rdi_count = 0; + int ppp_count = 0; + int ife_rd_count = 0; + int lcr_count = 0; + bool crop_enable = true; + + is_dual_vfe = in_port->usage_type; + + /* get root node resource */ + rc = cam_ife_hw_mgr_acquire_res_root(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, "Can not acquire csid rx resource"); + goto err; + } + + cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count, + &rdi_count, &ppp_count, &ife_rd_count, &lcr_count); + + if (!ipp_count && !rdi_count && !ppp_count && !ife_rd_count + && !lcr_count) { + CAM_ERR(CAM_ISP, + "No PIX or RDI or PPP or IFE RD or LCR resource"); + return -EINVAL; + } + + if (ipp_count || lcr_count) { + /* get ife csid IPP resource */ + rc = cam_ife_hw_mgr_acquire_res_ife_csid_pxl(ife_ctx, + in_port, true, crop_enable); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CSID IPP/LCR resource Failed"); + goto err; + } + } + + if (rdi_count) { + /* get ife csid RDI resource */ + rc = cam_ife_hw_mgr_acquire_res_ife_csid_rdi(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CSID RDI resource Failed"); + goto err; + } + } + + if (ppp_count) { + /* get ife csid PPP resource */ + + /* If both IPP and PPP paths are requested with the same vc dt + * it is implied that the sensor is a type 3 PD sensor. Crop + * must be enabled for this sensor on PPP path as well. + */ + if (!ipp_count) + crop_enable = false; + + rc = cam_ife_hw_mgr_acquire_res_ife_csid_pxl(ife_ctx, + in_port, false, crop_enable); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CSID PPP resource Failed"); + goto err; + } + } + + /* get ife src resource */ + if (ife_rd_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_rd_src(ife_ctx, in_port); + rc = cam_ife_hw_mgr_acquire_res_bus_rd(ife_ctx, in_port); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE RD SRC resource Failed"); + goto err; + } + } else if (ipp_count || ppp_count || rdi_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, + in_port, false, + acquired_hw_id, acquired_hw_path); + + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE IPP/PPP SRC resource Failed"); + goto err; + } + } + + if (lcr_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port, true, + acquired_hw_id, acquired_hw_path); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE LCR SRC resource Failed"); + goto err; + } + } + + CAM_DBG(CAM_ISP, "Acquiring IFE OUT resource..."); + rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed"); + goto err; + } + + *num_pix_port += ipp_count + ppp_count + ife_rd_count + lcr_count; + *num_rdi_port += rdi_count; + + return 0; +err: + /* release resource at the acquire entry funciton */ + return rc; +} + +void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + + if (!userdata) { + CAM_ERR(CAM_ISP, "Invalid args"); + return; + } + + ctx = userdata; + + if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + complete(&ctx->config_done_complete); + CAM_DBG(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", + handle, userdata, status, cookie, ctx->ctx_index); + } else { + CAM_WARN(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); + } +} + +static int cam_ife_mgr_acquire_get_unified_structure_v0( + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t offset, uint32_t *input_size, + struct cam_isp_in_port_generic_info **in_port) +{ + struct cam_isp_in_port_info *in = NULL; + uint32_t in_port_length = 0; + struct cam_isp_in_port_generic_info *port_info = NULL; + int32_t rc = 0, i; + + in = (struct cam_isp_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset + *input_size); + + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + + *input_size += in_port_length; + + if ((*input_size) > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "Input is not proper"); + rc = -EINVAL; + } + + port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), GFP_KERNEL); + + if (!port_info) + return -ENOMEM; + + port_info->major_ver = + (acquire_hw_info->input_info_version >> 16) & 0xFFFF; + port_info->minor_ver = + acquire_hw_info->input_info_version & 0xFFFF; + port_info->res_type = in->res_type; + port_info->lane_type = in->lane_type; + port_info->lane_num = in->lane_num; + port_info->lane_cfg = in->lane_cfg; + port_info->vc[0] = in->vc; + port_info->dt[0] = in->dt; + port_info->num_valid_vc_dt = 1; + port_info->format = in->format; + port_info->test_pattern = in->test_pattern; + port_info->usage_type = in->usage_type; + port_info->left_start = in->left_start; + port_info->left_stop = in->left_stop; + port_info->left_width = in->left_width; + port_info->right_start = in->right_start; + port_info->right_stop = in->right_stop; + port_info->right_width = in->right_width; + port_info->line_start = in->line_start; + port_info->line_stop = in->line_stop; + port_info->height = in->height; + port_info->pixel_clk = in->pixel_clk; + port_info->batch_size = in->batch_size; + port_info->dsp_mode = in->dsp_mode; + port_info->hbi_cnt = in->hbi_cnt; + port_info->cust_node = 0; + port_info->num_out_res = in->num_out_res; + + port_info->data = kcalloc(in->num_out_res, + sizeof(struct cam_isp_out_port_generic_info), + GFP_KERNEL); + if (port_info->data == NULL) { + rc = -ENOMEM; + goto release_port_mem; + } + + for (i = 0; i < in->num_out_res; i++) { + port_info->data[i].res_type = in->data[i].res_type; + port_info->data[i].format = in->data[i].format; + port_info->data[i].width = in->data[i].width; + port_info->data[i].height = in->data[i].height; + port_info->data[i].comp_grp_id = in->data[i].comp_grp_id; + port_info->data[i].split_point = in->data[i].split_point; + port_info->data[i].secure_mode = in->data[i].secure_mode; + port_info->data[i].reserved = in->data[i].reserved; + } + *in_port = port_info; + + return 0; +release_port_mem: + kfree(port_info); + return rc; +} + +static int cam_ife_mgr_acquire_get_unified_structure_v2( + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t offset, uint32_t *input_size, + struct cam_isp_in_port_generic_info **in_port) +{ + struct cam_isp_in_port_info_v2 *in = NULL; + uint32_t in_port_length = 0; + struct cam_isp_in_port_generic_info *port_info = NULL; + int32_t rc = 0, i; + + in = (struct cam_isp_in_port_info_v2 *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset + *input_size); + + in_port_length = sizeof(struct cam_isp_in_port_info_v2) + + (in->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info_v2); + + *input_size += in_port_length; + + if ((*input_size) > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "Input is not proper"); + rc = -EINVAL; + } + + port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), GFP_KERNEL); + + if (!port_info) + return -ENOMEM; + + port_info->major_ver = + (acquire_hw_info->input_info_version >> 16) & 0xFFFF; + port_info->minor_ver = + acquire_hw_info->input_info_version & 0xFFFF; + port_info->res_type = in->res_type; + port_info->lane_type = in->lane_type; + port_info->lane_num = in->lane_num; + port_info->lane_cfg = in->lane_cfg; + port_info->num_valid_vc_dt = in->num_valid_vc_dt; + + if (port_info->num_valid_vc_dt == 0 || + port_info->num_valid_vc_dt >= CAM_ISP_VC_DT_CFG) { + CAM_ERR(CAM_ISP, "Invalid i/p arg invalid vc-dt: %d", + in->num_valid_vc_dt); + rc = -EINVAL; + goto release_mem; + } + + for (i = 0; i < port_info->num_valid_vc_dt; i++) { + port_info->vc[i] = in->vc[i]; + port_info->dt[i] = in->dt[i]; + } + + port_info->format = in->format; + port_info->test_pattern = in->test_pattern; + port_info->usage_type = in->usage_type; + port_info->left_start = in->left_start; + port_info->left_stop = in->left_stop; + port_info->left_width = in->left_width; + port_info->right_start = in->right_start; + port_info->right_stop = in->right_stop; + port_info->right_width = in->right_width; + port_info->line_start = in->line_start; + port_info->line_stop = in->line_stop; + port_info->height = in->height; + port_info->pixel_clk = in->pixel_clk; + port_info->batch_size = in->batch_size; + port_info->dsp_mode = in->dsp_mode; + port_info->hbi_cnt = in->hbi_cnt; + port_info->cust_node = in->cust_node; + port_info->num_out_res = in->num_out_res; + + port_info->data = kcalloc(in->num_out_res, + sizeof(struct cam_isp_out_port_generic_info), + GFP_KERNEL); + if (port_info->data == NULL) { + rc = -ENOMEM; + goto release_mem; + } + + for (i = 0; i < port_info->num_out_res; i++) { + port_info->data[i].res_type = in->data[i].res_type; + port_info->data[i].format = in->data[i].format; + port_info->data[i].width = in->data[i].width; + port_info->data[i].height = in->data[i].height; + port_info->data[i].comp_grp_id = in->data[i].comp_grp_id; + port_info->data[i].split_point = in->data[i].split_point; + port_info->data[i].secure_mode = in->data[i].secure_mode; + } + + *in_port = port_info; + + return 0; + +release_mem: + kfree(port_info); + return rc; +} + +static int cam_ife_mgr_acquire_get_unified_structure( + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t offset, uint32_t *input_size, + struct cam_isp_in_port_generic_info **in_port) +{ + uint32_t major_ver = 0, minor_ver = 0; + + if (acquire_hw_info == NULL || input_size == NULL) + return -EINVAL; + + major_ver = (acquire_hw_info->common_info_version >> 12) & 0xF; + minor_ver = (acquire_hw_info->common_info_version) & 0xFFF; + + switch (major_ver) { + case 1: + return cam_ife_mgr_acquire_get_unified_structure_v0( + acquire_hw_info, offset, input_size, in_port); + case 2: + return cam_ife_mgr_acquire_get_unified_structure_v2( + acquire_hw_info, offset, input_size, in_port); + break; + default: + CAM_ERR(CAM_ISP, "Invalid ver of i/p port info from user"); + return -EINVAL; + } + + return 0; +} + +/* entry function: acquire_hw */ +static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) +{ + struct cam_ife_hw_mgr *ife_hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -1; + int i, j; + struct cam_ife_hw_mgr_ctx *ife_ctx; + struct cam_isp_in_port_generic_info *in_port = NULL; + struct cam_cdm_acquire_data cdm_acquire; + uint32_t num_pix_port_per_in = 0; + uint32_t num_rdi_port_per_in = 0; + uint32_t total_pix_port = 0; + uint32_t total_rdi_port = 0; + struct cam_isp_acquire_hw_info *acquire_hw_info = NULL; + uint32_t input_size = 0; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + /* get the ife ctx */ + rc = cam_ife_hw_mgr_get_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); + if (rc || !ife_ctx) { + CAM_ERR(CAM_ISP, "Get ife hw context failed"); + goto err; + } + + ife_ctx->common.cb_priv = acquire_args->context_data; + for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++) + ife_ctx->common.event_cb[i] = acquire_args->event_cb; + + ife_ctx->hw_mgr = ife_hw_mgr; + + + memcpy(cdm_acquire.identifier, "ife", sizeof("ife")); + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ife_ctx; + cdm_acquire.base_array_cnt = CAM_IFE_HW_NUM_MAX; + for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (ife_hw_mgr->cdm_reg_map[i]) + cdm_acquire.base_array[j++] = + ife_hw_mgr->cdm_reg_map[i]; + } + cdm_acquire.base_array_cnt = j; + + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback; + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire the CDM HW"); + goto free_ctx; + } + + CAM_DBG(CAM_ISP, "Successfully acquired the CDM HW hdl=%x", + cdm_acquire.handle); + ife_ctx->cdm_handle = cdm_acquire.handle; + ife_ctx->cdm_ops = cdm_acquire.ops; + + acquire_hw_info = + (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; + + rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info); + if (rc) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + goto free_cdm; + } + + /* acquire HW resources */ + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + rc = cam_ife_mgr_acquire_get_unified_structure(acquire_hw_info, + i, &input_size, &in_port); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed in parsing: %d", rc); + goto free_res; + } + CAM_DBG(CAM_ISP, "in_res_type %x", in_port->res_type); + + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, + &num_pix_port_per_in, &num_rdi_port_per_in, + &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + + total_pix_port += num_pix_port_per_in; + total_rdi_port += num_rdi_port_per_in; + + if (rc) { + CAM_ERR(CAM_ISP, "can not acquire resource"); + goto free_mem; + } + kfree(in_port->data); + kfree(in_port); + in_port = NULL; + } + + /* Check whether context has only RDI resource */ + if (!total_pix_port) { + ife_ctx->is_rdi_only_context = 1; + CAM_DBG(CAM_ISP, "RDI only context"); + } + + /* Process base info */ + rc = cam_ife_mgr_process_base_info(ife_ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Process base info failed"); + goto free_res; + } + + acquire_args->ctxt_to_hw_map = ife_ctx; + ife_ctx->ctx_in_use = 1; + + acquire_args->valid_acquired_hw = + acquire_hw_info->num_inputs; + + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + + CAM_DBG(CAM_ISP, "Exit...(success)"); + + return 0; +free_mem: + kfree(in_port->data); + kfree(in_port); +free_res: + cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx); +free_cdm: + cam_cdm_release(ife_ctx->cdm_handle); +free_ctx: + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); +err: + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +void cam_ife_mgr_acquire_get_unified_dev_str(struct cam_isp_in_port_info *in, + struct cam_isp_in_port_generic_info *gen_port_info) +{ + int i; + + gen_port_info->res_type = in->res_type; + gen_port_info->lane_type = in->lane_type; + gen_port_info->lane_num = in->lane_num; + gen_port_info->lane_cfg = in->lane_cfg; + gen_port_info->vc[0] = in->vc; + gen_port_info->dt[0] = in->dt; + gen_port_info->num_valid_vc_dt = 1; + gen_port_info->format = in->format; + gen_port_info->test_pattern = in->test_pattern; + gen_port_info->usage_type = in->usage_type; + gen_port_info->left_start = in->left_start; + gen_port_info->left_stop = in->left_stop; + gen_port_info->left_width = in->left_width; + gen_port_info->right_start = in->right_start; + gen_port_info->right_stop = in->right_stop; + gen_port_info->right_width = in->right_width; + gen_port_info->line_start = in->line_start; + gen_port_info->line_stop = in->line_stop; + gen_port_info->height = in->height; + gen_port_info->pixel_clk = in->pixel_clk; + gen_port_info->batch_size = in->batch_size; + gen_port_info->dsp_mode = in->dsp_mode; + gen_port_info->hbi_cnt = in->hbi_cnt; + gen_port_info->cust_node = 0; + gen_port_info->num_out_res = in->num_out_res; + + for (i = 0; i < in->num_out_res; i++) { + gen_port_info->data[i].res_type = in->data[i].res_type; + gen_port_info->data[i].format = in->data[i].format; + gen_port_info->data[i].width = in->data[i].width; + gen_port_info->data[i].height = in->data[i].height; + gen_port_info->data[i].comp_grp_id = in->data[i].comp_grp_id; + gen_port_info->data[i].split_point = in->data[i].split_point; + gen_port_info->data[i].secure_mode = in->data[i].secure_mode; + } +} + +/* entry function: acquire_hw */ +static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) +{ + struct cam_ife_hw_mgr *ife_hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -1; + int i, j; + struct cam_ife_hw_mgr_ctx *ife_ctx; + struct cam_isp_in_port_info *in_port = NULL; + struct cam_isp_resource *isp_resource = NULL; + struct cam_cdm_acquire_data cdm_acquire; + struct cam_isp_in_port_generic_info *gen_port_info = NULL; + uint32_t num_pix_port_per_in = 0; + uint32_t num_rdi_port_per_in = 0; + uint32_t total_pix_port = 0; + uint32_t total_rdi_port = 0; + uint32_t in_port_length = 0; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + /* get the ife ctx */ + rc = cam_ife_hw_mgr_get_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); + if (rc || !ife_ctx) { + CAM_ERR(CAM_ISP, "Get ife hw context failed"); + goto err; + } + + ife_ctx->common.cb_priv = acquire_args->context_data; + for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++) + ife_ctx->common.event_cb[i] = acquire_args->event_cb; + + ife_ctx->hw_mgr = ife_hw_mgr; + + + memcpy(cdm_acquire.identifier, "ife", sizeof("ife")); + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ife_ctx; + cdm_acquire.base_array_cnt = CAM_IFE_HW_NUM_MAX; + for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (ife_hw_mgr->cdm_reg_map[i]) + cdm_acquire.base_array[j++] = + ife_hw_mgr->cdm_reg_map[i]; + } + cdm_acquire.base_array_cnt = j; + + + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback; + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire the CDM HW"); + goto free_ctx; + } + + CAM_DBG(CAM_ISP, "Successfully acquired the CDM HW hdl=%x", + cdm_acquire.handle); + ife_ctx->cdm_handle = cdm_acquire.handle; + ife_ctx->cdm_ops = cdm_acquire.ops; + + isp_resource = (struct cam_isp_resource *)acquire_args->acquire_info; + + /* acquire HW resources */ + for (i = 0; i < acquire_args->num_acq; i++) { + if (isp_resource[i].resource_id != CAM_ISP_RES_ID_PORT) + continue; + + CAM_DBG(CAM_ISP, "acquire no = %d total = %d", i, + acquire_args->num_acq); + CAM_DBG(CAM_ISP, + "start copy from user handle %lld with len = %d", + isp_resource[i].res_hdl, + isp_resource[i].length); + + in_port_length = sizeof(struct cam_isp_in_port_info); + + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + goto free_res; + } + + in_port = memdup_user( + u64_to_user_ptr(isp_resource[i].res_hdl), + isp_resource[i].length); + if (!IS_ERR(in_port)) { + if (in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "too many output res %d", + in_port->num_out_res); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + + gen_port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), + GFP_KERNEL); + if (gen_port_info == NULL) { + rc = -ENOMEM; + goto free_res; + } + + gen_port_info->data = kcalloc( + sizeof(struct cam_isp_out_port_generic_info), + in_port->num_out_res, GFP_KERNEL); + if (gen_port_info->data == NULL) { + kfree(gen_port_info); + gen_port_info = NULL; + rc = -ENOMEM; + goto free_res; + } + + cam_ife_mgr_acquire_get_unified_dev_str(in_port, + gen_port_info); + + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, + gen_port_info, &num_pix_port_per_in, + &num_rdi_port_per_in, + &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + + total_pix_port += num_pix_port_per_in; + total_rdi_port += num_rdi_port_per_in; + + kfree(in_port); + if (gen_port_info != NULL) { + kfree(gen_port_info->data); + kfree(gen_port_info); + gen_port_info = NULL; + } + if (rc) { + CAM_ERR(CAM_ISP, "can not acquire resource"); + goto free_res; + } + } else { + CAM_ERR(CAM_ISP, + "Copy from user failed with in_port = %pK", + in_port); + rc = -EFAULT; + goto free_res; + } + } + + /* Check whether context has only RDI resource */ + if (!total_pix_port) { + ife_ctx->is_rdi_only_context = 1; + CAM_DBG(CAM_ISP, "RDI only context"); + } + + /* Process base info */ + rc = cam_ife_mgr_process_base_info(ife_ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Process base info failed"); + goto free_res; + } + + acquire_args->ctxt_to_hw_map = ife_ctx; + ife_ctx->ctx_in_use = 1; + + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + + CAM_DBG(CAM_ISP, "Exit...(success)"); + + return 0; +free_res: + cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx); + cam_cdm_release(ife_ctx->cdm_handle); +free_ctx: + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); +err: + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +/* entry function: acquire_hw */ +static int cam_ife_mgr_acquire(void *hw_mgr_priv, + void *acquire_hw_args) +{ + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -1; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + if (acquire_args->num_acq == CAM_API_COMPAT_CONSTANT) + rc = cam_ife_mgr_acquire_hw(hw_mgr_priv, acquire_hw_args); + else + rc = cam_ife_mgr_acquire_dev(hw_mgr_priv, acquire_hw_args); + + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +static const char *cam_isp_util_usage_data_to_string( + uint32_t usage_data) +{ + switch (usage_data) { + case CAM_ISP_USAGE_LEFT_PX: + return "LEFT_PX"; + case CAM_ISP_USAGE_RIGHT_PX: + return "RIGHT_PX"; + case CAM_ISP_USAGE_RDI: + return "RDI"; + default: + return "USAGE_INVALID"; + } +} + +static int cam_isp_classify_vote_info( + struct cam_ife_hw_mgr_res *hw_mgr_res, + struct cam_isp_bw_config_v2 *bw_config, + struct cam_axi_vote *isp_vote, + uint32_t split_idx, + bool *camif_l_bw_updated, + bool *camif_r_bw_updated) +{ + int rc = 0, i, j = 0; + + if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) + || (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB)) { + if (split_idx == CAM_ISP_HW_SPLIT_LEFT) { + if (*camif_l_bw_updated) + return rc; + + for (i = 0; i < bw_config->num_paths; i++) { + if (bw_config->axi_path[i].usage_data == + CAM_ISP_USAGE_LEFT_PX) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + *camif_l_bw_updated = true; + } else { + if (*camif_r_bw_updated) + return rc; + + for (i = 0; i < bw_config->num_paths; i++) { + if (bw_config->axi_path[i].usage_data == + CAM_ISP_USAGE_RIGHT_PX) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + *camif_r_bw_updated = true; + } + } else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) + && (hw_mgr_res->res_id <= + CAM_ISP_HW_VFE_IN_RDI3)) { + for (i = 0; i < bw_config->num_paths; i++) { + if ((bw_config->axi_path[i].usage_data == + CAM_ISP_USAGE_RDI) && + ((bw_config->axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IFE_RDI0) == + (hw_mgr_res->res_id - + CAM_ISP_HW_VFE_IN_RDI0))) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + } else { + if (hw_mgr_res->hw_res[split_idx]) { + CAM_ERR(CAM_ISP, "Invalid res_id %u, split_idx: %u", + hw_mgr_res->res_id, split_idx); + rc = -EINVAL; + return rc; + } + } + + for (i = 0; i < isp_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "CLASSIFY_VOTE [%s] [%s] [%s] [%llu] [%llu] [%llu]", + cam_isp_util_usage_data_to_string( + isp_vote->axi_path[i].usage_data), + cam_cpas_axi_util_path_type_to_string( + isp_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + isp_vote->axi_path[i].transac_type), + isp_vote->axi_path[i].camnoc_bw, + isp_vote->axi_path[i].mnoc_ab_bw, + isp_vote->axi_path[i].mnoc_ib_bw); + } + + return rc; +} + +static int cam_isp_blob_bw_update_v2( + struct cam_isp_bw_config_v2 *bw_config, + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_bw_update_args_v2 bw_upd_args; + int rc = -EINVAL; + uint32_t i, split_idx; + bool camif_l_bw_updated = false; + bool camif_r_bw_updated = false; + + for (i = 0; i < bw_config->num_paths; i++) { + CAM_DBG(CAM_PERF, + "ISP_BLOB usage_type=%u [%s] [%s] [%s] [%llu] [%llu] [%llu]", + bw_config->usage_type, + cam_isp_util_usage_data_to_string( + bw_config->axi_path[i].usage_data), + cam_cpas_axi_util_path_type_to_string( + bw_config->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + bw_config->axi_path[i].transac_type), + bw_config->axi_path[i].camnoc_bw, + bw_config->axi_path[i].mnoc_ab_bw, + bw_config->axi_path[i].mnoc_ib_bw); + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (split_idx = 0; split_idx < CAM_ISP_HW_SPLIT_MAX; + split_idx++) { + if (!hw_mgr_res->hw_res[split_idx]) + continue; + + memset(&bw_upd_args.isp_vote, 0, + sizeof(struct cam_axi_vote)); + rc = cam_isp_classify_vote_info(hw_mgr_res, bw_config, + &bw_upd_args.isp_vote, split_idx, + &camif_l_bw_updated, &camif_r_bw_updated); + if (rc) + return rc; + + if (!bw_upd_args.isp_vote.num_paths) + continue; + + hw_intf = hw_mgr_res->hw_res[split_idx]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_upd_args.node_res = + hw_mgr_res->hw_res[split_idx]; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_UPDATE_V2, + &bw_upd_args, + sizeof( + struct cam_vfe_bw_update_args_v2)); + if (rc) + CAM_ERR(CAM_ISP, + "BW Update failed rc: %d", rc); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + } + + return rc; +} + +static int cam_isp_blob_bw_update( + struct cam_isp_bw_config *bw_config, + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_bw_update_args bw_upd_args; + uint64_t cam_bw_bps = 0; + uint64_t ext_bw_bps = 0; + int rc = -EINVAL; + uint32_t i; + bool camif_l_bw_updated = false; + bool camif_r_bw_updated = false; + + CAM_DBG(CAM_PERF, + "ISP_BLOB usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu, right cam_bw_bps=%llu ext_bw_bps=%llu", + bw_config->usage_type, + bw_config->left_pix_vote.cam_bw_bps, + bw_config->left_pix_vote.ext_bw_bps, + bw_config->right_pix_vote.cam_bw_bps, + bw_config->right_pix_vote.ext_bw_bps); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) + || (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD)) + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_bw_updated) + continue; + + cam_bw_bps = + bw_config->left_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->left_pix_vote.ext_bw_bps; + + camif_l_bw_updated = true; + } else { + if (camif_r_bw_updated) + continue; + + cam_bw_bps = + bw_config->right_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->right_pix_vote.ext_bw_bps; + + camif_r_bw_updated = true; + } + else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) + && (hw_mgr_res->res_id <= + CAM_ISP_HW_VFE_IN_RDI3)) { + uint32_t idx = hw_mgr_res->res_id - + CAM_ISP_HW_VFE_IN_RDI0; + if (idx >= bw_config->num_rdi) + continue; + + cam_bw_bps = + bw_config->rdi_vote[idx].cam_bw_bps; + ext_bw_bps = + bw_config->rdi_vote[idx].ext_bw_bps; + } else if (hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_PDLIB) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_bw_updated) + continue; + + cam_bw_bps = + bw_config->left_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->left_pix_vote.ext_bw_bps; + + camif_l_bw_updated = true; + } else { + if (camif_r_bw_updated) + continue; + + cam_bw_bps = + bw_config->right_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->right_pix_vote.ext_bw_bps; + + camif_r_bw_updated = true; + } + } else { + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_LCR + && hw_mgr_res->hw_res[i]) { + CAM_ERR(CAM_ISP, "Invalid res_id %u", + hw_mgr_res->res_id); + rc = -EINVAL; + return rc; + } + } + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + bw_upd_args.camnoc_bw_bytes = cam_bw_bps; + bw_upd_args.external_bw_bytes = ext_bw_bps; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_UPDATE, + &bw_upd_args, + sizeof(struct cam_vfe_bw_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "BW Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +/* entry function: config_hw */ +static int cam_ife_mgr_config_hw(void *hw_mgr_priv, + void *config_hw_args) +{ + int rc = -1, i; + struct cam_hw_config_args *cfg; + struct cam_hw_update_entry *cmd; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_isp_prepare_hw_update_data *hw_update_data; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_mgr_priv || !config_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + cfg = config_hw_args; + ctx = (struct cam_ife_hw_mgr_ctx *)cfg->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + if (!ctx->ctx_in_use || !ctx->cdm_cmd) { + CAM_ERR(CAM_ISP, "Invalid context parameters"); + return -EPERM; + } + if (atomic_read(&ctx->overflow_pending)) + return -EINVAL; + + hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; + + CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld", + ctx, ctx->ctx_index, cfg->request_id); + + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (hw_update_data->bw_config_valid[i] == true) { + + CAM_DBG(CAM_ISP, "idx=%d, bw_config_version=%d", + ctx, ctx->ctx_index, i, + hw_update_data->bw_config_version); + + if (hw_update_data->bw_config_version == + CAM_ISP_BW_CONFIG_V1) { + rc = cam_isp_blob_bw_update( + (struct cam_isp_bw_config *) + &hw_update_data->bw_config[i], ctx); + if (rc) + CAM_ERR(CAM_ISP, + "Bandwidth Update Failed rc: %d", rc); + } else if (hw_update_data->bw_config_version == + CAM_ISP_BW_CONFIG_V2) { + rc = cam_isp_blob_bw_update_v2( + (struct cam_isp_bw_config_v2 *) + &hw_update_data->bw_config_v2[i], ctx); + if (rc) + CAM_ERR(CAM_ISP, + "Bandwidth Update Failed rc: %d", rc); + + } else { + CAM_ERR(CAM_ISP, + "Invalid bw config version: %d", + hw_update_data->bw_config_version); + } + } + } + + CAM_DBG(CAM_ISP, + "Enter ctx id:%d num_hw_upd_entries %d request id: %llu", + ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id); + + if (cfg->num_hw_update_entries > 0) { + cdm_cmd = ctx->cdm_cmd; + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = true; + cdm_cmd->userdata = ctx; + cdm_cmd->cookie = cfg->request_id; + + for (i = 0 ; i <= cfg->num_hw_update_entries; i++) { + cmd = (cfg->hw_update_entries + i); + cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i].offset = cmd->offset; + cdm_cmd->cmd[i].len = cmd->len; + } + + if (cfg->init_packet) + init_completion(&ctx->config_done_complete); + + CAM_DBG(CAM_ISP, "Submit to CDM"); + rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to apply the configs"); + return rc; + } + + if (cfg->init_packet) { + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(30)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, + "config done completion timeout for req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, ctx->ctx_index); + if (rc == 0) + rc = -ETIMEDOUT; + } else { + rc = 0; + CAM_DBG(CAM_ISP, + "config done Success for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); + } + } + } else { + CAM_ERR(CAM_ISP, "No commands to config"); + } + CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id); + + return rc; +} + +static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_ctx *ctx; + uint32_t i, master_base_idx = 0; + + if (!stop_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", + ctx->ctx_index); + + if (!ctx->num_base) { + CAM_ERR(CAM_ISP, "Number of bases are zero"); + return -EINVAL; + } + + /* get master base index first */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) { + master_base_idx = ctx->base[i].idx; + break; + } + } + + if (i == ctx->num_base) + master_base_idx = ctx->base[0].idx; + + + /* stop the master CIDs first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + master_base_idx, CAM_CSID_HALT_IMMEDIATELY); + + /* stop rest of the CIDs */ + for (i = 0; i < ctx->num_base; i++) { + if (i == master_base_idx) + continue; + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + ctx->base[i].idx, CAM_CSID_HALT_IMMEDIATELY); + } + + /* stop the master CSID path first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + master_base_idx, CAM_CSID_HALT_IMMEDIATELY); + + /* Stop rest of the CSID paths */ + for (i = 0; i < ctx->num_base; i++) { + if (i == master_base_idx) + continue; + + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + ctx->base[i].idx, CAM_CSID_HALT_IMMEDIATELY); + } + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + /* IFE out resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); + + + /* Stop tasklet for context */ + cam_tasklet_stop(ctx->common.tasklet_info); + CAM_DBG(CAM_ISP, "Exit...ctx id:%d rc :%d", + ctx->ctx_index, rc); + + return rc; +} + +static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx, + enum cam_vfe_bw_control_action action) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_bw_control_args bw_ctrl_args; + int rc = -EINVAL; + uint32_t i; + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_ctrl_args.node_res = + hw_mgr_res->hw_res[i]; + bw_ctrl_args.action = action; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_CONTROL, + &bw_ctrl_args, + sizeof(struct cam_vfe_bw_control_args)); + if (rc) + CAM_ERR(CAM_ISP, "BW Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx) +{ + return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE); +} + +/* entry function: stop_hw */ +static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_isp_stop_args *stop_isp; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_ctx *ctx; + enum cam_ife_csid_halt_cmd csid_halt_type; + uint32_t i, master_base_idx = 0; + + if (!hw_mgr_priv || !stop_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index); + stop_isp = (struct cam_isp_stop_args *)stop_args->args; + + if ((stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_IMMEDIATELY) && + (stop_isp->stop_only)) { + CAM_ERR(CAM_ISP, "Invalid params hw_stop_cmd:%d stop_only:%d", + stop_isp->hw_stop_cmd, stop_isp->stop_only); + return -EPERM; + } + + /* Set the csid halt command */ + if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) + csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY; + else + csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; + + /* Note:stop resource will remove the irq mask from the hardware */ + + if (!ctx->num_base) { + CAM_ERR(CAM_ISP, "number of bases are zero"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Halting CSIDs"); + + /* get master base index first */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) { + master_base_idx = ctx->base[i].idx; + break; + } + } + + /* + * If Context does not have PIX resources and has only RDI resource + * then take the first base index. + */ + if (i == ctx->num_base) + master_base_idx = ctx->base[0].idx; + CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx); + + /* Stop the master CSID path first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + + /* stop rest of the CSID paths */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == master_base_idx) + continue; + CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + } + + CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx); + + /* Stop the master CIDs first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + master_base_idx, csid_halt_type); + + /* stop rest of the CIDs */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == master_base_idx) + continue; + CAM_DBG(CAM_ISP, "Stopping CID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + ctx->base[i].idx, csid_halt_type); + } + + CAM_DBG(CAM_ISP, "Going to stop IFE Out"); + + /* IFE out resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); + + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + CAM_DBG(CAM_ISP, "Going to stop IFE Mux"); + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + cam_ife_mgr_pause_hw(ctx); + + if (stop_isp->stop_only) { + cam_tasklet_stop(ctx->common.tasklet_info); + goto end; + } + + if (cam_cdm_stream_off(ctx->cdm_handle)) + CAM_ERR(CAM_ISP, "CDM stream off failed %d", ctx->cdm_handle); + + cam_ife_hw_mgr_deinit_hw(ctx); + cam_tasklet_stop(ctx->common.tasklet_info); + + CAM_DBG(CAM_ISP, + "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) { + rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE); + if (rc) { + CAM_ERR(CAM_ISP, + "SAFE SCM call failed:Check TZ/HYP dependency"); + rc = 0; + } + } + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + +end: + return rc; +} + +static int cam_ife_mgr_reset_vfe_hw(struct cam_ife_hw_mgr *hw_mgr, + uint32_t hw_idx) +{ + uint32_t i = 0; + struct cam_hw_intf *vfe_hw_intf; + uint32_t vfe_reset_type; + + if (!hw_mgr) { + CAM_DBG(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + /* Reset VFE HW*/ + vfe_reset_type = CAM_VFE_HW_RESET_HW; + + for (i = 0; i < CAM_VFE_HW_NUM_MAX; i++) { + if (hw_idx != hw_mgr->ife_devices[i]->hw_idx) + continue; + CAM_DBG(CAM_ISP, "VFE (id = %d) reset", hw_idx); + vfe_hw_intf = hw_mgr->ife_devices[i]; + vfe_hw_intf->hw_ops.reset(vfe_hw_intf->hw_priv, + &vfe_reset_type, sizeof(vfe_reset_type)); + break; + } + + CAM_DBG(CAM_ISP, "Exit Successfully"); + return 0; +} + +static int cam_ife_mgr_restart_hw(void *start_hw_args) +{ + int rc = -1; + struct cam_hw_start_args *start_args = start_hw_args; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t i; + + if (!start_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", ctx->ctx_index); + + cam_tasklet_start(ctx->common.tasklet_info); + + /* start the IFE out devices */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + rc = cam_ife_hw_mgr_start_hw_res( + &ctx->res_list_ife_out[i], ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)", i); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index); + + /* Start IFE BUS RD device */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", ctx->ctx_index); + /* Start the IFE CSID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CID SRC ... in ctx id:%d", ctx->ctx_index); + /* Start IFE root node: do nothing */ + CAM_DBG(CAM_ISP, "Exit...(success)"); + return 0; + +err: + cam_ife_mgr_stop_hw_in_overflow(start_hw_args); + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) +{ + int rc = -1; + struct cam_isp_start_args *start_isp = start_hw_args; + struct cam_hw_stop_args stop_args; + struct cam_isp_stop_args stop_isp; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *rsrc_node = NULL; + uint32_t i, camif_debug; + + if (!hw_mgr_priv || !start_isp) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *) + start_isp->hw_config.ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + if ((!ctx->init_done) && start_isp->start_only) { + CAM_ERR(CAM_ISP, "Invalid args init_done %d start_only %d", + ctx->init_done, start_isp->start_only); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enter... ctx id:%d", + ctx->ctx_index); + + /* update Bandwidth should be done at the hw layer */ + + cam_tasklet_start(ctx->common.tasklet_info); + + if (ctx->init_done && start_isp->start_only) + goto start_only; + + /* set current csid debug information to CSID HW */ + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (g_ife_hw_mgr.csid_devices[i]) + rc = g_ife_hw_mgr.csid_devices[i]->hw_ops.process_cmd( + g_ife_hw_mgr.csid_devices[i]->hw_priv, + CAM_IFE_CSID_SET_CSID_DEBUG, + &g_ife_hw_mgr.debug_cfg.csid_debug, + sizeof(g_ife_hw_mgr.debug_cfg.csid_debug)); + } + + camif_debug = g_ife_hw_mgr.debug_cfg.camif_debug; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF)) { + rc = hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, + &camif_debug, + sizeof(camif_debug)); + } + } + } + + rc = cam_ife_hw_mgr_init_hw(ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Init failed"); + goto tasklet_stop; + } + + ctx->init_done = true; + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + if (!atomic_fetch_inc(&g_ife_hw_mgr.active_ctx_cnt)) { + rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_ENABLE); + if (rc) { + CAM_ERR(CAM_ISP, + "SAFE SCM call failed:Check TZ/HYP dependency"); + rc = -EFAULT; + goto deinit_hw; + } + } + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + + CAM_DBG(CAM_ISP, "start cdm interface"); + rc = cam_cdm_stream_on(ctx->cdm_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start cdm (%d)", + ctx->cdm_handle); + goto safe_disable; + } + + /* Apply initial configuration */ + CAM_DBG(CAM_ISP, "Config HW"); + rc = cam_ife_mgr_config_hw(hw_mgr_priv, &start_isp->hw_config); + if (rc) { + CAM_ERR(CAM_ISP, "Config HW failed"); + goto cdm_streamoff; + } + +start_only: + + CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", + ctx->ctx_index); + /* start the IFE out devices */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + rc = cam_ife_hw_mgr_start_hw_res( + &ctx->res_list_ife_out[i], ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)", + i); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE CSID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CID SRC ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE CID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + /* Start IFE root node: do nothing */ + CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); + + return 0; + +err: + stop_isp.stop_only = false; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + stop_args.ctxt_to_hw_map = start_isp->hw_config.ctxt_to_hw_map; + stop_args.args = (void *)(&stop_isp); + + cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args); + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; + +cdm_streamoff: + cam_cdm_stream_off(ctx->cdm_handle); + +safe_disable: + cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE); + +deinit_hw: + cam_ife_hw_mgr_deinit_hw(ctx); + +tasklet_stop: + cam_tasklet_stop(ctx->common.tasklet_info); + + return rc; +} + +static int cam_ife_mgr_read(void *hw_mgr_priv, void *read_args) +{ + return -EPERM; +} + +static int cam_ife_mgr_write(void *hw_mgr_priv, void *write_args) +{ + return -EPERM; +} + +static int cam_ife_mgr_release_hw(void *hw_mgr_priv, + void *release_hw_args) +{ + int rc = 0; + struct cam_hw_release_args *release_args = release_hw_args; + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_ife_hw_mgr_ctx *ctx; + uint32_t i; + + if (!hw_mgr_priv || !release_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)release_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", + ctx->ctx_index); + + if (ctx->init_done) + cam_ife_hw_mgr_deinit_hw(ctx); + + /* we should called the stop hw before this already */ + cam_ife_hw_mgr_release_hw_for_ctx(ctx); + + /* reset base info */ + ctx->num_base = 0; + memset(ctx->base, 0, sizeof(ctx->base)); + + /* release cdm handle */ + cam_cdm_release(ctx->cdm_handle); + + /* clean context */ + list_del_init(&ctx->list); + ctx->ctx_in_use = 0; + ctx->is_rdi_only_context = 0; + ctx->cdm_handle = 0; + ctx->cdm_ops = NULL; + atomic_set(&ctx->overflow_pending, 0); + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + ctx->sof_cnt[i] = 0; + ctx->eof_cnt[i] = 0; + ctx->epoch_cnt[i] = 0; + } + CAM_DBG(CAM_ISP, "Exit...ctx id:%d", + ctx->ctx_index); + cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx); + return rc; +} + +static int cam_isp_blob_fe_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_fe_config *fe_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + int rc = -EINVAL; + uint32_t i; + struct cam_vfe_fe_update_args fe_upd_args; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + &fe_upd_args, + sizeof( + struct cam_fe_config)); + if (rc) + CAM_ERR(CAM_ISP, "fs Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + &fe_upd_args, + sizeof( + struct cam_vfe_fe_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "fe Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + return rc; +} + +static int cam_isp_blob_ubwc_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_ubwc_config *ubwc_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid ctx"); + rc = -EINVAL; + goto end; + } + + if ((prepare->num_hw_update_entries + 1) >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d max:%d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + rc = -EINVAL; + goto end; + } + + switch (ubwc_config->api_version) { + case CAM_UBWC_CFG_VERSION_1: + CAM_DBG(CAM_ISP, "num_ports= %d", ubwc_config->num_ports); + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < ubwc_config->num_ports; i++) { + ubwc_plane_cfg = &ubwc_config->ubwc_plane_cfg[i][0]; + res_id_out = ubwc_plane_cfg->port_type & 0xFF; + + CAM_DBG(CAM_ISP, "UBWC config idx %d, port_type=%d", i, + ubwc_plane_cfg->port_type); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid port type:%x", + ubwc_plane_cfg->port_type); + rc = -EINVAL; + goto end; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base=%d bytes_used=%u buf_size=%u", + blob_info->base_info->idx, bytes_used, + kmd_buf_info->size); + rc = -ENOMEM; + goto end; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; + + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, "Invalid hw_mgr_res"); + rc = -EINVAL; + goto end; + } + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)ubwc_plane_cfg, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", + blob_info->base_info->idx, + bytes_used, + res_id_out); + goto end; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = + total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid UBWC API Version %d", + ubwc_config->api_version); + rc = -EINVAL; + break; + } +end: + return rc; +} + +static int cam_isp_get_generic_ubwc_data_v2( + struct cam_ubwc_plane_cfg_v2 *ubwc_cfg, + uint32_t version, + struct cam_vfe_generic_ubwc_config *generic_ubwc_cfg) +{ + int i = 0; + + generic_ubwc_cfg->api_version = version; + for (i = 0; i < CAM_PACKET_MAX_PLANES - 1; i++) { + generic_ubwc_cfg->ubwc_plane_cfg[i].port_type = + ubwc_cfg[i].port_type; + generic_ubwc_cfg->ubwc_plane_cfg[i].meta_stride = + ubwc_cfg[i].meta_stride; + generic_ubwc_cfg->ubwc_plane_cfg[i].meta_size = + ubwc_cfg[i].meta_size; + generic_ubwc_cfg->ubwc_plane_cfg[i].meta_offset = + ubwc_cfg[i].meta_offset; + generic_ubwc_cfg->ubwc_plane_cfg[i].packer_config = + ubwc_cfg[i].packer_config; + generic_ubwc_cfg->ubwc_plane_cfg[i].mode_config_0 = + ubwc_cfg[i].mode_config_0; + generic_ubwc_cfg->ubwc_plane_cfg[i].mode_config_1 = + ubwc_cfg[i].mode_config_1; + generic_ubwc_cfg->ubwc_plane_cfg[i].tile_config = + ubwc_cfg[i].tile_config; + generic_ubwc_cfg->ubwc_plane_cfg[i].h_init = + ubwc_cfg[i].h_init; + generic_ubwc_cfg->ubwc_plane_cfg[i].v_init = + ubwc_cfg[i].v_init; + generic_ubwc_cfg->ubwc_plane_cfg[i].static_ctrl = + ubwc_cfg[i].static_ctrl; + generic_ubwc_cfg->ubwc_plane_cfg[i].ctrl_2 = + ubwc_cfg[i].ctrl_2; + generic_ubwc_cfg->ubwc_plane_cfg[i].stats_ctrl_2 = + ubwc_cfg[i].stats_ctrl_2; + generic_ubwc_cfg->ubwc_plane_cfg[i].lossy_threshold_0 = + ubwc_cfg[i].lossy_threshold_0; + generic_ubwc_cfg->ubwc_plane_cfg[i].lossy_threshold_1 = + ubwc_cfg[i].lossy_threshold_1; + generic_ubwc_cfg->ubwc_plane_cfg[i].lossy_var_offset = + ubwc_cfg[i].lossy_var_offset; + generic_ubwc_cfg->ubwc_plane_cfg[i].bandwidth_limit = + ubwc_cfg[i].bandwidth_limit; + } + + return 0; +} + +static int cam_isp_blob_ubwc_update_v2( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_ubwc_config_v2 *ubwc_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ubwc_plane_cfg_v2 *ubwc_plane_cfg; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + struct cam_vfe_generic_ubwc_config generic_ubwc_cfg; + + ctx = prepare->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid ctx"); + rc = -EINVAL; + goto end; + } + + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d max:%d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "num_ports= %d", ubwc_config->num_ports); + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < ubwc_config->num_ports; i++) { + ubwc_plane_cfg = &ubwc_config->ubwc_plane_cfg[i][0]; + res_id_out = ubwc_plane_cfg->port_type & 0xFF; + + CAM_DBG(CAM_ISP, "UBWC config idx %d, port_type=%d", i, + ubwc_plane_cfg->port_type); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid port type:%x", + ubwc_plane_cfg->port_type); + rc = -EINVAL; + goto end; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base=%d bytes_used=%u buf_size=%u", + blob_info->base_info->idx, bytes_used, + kmd_buf_info->size); + rc = -ENOMEM; + goto end; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; + + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, "Invalid hw_mgr_res"); + rc = -EINVAL; + goto end; + } + + rc = cam_isp_get_generic_ubwc_data_v2(ubwc_plane_cfg, + ubwc_config->api_version, &generic_ubwc_cfg); + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)&generic_ubwc_cfg, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", + blob_info->base_info->idx, + bytes_used, + res_id_out); + goto end; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = + total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } +end: + return rc; +} + +static int cam_isp_blob_hfr_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_resource_hfr_config *hfr_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_isp_port_hfr_config *port_hfr_config; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + CAM_DBG(CAM_ISP, "num_ports= %d", + hfr_config->num_ports); + + /* Max one hw entries required for hfr config update */ + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < hfr_config->num_ports; i++) { + port_hfr_config = &hfr_config->port_hfr_config[i]; + res_id_out = port_hfr_config->resource_type & 0xFF; + + CAM_DBG(CAM_ISP, "hfr config idx %d, type=%d", i, + res_id_out); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "invalid out restype:%x", + port_hfr_config->resource_type); + return -EINVAL; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + blob_info->base_info->idx); + rc = -ENOMEM; + return rc; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)port_hfr_config, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, rc=%d", + blob_info->base_info->idx, bytes_used); + return rc; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +static int cam_isp_blob_csid_clock_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_csid_clock_config *clock_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_csid_clock_update_args csid_clock_upd_args; + uint64_t clk_rate = 0; + int rc = -EINVAL; + uint32_t i; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_ISP, + "csid clk=%llu", clock_config->csid_clock); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i]) + continue; + clk_rate = clock_config->csid_clock; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + csid_clock_upd_args.clk_rate = clk_rate; + CAM_DBG(CAM_ISP, "i= %d clk=%llu\n", + i, csid_clock_upd_args.clk_rate); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + blob_type_hw_cmd_map[blob_type], + &csid_clock_upd_args, + sizeof( + struct cam_ife_csid_clock_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update failed"); + } else + CAM_ERR(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_isp_blob_core_cfg_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_core_config *core_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + uint64_t clk_rate = 0; + int rc = 0, i; + struct cam_vfe_core_config_args vfe_core_config; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i] || + hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + vfe_core_config.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&vfe_core_config.core_config, + core_config, + sizeof(struct cam_isp_core_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CORE_CONFIG, + &vfe_core_config, + sizeof( + struct cam_vfe_core_config_args)); + if (rc) + CAM_ERR(CAM_ISP, "Core cfg parse fail"); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + } + + return rc; +} + +static int cam_isp_blob_clock_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_clock_config *clock_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_clock_update_args clock_upd_args; + uint64_t clk_rate = 0; + int rc = -EINVAL; + uint32_t i; + uint32_t j; + bool camif_l_clk_updated = false; + bool camif_r_clk_updated = false; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_PERF, + "usage=%u left_clk= %lu right_clk=%lu", + clock_config->usage_type, + clock_config->left_pix_hz, + clock_config->right_pix_hz); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_clk_updated) + continue; + + clk_rate = + clock_config->left_pix_hz; + + camif_l_clk_updated = true; + } else { + if (camif_r_clk_updated) + continue; + + clk_rate = + clock_config->right_pix_hz; + + camif_r_clk_updated = true; + } + } else if (hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_PDLIB) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_clk_updated) + continue; + + clk_rate = + clock_config->left_pix_hz; + + camif_l_clk_updated = true; + } else { + if (camif_r_clk_updated) + continue; + + clk_rate = + clock_config->right_pix_hz; + + camif_r_clk_updated = true; + } + } else if ((hw_mgr_res->res_id >= + CAM_ISP_HW_VFE_IN_RD) && (hw_mgr_res->res_id + <= CAM_ISP_HW_VFE_IN_RDI3)) + for (j = 0; j < clock_config->num_rdi; j++) + clk_rate = max(clock_config->rdi_hz[j], + clk_rate); + else + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_LCR + && hw_mgr_res->hw_res[i]) { + CAM_ERR(CAM_ISP, "Invalid res_id %u", + hw_mgr_res->res_id); + rc = -EINVAL; + return rc; + } + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + clock_upd_args.node_res = + hw_mgr_res->hw_res[i]; + CAM_DBG(CAM_ISP, + "res_id=%u i= %d clk=%llu\n", + hw_mgr_res->res_id, i, clk_rate); + + clock_upd_args.clk_rate = clk_rate; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CLOCK_UPDATE, + &clock_upd_args, + sizeof( + struct cam_vfe_clock_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_isp_blob_vfe_out_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_vfe_out_config *vfe_out_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_isp_vfe_wm_config *wm_config; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *ife_out_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < vfe_out_config->num_ports; i++) { + wm_config = &vfe_out_config->wm_config[i]; + res_id_out = wm_config->port_type & 0xFF; + + CAM_DBG(CAM_ISP, "VFE out config idx: %d port: 0x%x", + i, wm_config->port_type); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid out port:0x%x", + wm_config->port_type); + return -EINVAL; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "No free kmd memory for base idx: %d", + blob_info->base_info->idx); + rc = -ENOMEM; + return rc; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + (kmd_buf_info->used_bytes / 4) + + (total_used_bytes / 4); + ife_out_res = &ctx->res_list_ife_out[res_id_out]; + + rc = cam_isp_add_cmd_buf_update( + ife_out_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)wm_config, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed to update VFE Out out_type:0x%X base_idx:%d bytes_used:%u rc:%d", + wm_config->port_type, blob_info->base_info->idx, + bytes_used, rc); + return rc; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +static int cam_isp_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + int rc = 0; + struct cam_isp_generic_blob_info *blob_info = user_data; + struct cam_hw_prepare_update_args *prepare = NULL; + struct cam_ife_hw_mgr_ctx *ife_mgr_ctx = NULL; + + if (!blob_data || (blob_size == 0) || !blob_info) { + CAM_ERR(CAM_ISP, "Invalid args data %pK size %d info %pK", + blob_data, blob_size, blob_info); + return -EINVAL; + } + + if (blob_type >= CAM_ISP_GENERIC_BLOB_TYPE_MAX) { + CAM_ERR(CAM_ISP, "Invalid Blob Type %d Max %d", blob_type, + CAM_ISP_GENERIC_BLOB_TYPE_MAX); + return -EINVAL; + } + + prepare = blob_info->prepare; + if (!prepare || !prepare->ctxt_to_hw_map) { + CAM_ERR(CAM_ISP, "Failed. prepare is NULL, blob_type %d", + blob_type); + return -EINVAL; + } + + ife_mgr_ctx = prepare->ctxt_to_hw_map; + CAM_DBG(CAM_ISP, "Context[%pK][%d] blob_type=%d, blob_size=%d", + ife_mgr_ctx, ife_mgr_ctx->ctx_index, blob_type, blob_size); + + switch (blob_type) { + case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: { + struct cam_isp_resource_hfr_config *hfr_config; + + if (blob_size < sizeof(struct cam_isp_resource_hfr_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + hfr_config = (struct cam_isp_resource_hfr_config *)blob_data; + + if (hfr_config->num_ports > CAM_ISP_IFE_OUT_RES_MAX || + hfr_config->num_ports == 0) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in HFR config", + hfr_config->num_ports); + return -EINVAL; + } + + /* Check for integer overflow */ + if (hfr_config->num_ports != 1) { + if (sizeof(struct cam_isp_port_hfr_config) > + ((UINT_MAX - + sizeof(struct cam_isp_resource_hfr_config)) / + (hfr_config->num_ports - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in hfr config num_ports:%u size per port:%lu", + hfr_config->num_ports, + sizeof(struct cam_isp_port_hfr_config)); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_isp_resource_hfr_config) + + (hfr_config->num_ports - 1) * + sizeof(struct cam_isp_port_hfr_config))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_resource_hfr_config) + + (hfr_config->num_ports - 1) * + sizeof(struct cam_isp_port_hfr_config)); + return -EINVAL; + } + + rc = cam_isp_blob_hfr_update(blob_type, blob_info, + hfr_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "HFR Update Failed"); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: { + struct cam_isp_clock_config *clock_config; + + if (blob_size < sizeof(struct cam_isp_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + clock_config = (struct cam_isp_clock_config *)blob_data; + + if (clock_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in clock config", + clock_config->num_rdi); + return -EINVAL; + } + + /* Check for integer overflow */ + if (clock_config->num_rdi != 1) { + if (sizeof(uint64_t) > ((UINT_MAX - + sizeof(struct cam_isp_clock_config)) / + (clock_config->num_rdi - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in clock config num_rdi:%u size per port:%lu", + clock_config->num_rdi, + sizeof(uint64_t)); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_isp_clock_config) + + sizeof(uint64_t) * (clock_config->num_rdi - 1))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(uint32_t) * 2 + sizeof(uint64_t) * + (clock_config->num_rdi + 2)); + return -EINVAL; + } + + rc = cam_isp_blob_clock_update(blob_type, blob_info, + clock_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update Failed"); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: { + struct cam_isp_bw_config *bw_config; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + CAM_WARN(CAM_ISP, "Deprecated Blob TYPE_BW_CONFIG"); + if (blob_size < sizeof(struct cam_isp_bw_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config = (struct cam_isp_bw_config *)blob_data; + + if (bw_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config", + bw_config->num_rdi); + return -EINVAL; + } + + /* Check for integer overflow */ + if (bw_config->num_rdi != 1) { + if (sizeof(struct cam_isp_bw_vote) > ((UINT_MAX - + sizeof(struct cam_isp_bw_config)) / + (bw_config->num_rdi - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in bw config num_rdi:%u size per port:%lu", + bw_config->num_rdi, + sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_isp_bw_config) + + (bw_config->num_rdi - 1) * + sizeof(struct cam_isp_bw_vote))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_isp_bw_config) + + (bw_config->num_rdi - 1) * + sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } + + if (!prepare || !prepare->priv || + (bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) { + CAM_ERR(CAM_ISP, "Invalid inputs"); + return -EINVAL; + } + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + memcpy(&prepare_hw_data->bw_config[bw_config->usage_type], + bw_config, sizeof(prepare_hw_data->bw_config[0])); + prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V1; + prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: { + size_t bw_config_size = 0; + struct cam_isp_bw_config_v2 *bw_config; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (blob_size < sizeof(struct cam_isp_bw_config_v2)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config = (struct cam_isp_bw_config_v2 *)blob_data; + + if (bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES) { + CAM_ERR(CAM_ISP, "Invalid num paths %d", + bw_config->num_paths); + return -EINVAL; + } + + /* Check for integer overflow */ + if (bw_config->num_paths != 1) { + if (sizeof(struct cam_axi_per_path_bw_vote) > + ((UINT_MAX - + sizeof(struct cam_isp_bw_config_v2)) / + (bw_config->num_paths - 1))) { + CAM_ERR(CAM_ISP, + "Size exceeds limit paths:%u size per path:%lu", + bw_config->num_paths - 1, + sizeof( + struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_isp_bw_config_v2) + + ((bw_config->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)))) { + CAM_ERR(CAM_ISP, + "Invalid blob size: %u, num_paths: %u, bw_config size: %lu, per_path_vote size: %lu", + blob_size, bw_config->num_paths, + sizeof(struct cam_isp_bw_config_v2), + sizeof(struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + + if (!prepare || !prepare->priv || + (bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) { + CAM_ERR(CAM_ISP, "Invalid inputs"); + return -EINVAL; + } + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + memset(&prepare_hw_data->bw_config_v2[bw_config->usage_type], + 0, sizeof( + prepare_hw_data->bw_config_v2[bw_config->usage_type])); + bw_config_size = sizeof(struct cam_isp_bw_config_internal_v2) + + ((bw_config->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)); + memcpy(&prepare_hw_data->bw_config_v2[bw_config->usage_type], + bw_config, bw_config_size); + + prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V2; + prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: { + struct cam_ubwc_config *ubwc_config; + + if (blob_size < sizeof(struct cam_ubwc_config)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u", blob_size); + return -EINVAL; + } + + ubwc_config = (struct cam_ubwc_config *)blob_data; + + if (ubwc_config->num_ports > CAM_VFE_MAX_UBWC_PORTS || + ubwc_config->num_ports == 0) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in ubwc config", + ubwc_config->num_ports); + return -EINVAL; + } + + /* Check for integer overflow */ + if (ubwc_config->num_ports != 1) { + if (sizeof(struct cam_ubwc_plane_cfg_v1) > + ((UINT_MAX - sizeof(struct cam_ubwc_config)) / + ((ubwc_config->num_ports - 1) * 2))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in ubwc config num_ports:%u size per port:%lu", + ubwc_config->num_ports, + sizeof(struct cam_ubwc_plane_cfg_v1) * + 2); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_ubwc_config) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v1) * 2)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u expected %lu", + blob_size, + sizeof(struct cam_ubwc_config) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v1) * 2); + return -EINVAL; + } + + rc = cam_isp_blob_ubwc_update(blob_type, blob_info, + ubwc_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "UBWC Update Failed rc: %d", rc); + } + break; + + case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG_V2: { + struct cam_ubwc_config_v2 *ubwc_config; + + if (blob_size < sizeof(struct cam_ubwc_config_v2)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u", blob_size); + return -EINVAL; + } + + ubwc_config = (struct cam_ubwc_config_v2 *)blob_data; + + if (ubwc_config->num_ports > CAM_VFE_MAX_UBWC_PORTS || + ubwc_config->num_ports == 0) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in ubwc config", + ubwc_config->num_ports); + return -EINVAL; + } + + /* Check for integer overflow */ + if (ubwc_config->num_ports != 1) { + if (sizeof(struct cam_ubwc_plane_cfg_v2) > + ((UINT_MAX - sizeof(struct cam_ubwc_config_v2)) + / ((ubwc_config->num_ports - 1) * 2))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in ubwc config num_ports:%u size per port:%lu", + ubwc_config->num_ports, + sizeof(struct cam_ubwc_plane_cfg_v2) * + 2); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_ubwc_config_v2) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v2) * 2)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u expected %lu", + blob_size, + sizeof(struct cam_ubwc_config_v2) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v2) * 2); + return -EINVAL; + } + + rc = cam_isp_blob_ubwc_update_v2(blob_type, blob_info, + ubwc_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "UBWC Update Failed rc: %d", rc); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG: { + struct cam_isp_csid_clock_config *clock_config; + + if (blob_size < sizeof(struct cam_isp_csid_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_csid_clock_config)); + return -EINVAL; + } + + clock_config = (struct cam_isp_csid_clock_config *)blob_data; + + rc = cam_isp_blob_csid_clock_update(blob_type, blob_info, + clock_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update Failed"); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: { + struct cam_fe_config *fe_config; + + if (blob_size < sizeof(struct cam_fe_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_fe_config)); + return -EINVAL; + } + + fe_config = (struct cam_fe_config *)blob_data; + + rc = cam_isp_blob_fe_update(blob_type, blob_info, + fe_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG: { + struct cam_isp_core_config *core_config; + + if (blob_size < sizeof(struct cam_isp_core_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_isp_core_config)); + return -EINVAL; + } + + core_config = (struct cam_isp_core_config *)blob_data; + + rc = cam_isp_blob_core_cfg_update(blob_type, blob_info, + core_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Core cfg update fail: %d", rc); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG: { + struct cam_isp_vfe_out_config *vfe_out_config; + + if (blob_size < sizeof(struct cam_isp_vfe_out_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", + blob_size, + sizeof(struct cam_isp_vfe_out_config)); + return -EINVAL; + } + + vfe_out_config = (struct cam_isp_vfe_out_config *)blob_data; + + if (vfe_out_config->num_ports > CAM_IFE_HW_OUT_RES_MAX || + vfe_out_config->num_ports == 0) { + CAM_ERR(CAM_ISP, + "Invalid num_ports:%u in vfe out config", + vfe_out_config->num_ports, + CAM_IFE_HW_OUT_RES_MAX); + return -EINVAL; + } + + /* Check for integer overflow */ + if (vfe_out_config->num_ports != 1) { + if (sizeof(struct cam_isp_vfe_wm_config) > ((UINT_MAX - + sizeof(struct cam_isp_vfe_out_config)) / + (vfe_out_config->num_ports - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in vfe out config num_ports:%u size per port:%lu", + vfe_out_config->num_ports, + sizeof(struct cam_isp_vfe_wm_config)); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_isp_vfe_out_config) + + (vfe_out_config->num_ports - 1) * + sizeof(struct cam_isp_vfe_wm_config))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_isp_vfe_out_config) + + (vfe_out_config->num_ports - 1) * + sizeof(struct cam_isp_vfe_wm_config)); + return -EINVAL; + } + + rc = cam_isp_blob_vfe_out_update(blob_type, blob_info, + vfe_out_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "VFE out update failed rc: %d", rc); + } + break; + + default: + CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); + break; + } + + return rc; +} + +static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc = 0; + struct cam_hw_prepare_update_args *prepare = + (struct cam_hw_prepare_update_args *) prepare_hw_update_args; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr *hw_mgr; + struct cam_kmd_buf_info kmd_buf; + uint32_t i; + bool fill_fence = true; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (!hw_mgr_priv || !prepare_hw_update_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + ctx = (struct cam_ife_hw_mgr_ctx *) prepare->ctxt_to_hw_map; + hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv; + + + CAM_DBG(CAM_REQ, "ctx[%pK][%d] Enter for req_id %lld", + ctx, ctx->ctx_index, prepare->packet->header.request_id); + + rc = cam_packet_util_validate_packet(prepare->packet, + prepare->remain_len); + if (rc) + return rc; + + /* Pre parse the packet*/ + rc = cam_packet_util_get_kmd_buffer(prepare->packet, &kmd_buf); + if (rc) + return rc; + + rc = cam_packet_util_process_patches(prepare->packet, + hw_mgr->mgr_common.cmd_iommu_hdl, + hw_mgr->mgr_common.cmd_iommu_hdl_secure); + if (rc) { + CAM_ERR(CAM_ISP, "Patch ISP packet failed."); + return rc; + } + + prepare->num_hw_update_entries = 0; + prepare->num_in_map_entries = 0; + prepare->num_out_map_entries = 0; + + memset(&prepare_hw_data->bw_config[0], 0x0, + sizeof(prepare_hw_data->bw_config[0]) * + CAM_IFE_HW_NUM_MAX); + memset(&prepare_hw_data->bw_config_valid[0], 0x0, + sizeof(prepare_hw_data->bw_config_valid[0]) * + CAM_IFE_HW_NUM_MAX); + + for (i = 0; i < ctx->num_base; i++) { + CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i); + + /* Add change base */ + rc = cam_isp_add_change_base(prepare, &ctx->res_list_ife_src, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in change base i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + + + /* get command buffers */ + if (ctx->base[i].split_id != CAM_ISP_HW_SPLIT_MAX) { + rc = cam_isp_add_command_buffers(prepare, &kmd_buf, + &ctx->base[i], + cam_isp_packet_generic_blob_handler, + ctx->res_list_ife_out, CAM_IFE_HW_OUT_RES_MAX); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in add cmdbuf, i=%d, split_id=%d, rc=%d", + i, ctx->base[i].split_id, rc); + goto end; + } + } + + /* get IO buffers */ + rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl, + hw_mgr->mgr_common.img_iommu_hdl_secure, + prepare, ctx->base[i].idx, + &kmd_buf, ctx->res_list_ife_out, + &ctx->res_list_ife_in_rd, + CAM_IFE_HW_OUT_RES_MAX, fill_fence); + + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in io buffers, i=%d, rc=%d", + i, rc); + goto end; + } + + /* fence map table entries need to fill only once in the loop */ + if (fill_fence) + fill_fence = false; + } + + /* + * reg update will be done later for the initial configure. + * need to plus one to the op_code and only take the lower + * bits to get the type of operation since UMD definition + * of op_code has some difference from KMD. + */ + if (((prepare->packet->header.op_code + 1) & 0xF) == + CAM_ISP_PACKET_INIT_DEV) { + prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV; + goto end; + } else + prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_UPDATE_DEV; + + /* add reg update commands */ + for (i = 0; i < ctx->num_base; i++) { + /* Add change base */ + rc = cam_isp_add_change_base(prepare, &ctx->res_list_ife_src, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in change base adding reg_update cmd i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + + /*Add reg update */ + rc = cam_isp_add_reg_update(prepare, &ctx->res_list_ife_src, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Add Reg_update cmd Failed i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + } + +end: + return rc; +} + +static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx) +{ + return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE); +} + +static int cam_ife_mgr_sof_irq_debug( + struct cam_ife_hw_mgr_ctx *ctx, + uint32_t sof_irq_enable) +{ + int rc = 0; + uint32_t i = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_isp_resource_node *rsrc_node = NULL; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc |= hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF)) { + rc |= hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + return rc; +} + +static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + uint64_t iova_addr; + size_t src_buf_size; + int i; + int j; + int rc = 0; + int32_t mmu_hdl; + + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (pf_buf_info && + GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_ISP, + "Found PF at port: 0x%x mem 0x%x fd: 0x%x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_ISP, "port: 0x%x f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "get src buf address fail mem_handle 0x%x", + io_cfg[i].mem_handle[j]); + continue; + } + if (iova_addr >> 32) { + CAM_ERR(CAM_ISP, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_ISP, + "pln %d w %d h %d s %u size 0x%x addr 0x%x end_addr 0x%x offset %x memh %x", + j, io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + (unsigned int)src_buf_size, + (unsigned int)iova_addr, + (unsigned int)iova_addr + + (unsigned int)src_buf_size, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + } + } +} + +static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_ife_hw_mgr_ctx *ctx = (struct cam_ife_hw_mgr_ctx *) + hw_cmd_args->ctxt_to_hw_map; + struct cam_isp_hw_cmd_args *isp_hw_cmd_args = NULL; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Fatal: Invalid context is used"); + return -EPERM; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_INTERNAL: + if (!hw_cmd_args->u.internal_args) { + CAM_ERR(CAM_ISP, "Invalid cmd arguments"); + return -EINVAL; + } + + isp_hw_cmd_args = (struct cam_isp_hw_cmd_args *) + hw_cmd_args->u.internal_args; + + switch (isp_hw_cmd_args->cmd_type) { + case CAM_ISP_HW_MGR_CMD_PAUSE_HW: + cam_ife_mgr_pause_hw(ctx); + break; + case CAM_ISP_HW_MGR_CMD_RESUME_HW: + cam_ife_mgr_resume_hw(ctx); + break; + case CAM_ISP_HW_MGR_CMD_SOF_DEBUG: + cam_ife_mgr_sof_irq_debug(ctx, + isp_hw_cmd_args->u.sof_irq_enable); + break; + case CAM_ISP_HW_MGR_CMD_CTX_TYPE: + if (ctx->is_fe_enable) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2; + else if (ctx->is_rdi_only_context) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI; + else + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX; + break; + default: + CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", + hw_cmd_args->cmd_type); + rc = -EINVAL; + break; + } + break; + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_ife_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->mgr_common.img_iommu_hdl, + hw_mgr->mgr_common.img_iommu_hdl_secure, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + break; + default: + CAM_ERR(CAM_ISP, "Invalid cmd"); + } + + return rc; +} + +static int cam_ife_mgr_cmd_get_sof_timestamp( + struct cam_ife_hw_mgr_ctx *ife_ctx, + uint64_t *time_stamp, + uint64_t *boot_time_stamp) +{ + int rc = -EINVAL; + uint32_t i; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_csid_get_time_stamp_args csid_get_time; + + list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + /* + * Get the SOF time stamp from left resource only. + * Left resource is master for dual vfe case and + * Rdi only context case left resource only hold + * the RDI resource + */ + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + /* + * Single VFE case, Get the time stamp from + * available one csid hw in the context + * Dual VFE case, get the time stamp from + * master(left) would be sufficient + */ + + csid_get_time.node_res = + hw_mgr_res->hw_res[i]; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_CMD_GET_TIME_STAMP, + &csid_get_time, + sizeof( + struct cam_csid_get_time_stamp_args)); + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { + *time_stamp = + csid_get_time.time_stamp_val; + *boot_time_stamp = + csid_get_time.boot_timestamp; + } + } + } + } + + if (rc) + CAM_ERR_RATE_LIMIT(CAM_ISP, "Getting sof time stamp failed"); + + return rc; +} + +static int cam_ife_mgr_process_recovery_cb(void *priv, void *data) +{ + int32_t rc = 0; + struct cam_hw_event_recovery_data *recovery_data = data; + struct cam_hw_start_args start_args; + struct cam_hw_stop_args stop_args; + struct cam_ife_hw_mgr *ife_hw_mgr = priv; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t i = 0; + + uint32_t error_type = recovery_data->error_type; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + + /* Here recovery is performed */ + CAM_DBG(CAM_ISP, "ErrorType = %d", error_type); + + switch (error_type) { + case CAM_ISP_HW_ERROR_OVERFLOW: + case CAM_ISP_HW_ERROR_BUSIF_OVERFLOW: + if (!recovery_data->affected_ctx[0]) { + CAM_ERR(CAM_ISP, + "No context is affected but recovery called"); + kfree(recovery_data); + return 0; + } + /* stop resources here */ + CAM_DBG(CAM_ISP, "STOP: Number of affected context: %d", + recovery_data->no_of_context); + for (i = 0; i < recovery_data->no_of_context; i++) { + stop_args.ctxt_to_hw_map = + recovery_data->affected_ctx[i]; + rc = cam_ife_mgr_stop_hw_in_overflow(&stop_args); + if (rc) { + CAM_ERR(CAM_ISP, "CTX stop failed(%d)", rc); + return rc; + } + } + + CAM_DBG(CAM_ISP, "RESET: CSID PATH"); + for (i = 0; i < recovery_data->no_of_context; i++) { + ctx = recovery_data->affected_ctx[i]; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, + list) { + rc = cam_ife_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Failed RESET (%d)", + hw_mgr_res->res_id); + return rc; + } + } + } + + CAM_DBG(CAM_ISP, "RESET: Calling VFE reset"); + + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (recovery_data->affected_core[i]) + cam_ife_mgr_reset_vfe_hw(ife_hw_mgr, i); + } + + CAM_DBG(CAM_ISP, "START: Number of affected context: %d", + recovery_data->no_of_context); + + for (i = 0; i < recovery_data->no_of_context; i++) { + ctx = recovery_data->affected_ctx[i]; + start_args.ctxt_to_hw_map = ctx; + + atomic_set(&ctx->overflow_pending, 0); + + rc = cam_ife_mgr_restart_hw(&start_args); + if (rc) { + CAM_ERR(CAM_ISP, "CTX start failed(%d)", rc); + return rc; + } + CAM_DBG(CAM_ISP, "Started resources rc (%d)", rc); + } + CAM_DBG(CAM_ISP, "Recovery Done rc (%d)", rc); + + break; + + case CAM_ISP_HW_ERROR_P2I_ERROR: + break; + + case CAM_ISP_HW_ERROR_VIOLATION: + break; + + default: + CAM_ERR(CAM_ISP, "Invalid Error"); + } + CAM_DBG(CAM_ISP, "Exit: ErrorType = %d", error_type); + + kfree(recovery_data); + return rc; +} + +static int cam_ife_hw_mgr_do_error_recovery( + struct cam_hw_event_recovery_data *ife_mgr_recovery_data) +{ + int32_t rc = 0; + struct crm_workq_task *task = NULL; + struct cam_hw_event_recovery_data *recovery_data = NULL; + + recovery_data = kzalloc(sizeof(struct cam_hw_event_recovery_data), + GFP_ATOMIC); + if (!recovery_data) + return -ENOMEM; + + memcpy(recovery_data, ife_mgr_recovery_data, + sizeof(struct cam_hw_event_recovery_data)); + + CAM_DBG(CAM_ISP, "Enter: error_type (%d)", recovery_data->error_type); + + task = cam_req_mgr_workq_get_task(g_ife_hw_mgr.workq); + if (!task) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No empty task frame"); + kfree(recovery_data); + return -ENOMEM; + } + + task->process_cb = &cam_ife_mgr_process_recovery_cb; + task->payload = recovery_data; + rc = cam_req_mgr_workq_enqueue_task(task, + recovery_data->affected_ctx[0]->hw_mgr, + CRM_TASK_PRIORITY_0); + + return rc; +} + +/* + * This function checks if any of the valid entry in affected_core[] + * is associated with this context. if YES + * a. It fills the other cores associated with this context.in + * affected_core[] + * b. Return true + */ +static bool cam_ife_hw_mgr_is_ctx_affected( + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx, + uint32_t *affected_core, + uint32_t size) +{ + + bool rc = false; + uint32_t i = 0, j = 0; + uint32_t max_idx = ife_hwr_mgr_ctx->num_base; + uint32_t ctx_affected_core_idx[CAM_IFE_HW_NUM_MAX] = {0}; + + CAM_DBG(CAM_ISP, "Enter:max_idx = %d", max_idx); + + if ((max_idx >= CAM_IFE_HW_NUM_MAX) || (size > CAM_IFE_HW_NUM_MAX)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "invalid parameter = %d", max_idx); + return rc; + } + + for (i = 0; i < max_idx; i++) { + if (affected_core[ife_hwr_mgr_ctx->base[i].idx]) + rc = true; + else { + ctx_affected_core_idx[j] = ife_hwr_mgr_ctx->base[i].idx; + j = j + 1; + } + } + + if (rc) { + while (j) { + if (affected_core[ctx_affected_core_idx[j-1]] != 1) + affected_core[ctx_affected_core_idx[j-1]] = 1; + j = j - 1; + } + } + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +/* + * For any dual VFE context, if non-affected VFE is also serving + * another context, then that context should also be notified with fatal error + * So Loop through each context and - + * a. match core_idx + * b. Notify CTX with fatal error + */ +static int cam_ife_hw_mgr_find_affected_ctx( + struct cam_isp_hw_error_event_data *error_event_data, + uint32_t curr_core_idx, + struct cam_hw_event_recovery_data *recovery_data) +{ + uint32_t affected_core[CAM_IFE_HW_NUM_MAX] = {0}; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = NULL; + cam_hw_event_cb_func notify_err_cb; + struct cam_ife_hw_mgr *ife_hwr_mgr = NULL; + enum cam_isp_hw_event_type event_type = CAM_ISP_HW_EVENT_ERROR; + uint32_t i = 0; + + if (!recovery_data) { + CAM_ERR(CAM_ISP, "recovery_data parameter is NULL"); + return -EINVAL; + } + + recovery_data->no_of_context = 0; + affected_core[curr_core_idx] = 1; + ife_hwr_mgr = &g_ife_hw_mgr; + + list_for_each_entry(ife_hwr_mgr_ctx, + &ife_hwr_mgr->used_ctx_list, list) { + /* + * Check if current core_idx matches the HW associated + * with this context + */ + if (!cam_ife_hw_mgr_is_ctx_affected(ife_hwr_mgr_ctx, + affected_core, CAM_IFE_HW_NUM_MAX)) + continue; + + atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1); + notify_err_cb = ife_hwr_mgr_ctx->common.event_cb[event_type]; + + /* Add affected_context in list of recovery data */ + CAM_DBG(CAM_ISP, "Add affected ctx %d to list", + ife_hwr_mgr_ctx->ctx_index); + if (recovery_data->no_of_context < CAM_CTX_MAX) + recovery_data->affected_ctx[ + recovery_data->no_of_context++] = + ife_hwr_mgr_ctx; + + /* + * In the call back function corresponding ISP context + * will update CRM about fatal Error + */ + notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_ERROR, error_event_data); + } + + /* fill the affected_core in recovery data */ + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + recovery_data->affected_core[i] = affected_core[i]; + CAM_DBG(CAM_ISP, "Vfe core %d is affected (%d)", + i, recovery_data->affected_core[i]); + } + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_err( + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + uint32_t core_idx; + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_hw_event_recovery_data recovery_data = {0}; + int rc = -EINVAL; + + if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) + error_event_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_IN) + error_event_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) + error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + + core_idx = event_info->hw_idx; + + if (g_ife_hw_mgr.debug_cfg.enable_recovery) + error_event_data.recovery_enabled = true; + else + error_event_data.recovery_enabled = false; + + rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, + core_idx, &recovery_data); + + if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) + return rc; + + if (g_ife_hw_mgr.debug_cfg.enable_recovery) { + CAM_DBG(CAM_ISP, "IFE Mgr recovery is enabled"); + + /* Trigger for recovery */ + if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) + recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else + recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + cam_ife_hw_mgr_do_error_recovery(&recovery_data); + } else { + CAM_DBG(CAM_ISP, "recovery is not enabled"); + rc = 0; + } + + return rc; +} + +static int cam_ife_hw_mgr_handle_hw_rup( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hwr_irq_rup_cb; + struct cam_isp_hw_reg_update_event_data rup_event_data; + + ife_hwr_irq_rup_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + if (ife_hw_mgr_ctx->is_dual) + if (event_info->hw_idx != 1) + break; + + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hwr_irq_rup_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (!ife_hw_mgr_ctx->is_rdi_only_context) + break; + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hwr_irq_rup_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); + break; + + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "RUP done for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_check_irq_for_dual_vfe( + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx, + uint32_t hw_event_type) +{ + int32_t rc = -1; + uint32_t *event_cnt = NULL; + uint32_t core_idx0 = 0; + uint32_t core_idx1 = 1; + + if (!ife_hw_mgr_ctx->is_dual) + return 0; + + switch (hw_event_type) { + case CAM_ISP_HW_EVENT_SOF: + event_cnt = ife_hw_mgr_ctx->sof_cnt; + break; + case CAM_ISP_HW_EVENT_EPOCH: + event_cnt = ife_hw_mgr_ctx->epoch_cnt; + break; + case CAM_ISP_HW_EVENT_EOF: + event_cnt = ife_hw_mgr_ctx->eof_cnt; + break; + default: + return 0; + } + + if (event_cnt[core_idx0] == event_cnt[core_idx1]) { + + event_cnt[core_idx0] = 0; + event_cnt[core_idx1] = 0; + + rc = 0; + return rc; + } + + if ((event_cnt[core_idx0] && + (event_cnt[core_idx0] - event_cnt[core_idx1] > 1)) || + (event_cnt[core_idx1] && + (event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) { + + CAM_ERR_RATE_LIMIT(CAM_ISP, + "One of the VFE could not generate hw event %d", + hw_event_type); + rc = -1; + return rc; + } + + CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d", + hw_event_type); + + return rc; +} + +static int cam_ife_hw_mgr_handle_hw_epoch( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hw_irq_epoch_cb; + struct cam_isp_hw_epoch_event_data epoch_done_event_data; + int rc = 0; + + ife_hw_irq_epoch_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + ife_hw_mgr_ctx->epoch_cnt[event_info->hw_idx]++; + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, + CAM_ISP_HW_EVENT_EPOCH); + if (!rc) { + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); + } + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "Epoch for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_sof( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hw_irq_sof_cb; + struct cam_isp_hw_sof_event_data sof_done_event_data; + int rc = 0; + + ife_hw_irq_sof_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_RD: + ife_hw_mgr_ctx->sof_cnt[event_info->hw_idx]++; + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, + CAM_ISP_HW_EVENT_SOF); + if (!rc) { + cam_ife_mgr_cmd_get_sof_timestamp(ife_hw_mgr_ctx, + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); + + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + + ife_hw_irq_sof_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); + } + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (!ife_hw_mgr_ctx->is_rdi_only_context) + break; + cam_ife_mgr_cmd_get_sof_timestamp(ife_hw_mgr_ctx, + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hw_irq_sof_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); + break; + + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "SOF for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_eof( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hw_irq_eof_cb; + struct cam_isp_hw_eof_event_data eof_done_event_data; + int rc = 0; + + ife_hw_irq_eof_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + ife_hw_mgr_ctx->eof_cnt[event_info->hw_idx]++; + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, + CAM_ISP_HW_EVENT_EOF); + if (!rc) { + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hw_irq_eof_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EOF, &eof_done_event_data); + } + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "EOF for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_buf_done( + void *ctx, + void *evt_info) +{ + cam_hw_event_cb_func ife_hwr_irq_wm_done_cb; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + struct cam_isp_hw_done_event_data buf_done_event_data = {0}; + struct cam_isp_hw_event_info *event_info = evt_info; + + ife_hwr_irq_wm_done_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE]; + + buf_done_event_data.num_handles = 1; + buf_done_event_data.resource_handle[0] = event_info->res_id; + + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + return 0; + + if (buf_done_event_data.num_handles > 0 && ife_hwr_irq_wm_done_cb) { + CAM_DBG(CAM_ISP, "Notify ISP context"); + ife_hwr_irq_wm_done_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_DONE, &buf_done_event_data); + } + + CAM_DBG(CAM_ISP, "Buf done for VFE:%d out_res->res_id: 0x%x", + event_info->hw_idx, event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_event_handler( + void *priv, + uint32_t evt_id, + void *evt_info) +{ + int rc = 0; + + if (!evt_info) + return -EINVAL; + + if (!priv) + if (evt_id != CAM_ISP_HW_EVENT_ERROR) + return -EINVAL; + + CAM_DBG(CAM_ISP, "Event ID 0x%x", evt_id); + + switch (evt_id) { + case CAM_ISP_HW_EVENT_SOF: + rc = cam_ife_hw_mgr_handle_hw_sof(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_REG_UPDATE: + rc = cam_ife_hw_mgr_handle_hw_rup(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_EPOCH: + rc = cam_ife_hw_mgr_handle_hw_epoch(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_EOF: + rc = cam_ife_hw_mgr_handle_hw_eof(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_DONE: + rc = cam_ife_hw_mgr_handle_hw_buf_done(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_ERROR: + rc = cam_ife_hw_mgr_handle_hw_err(evt_info); + break; + + default: + CAM_ERR(CAM_ISP, "Invalid event ID %d", evt_id); + break; + } + + return rc; +} + +static int cam_ife_hw_mgr_sort_dev_with_caps( + struct cam_ife_hw_mgr *ife_hw_mgr) +{ + int i; + + /* get caps for csid devices */ + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + if (ife_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps) { + ife_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps( + ife_hw_mgr->csid_devices[i]->hw_priv, + &ife_hw_mgr->ife_csid_dev_caps[i], + sizeof(ife_hw_mgr->ife_csid_dev_caps[i])); + } + } + + /* get caps for ife devices */ + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->ife_devices[i]) + continue; + if (ife_hw_mgr->ife_devices[i]->hw_ops.get_hw_caps) { + ife_hw_mgr->ife_devices[i]->hw_ops.get_hw_caps( + ife_hw_mgr->ife_devices[i]->hw_priv, + &ife_hw_mgr->ife_dev_caps[i], + sizeof(ife_hw_mgr->ife_dev_caps[i])); + } + } + + return 0; +} + +static int cam_ife_set_csid_debug(void *data, u64 val) +{ + g_ife_hw_mgr.debug_cfg.csid_debug = val; + CAM_DBG(CAM_ISP, "Set CSID Debug value :%lld", val); + return 0; +} + +static int cam_ife_get_csid_debug(void *data, u64 *val) +{ + *val = g_ife_hw_mgr.debug_cfg.csid_debug; + CAM_DBG(CAM_ISP, "Get CSID Debug value :%lld", + g_ife_hw_mgr.debug_cfg.csid_debug); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_ife_csid_debug, + cam_ife_get_csid_debug, + cam_ife_set_csid_debug, "%16llu"); + +static int cam_ife_set_camif_debug(void *data, u64 val) +{ + g_ife_hw_mgr.debug_cfg.camif_debug = val; + CAM_DBG(CAM_ISP, + "Set camif enable_diag_sensor_status value :%lld", val); + return 0; +} + +static int cam_ife_get_camif_debug(void *data, u64 *val) +{ + *val = g_ife_hw_mgr.debug_cfg.camif_debug; + CAM_DBG(CAM_ISP, + "Set camif enable_diag_sensor_status value :%lld", + g_ife_hw_mgr.debug_cfg.csid_debug); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_ife_camif_debug, + cam_ife_get_camif_debug, + cam_ife_set_camif_debug, "%16llu"); + +static int cam_ife_hw_mgr_debug_register(void) +{ + g_ife_hw_mgr.debug_cfg.dentry = debugfs_create_dir("camera_ife", + NULL); + + if (!g_ife_hw_mgr.debug_cfg.dentry) { + CAM_ERR(CAM_ISP, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_file("ife_csid_debug", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, NULL, + &cam_ife_csid_debug)) { + CAM_ERR(CAM_ISP, "failed to create cam_ife_csid_debug"); + goto err; + } + + if (!debugfs_create_u32("enable_recovery", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_recovery"); + goto err; + } + + if (!debugfs_create_file("ife_camif_debug", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, NULL, + &cam_ife_camif_debug)) { + CAM_ERR(CAM_ISP, "failed to create cam_ife_camif_debug"); + goto err; + } + g_ife_hw_mgr.debug_cfg.enable_recovery = 0; + + return 0; + +err: + debugfs_remove_recursive(g_ife_hw_mgr.debug_cfg.dentry); + return -ENOMEM; +} + +int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) +{ + int rc = -EFAULT; + int i, j; + struct cam_iommu_handle cdm_handles; + struct cam_ife_hw_mgr_ctx *ctx_pool; + struct cam_ife_hw_mgr_res *res_list_ife_out; + + CAM_DBG(CAM_ISP, "Enter"); + + memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr)); + + mutex_init(&g_ife_hw_mgr.ctx_mutex); + + if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, "CSID num is different then IFE num"); + return -EINVAL; + } + + /* fill ife hw intf information */ + for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + rc = cam_vfe_hw_init(&g_ife_hw_mgr.ife_devices[i], i); + if (!rc) { + struct cam_hw_info *vfe_hw = + (struct cam_hw_info *) + g_ife_hw_mgr.ife_devices[i]->hw_priv; + struct cam_hw_soc_info *soc_info = &vfe_hw->soc_info; + + j++; + + g_ife_hw_mgr.cdm_reg_map[i] = &soc_info->reg_map[0]; + CAM_DBG(CAM_ISP, + "reg_map: mem base = %pK cam_base = 0x%llx", + (void __iomem *)soc_info->reg_map[0].mem_base, + (uint64_t) soc_info->reg_map[0].mem_cam_base); + } else { + g_ife_hw_mgr.cdm_reg_map[i] = NULL; + } + } + if (j == 0) { + CAM_ERR(CAM_ISP, "no valid IFE HW"); + return -EINVAL; + } + + /* fill csid hw intf information */ + for (i = 0, j = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + rc = cam_ife_csid_hw_init(&g_ife_hw_mgr.csid_devices[i], i); + if (!rc) + j++; + } + if (!j) { + CAM_ERR(CAM_ISP, "no valid IFE CSID HW"); + return -EINVAL; + } + + cam_ife_hw_mgr_sort_dev_with_caps(&g_ife_hw_mgr); + + /* setup ife context list */ + INIT_LIST_HEAD(&g_ife_hw_mgr.free_ctx_list); + INIT_LIST_HEAD(&g_ife_hw_mgr.used_ctx_list); + + /* + * for now, we only support one iommu handle. later + * we will need to setup more iommu handle for other + * use cases. + * Also, we have to release them once we have the + * deinit support + */ + if (cam_smmu_get_handle("ife", + &g_ife_hw_mgr.mgr_common.img_iommu_hdl)) { + CAM_ERR(CAM_ISP, "Can not get iommu handle"); + return -EINVAL; + } + + if (cam_smmu_get_handle("cam-secure", + &g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure)) { + CAM_ERR(CAM_ISP, "Failed to get secure iommu handle"); + goto secure_fail; + } + + CAM_DBG(CAM_ISP, "iommu_handles: non-secure[0x%x], secure[0x%x]", + g_ife_hw_mgr.mgr_common.img_iommu_hdl, + g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure); + + if (!cam_cdm_get_iommu_handle("ife", &cdm_handles)) { + CAM_DBG(CAM_ISP, "Successfully acquired the CDM iommu handles"); + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl = cdm_handles.non_secure; + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl_secure = + cdm_handles.secure; + } else { + CAM_DBG(CAM_ISP, "Failed to acquire the CDM iommu handles"); + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl = -1; + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl_secure = -1; + } + + atomic_set(&g_ife_hw_mgr.active_ctx_cnt, 0); + for (i = 0; i < CAM_CTX_MAX; i++) { + memset(&g_ife_hw_mgr.ctx_pool[i], 0, + sizeof(g_ife_hw_mgr.ctx_pool[i])); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].list); + + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_in.list); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_cid); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_csid); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_src); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_in_rd); + ctx_pool = &g_ife_hw_mgr.ctx_pool[i]; + for (j = 0; j < CAM_IFE_HW_OUT_RES_MAX; j++) { + res_list_ife_out = &ctx_pool->res_list_ife_out[j]; + INIT_LIST_HEAD(&res_list_ife_out->list); + } + + /* init context pool */ + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].free_res_list); + for (j = 0; j < CAM_IFE_HW_RES_POOL_MAX; j++) { + INIT_LIST_HEAD( + &g_ife_hw_mgr.ctx_pool[i].res_pool[j].list); + list_add_tail( + &g_ife_hw_mgr.ctx_pool[i].res_pool[j].list, + &g_ife_hw_mgr.ctx_pool[i].free_res_list); + } + + g_ife_hw_mgr.ctx_pool[i].cdm_cmd = + kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((CAM_IFE_HW_ENTRIES_MAX - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!g_ife_hw_mgr.ctx_pool[i].cdm_cmd) { + rc = -ENOMEM; + CAM_ERR(CAM_ISP, "Allocation Failed for cdm command"); + goto end; + } + + g_ife_hw_mgr.ctx_pool[i].ctx_index = i; + g_ife_hw_mgr.ctx_pool[i].hw_mgr = &g_ife_hw_mgr; + + cam_tasklet_init(&g_ife_hw_mgr.mgr_common.tasklet_pool[i], + &g_ife_hw_mgr.ctx_pool[i], i); + g_ife_hw_mgr.ctx_pool[i].common.tasklet_info = + g_ife_hw_mgr.mgr_common.tasklet_pool[i]; + + + init_completion(&g_ife_hw_mgr.ctx_pool[i].config_done_complete); + list_add_tail(&g_ife_hw_mgr.ctx_pool[i].list, + &g_ife_hw_mgr.free_ctx_list); + } + + /* Create Worker for ife_hw_mgr with 10 tasks */ + rc = cam_req_mgr_workq_create("cam_ife_worker", 10, + &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Unable to create worker"); + goto end; + } + + /* fill return structure */ + hw_mgr_intf->hw_mgr_priv = &g_ife_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_ife_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_ife_mgr_acquire; + hw_mgr_intf->hw_start = cam_ife_mgr_start_hw; + hw_mgr_intf->hw_stop = cam_ife_mgr_stop_hw; + hw_mgr_intf->hw_read = cam_ife_mgr_read; + hw_mgr_intf->hw_write = cam_ife_mgr_write; + hw_mgr_intf->hw_release = cam_ife_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update; + hw_mgr_intf->hw_config = cam_ife_mgr_config_hw; + hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd; + + if (iommu_hdl) + *iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl; + + cam_ife_hw_mgr_debug_register(); + CAM_DBG(CAM_ISP, "Exit"); + + return 0; +end: + if (rc) { + for (i = 0; i < CAM_CTX_MAX; i++) { + cam_tasklet_deinit( + &g_ife_hw_mgr.mgr_common.tasklet_pool[i]); + kfree(g_ife_hw_mgr.ctx_pool[i].cdm_cmd); + g_ife_hw_mgr.ctx_pool[i].cdm_cmd = NULL; + g_ife_hw_mgr.ctx_pool[i].common.tasklet_info = NULL; + } + } + cam_smmu_destroy_handle( + g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure); + g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure = -1; +secure_fail: + cam_smmu_destroy_handle(g_ife_hw_mgr.mgr_common.img_iommu_hdl); + g_ife_hw_mgr.mgr_common.img_iommu_hdl = -1; + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h new file mode 100644 index 000000000000..16143b014ebf --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_HW_MGR_H_ +#define _CAM_IFE_HW_MGR_H_ + +#include +#include "cam_isp_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_tasklet_util.h" + +/* enum cam_ife_hw_mgr_res_type - manager resource node type */ +enum cam_ife_hw_mgr_res_type { + CAM_IFE_HW_MGR_RES_UNINIT, + CAM_IFE_HW_MGR_RES_ROOT, + CAM_IFE_HW_MGR_RES_CID, + CAM_IFE_HW_MGR_RES_CSID, + CAM_IFE_HW_MGR_RES_IFE_SRC, + CAM_IFE_HW_MGR_RES_IFE_IN_RD, + CAM_IFE_HW_MGR_RES_IFE_OUT, +}; + +/* IFE resource constants */ +#define CAM_IFE_HW_IN_RES_MAX (CAM_ISP_IFE_IN_RES_MAX & 0xFF) +#define CAM_IFE_HW_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_MAX & 0xFF) +#define CAM_IFE_HW_RES_POOL_MAX 64 + +/** + * struct cam_vfe_hw_mgr_res- HW resources for the VFE manager + * + * @list: used by the resource list + * @res_type: IFE manager resource type + * @res_id: resource id based on the resource type for root or + * leaf resource, it matches the KMD interface port id. + * For branch resrouce, it is defined by the ISP HW + * layer + * @hw_res: hw layer resource array. For single VFE, only one VFE + * hw resrouce will be acquired. For dual VFE, two hw + * resources from different VFE HW device will be + * acquired + * @parent: point to the parent resource node. + * @children: point to the children resource nodes + * @child_num: numbe of the child resource node. + * @is_secure informs whether the resource is in secure mode or not + * + */ +struct cam_ife_hw_mgr_res { + struct list_head list; + enum cam_ife_hw_mgr_res_type res_type; + uint32_t res_id; + uint32_t is_dual_vfe; + struct cam_isp_resource_node *hw_res[CAM_ISP_HW_SPLIT_MAX]; + + /* graph */ + struct cam_ife_hw_mgr_res *parent; + struct cam_ife_hw_mgr_res *child[CAM_IFE_HW_OUT_RES_MAX]; + uint32_t num_children; + uint32_t is_secure; +}; + + +/** + * struct ctx_base_info - Base hardware information for the context + * + * @idx: Base resource index + * @split_id: Split info for the base resource + * + */ +struct ctx_base_info { + uint32_t idx; + enum cam_isp_hw_split_id split_id; +}; + +/** + * struct cam_ife_hw_mgr_debug - contain the debug information + * + * @dentry: Debugfs entry + * @csid_debug: csid debug information + * @enable_recovery: enable recovery + * @enable_diag_sensor_status: enable sensor diagnosis status + * @enable_req_dump: Enable request dump on HW errors + * + */ +struct cam_ife_hw_mgr_debug { + struct dentry *dentry; + uint64_t csid_debug; + uint32_t enable_recovery; + uint32_t camif_debug; + uint32_t enable_req_dump; +}; + +/** + * struct cam_vfe_hw_mgr_ctx - IFE HW manager Context object + * + * @list: used by the ctx list. + * @common: common acquired context data + * @ctx_index: acquired context id. + * @hw_mgr: IFE hw mgr which owns this context + * @ctx_in_use: flag to tell whether context is active + * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be + * one. + * @res_list_csid: CSID resource list + * @res_list_ife_src: IFE input resource list + * @res_list_ife_in_rd IFE input resource list for read path + * @res_list_ife_out: IFE output resoruces array + * @free_res_list: Free resources list for the branch node + * @res_pool: memory storage for the free resource list + * @irq_status0_mask: irq_status0_mask for the context + * @irq_status1_mask: irq_status1_mask for the context + * @base device base index array contain the all IFE HW + * instance associated with this context. + * @num_base number of valid base data in the base array + * @cdm_handle cdm hw acquire handle + * @cdm_ops cdm util operation pointer for building + * cdm commands + * @cdm_cmd cdm base and length request pointer + * @sof_cnt sof count value per core, used for dual VFE + * @epoch_cnt epoch count value per core, used for dual VFE + * @eof_cnt eof count value per core, used for dual VFE + * @overflow_pending flat to specify the overflow is pending for the + * context + * @is_rdi_only_context flag to specify the context has only rdi resource + * @config_done_complete indicator for configuration complete + * @init_done indicate whether init hw is done + * @is_fe_enable indicate whether fetch engine\read path is enabled + * @is_dual indicate whether context is in dual VFE mode + */ +struct cam_ife_hw_mgr_ctx { + struct list_head list; + struct cam_isp_hw_mgr_ctx common; + + uint32_t ctx_index; + struct cam_ife_hw_mgr *hw_mgr; + uint32_t ctx_in_use; + + struct cam_ife_hw_mgr_res res_list_ife_in; + struct list_head res_list_ife_cid; + struct list_head res_list_ife_csid; + struct list_head res_list_ife_src; + struct list_head res_list_ife_in_rd; + struct cam_ife_hw_mgr_res res_list_ife_out[ + CAM_IFE_HW_OUT_RES_MAX]; + + struct list_head free_res_list; + struct cam_ife_hw_mgr_res res_pool[CAM_IFE_HW_RES_POOL_MAX]; + + uint32_t irq_status0_mask[CAM_IFE_HW_NUM_MAX]; + uint32_t irq_status1_mask[CAM_IFE_HW_NUM_MAX]; + struct ctx_base_info base[CAM_IFE_HW_NUM_MAX]; + uint32_t num_base; + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; + struct cam_cdm_bl_request *cdm_cmd; + + uint32_t sof_cnt[CAM_IFE_HW_NUM_MAX]; + uint32_t epoch_cnt[CAM_IFE_HW_NUM_MAX]; + uint32_t eof_cnt[CAM_IFE_HW_NUM_MAX]; + atomic_t overflow_pending; + uint32_t is_rdi_only_context; + struct completion config_done_complete; + bool init_done; + bool is_fe_enable; + bool is_dual; +}; + +/** + * struct cam_ife_hw_mgr - IFE HW Manager + * + * @mgr_common: common data for all HW managers + * @csid_devices; csid device instances array. This will be filled by + * HW manager during the initialization. + * @ife_devices: IFE device instances array. This will be filled by + * HW layer during initialization + * @ctx_mutex: mutex for the hw context pool + * @free_ctx_list: free hw context list + * @used_ctx_list: used hw context list + * @ctx_pool: context storage + * @ife_csid_dev_caps csid device capability stored per core + * @ife_dev_caps ife device capability per core + * @work q work queue for IFE hw manager + * @debug_cfg debug configuration + */ +struct cam_ife_hw_mgr { + struct cam_isp_hw_mgr mgr_common; + struct cam_hw_intf *csid_devices[CAM_IFE_CSID_HW_NUM_MAX]; + struct cam_hw_intf *ife_devices[CAM_IFE_HW_NUM_MAX]; + struct cam_soc_reg_map *cdm_reg_map[CAM_IFE_HW_NUM_MAX]; + + struct mutex ctx_mutex; + atomic_t active_ctx_cnt; + struct list_head free_ctx_list; + struct list_head used_ctx_list; + struct cam_ife_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; + + struct cam_ife_csid_hw_caps ife_csid_dev_caps[ + CAM_IFE_CSID_HW_NUM_MAX]; + struct cam_vfe_hw_get_hw_cap ife_dev_caps[CAM_IFE_HW_NUM_MAX]; + struct cam_req_mgr_core_workq *workq; + struct cam_ife_hw_mgr_debug debug_cfg; +}; + +/** + * cam_ife_hw_mgr_init() + * + * @brief: Initialize the IFE hardware manger. This is the + * etnry functinon for the IFE HW manager. + * + * @hw_mgr_intf: IFE hardware manager object returned + * @iommu_hdl: Iommu handle to be returned + * + */ +int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); + +#endif /* _CAM_IFE_HW_MGR_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c new file mode 100644 index 000000000000..b1567d6b9cd8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_isp_hw_mgr_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_debug_util.h" + + +int cam_isp_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl) +{ + int rc = 0; + const char *compat_str = NULL; + + rc = of_property_read_string_index(of_node, "arch-compat", 0, + (const char **)&compat_str); + + if (strnstr(compat_str, "ife", strlen(compat_str))) + rc = cam_ife_hw_mgr_init(hw_mgr, iommu_hdl); + else { + CAM_ERR(CAM_ISP, "Invalid ISP hw type"); + rc = -EINVAL; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h new file mode 100644 index 000000000000..69e24bcc8625 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_MGR_H_ +#define _CAM_ISP_HW_MGR_H_ + +#include "cam_isp_hw_mgr_intf.h" +#include "cam_tasklet_util.h" + +#define CAM_ISP_HW_NUM_MAX 7 + +/** + * struct cam_isp_hw_mgr_ctx - common acquired context for managers + * + * @takslet_info: assciated tasklet + * @event_cb: call back interface to ISP context. Set during + * acquire device + * @cb_priv: first argument for the call back function + * set during acquire device + * + */ +struct cam_isp_hw_mgr_ctx { + void *tasklet_info; + cam_hw_event_cb_func event_cb[CAM_ISP_HW_EVENT_MAX]; + void *cb_priv; +}; + +/** + * struct cam_isp_hw_mgr - ISP HW Manager common object + * + * @tasklet_pool: Tasklet pool + * @img_iommu_hdl: iommu memory handle for regular image buffer + * @img_iommu_hdl_secure: iommu memory handle for secure image buffer + * @cmd_iommu_hdl: iommu memory handle for regular command buffer + * @cmd_iommu_hdl: iommu memory handle for secure command buffer + * @scratch_buf_range: scratch buffer range (not for IFE) + * @scratch_buf_addr: scratch buffer address (not for IFE) + * + */ +struct cam_isp_hw_mgr { + void *tasklet_pool[CAM_CTX_MAX]; + int img_iommu_hdl; + int img_iommu_hdl_secure; + int cmd_iommu_hdl; + int cmd_iommu_hdl_secure; + uint32_t scratch_buf_range; + dma_addr_t scratch_buf_addr; +}; + +/** + * struct cam_hw_event_recovery_data - Payload for the recovery procedure + * + * @error_type: Error type that causes the recovery + * @affected_core: Array of the hardware cores that are affected + * @affected_ctx: Array of the hardware contexts that are affected + * @no_of_context: Actual number of the affected context + * + */ +struct cam_hw_event_recovery_data { + uint32_t error_type; + uint32_t affected_core[CAM_ISP_HW_NUM_MAX]; + struct cam_ife_hw_mgr_ctx *affected_ctx[CAM_CTX_MAX]; + uint32_t no_of_context; +}; +#endif /* _CAM_ISP_HW_MGR_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile b/drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile new file mode 100644 index 000000000000..ccdfc05f103d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_tasklet_util.o cam_isp_packet_parser.o +obj-$(CONFIG_SPECTRA_CAMERA) += irq_controller/ diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c new file mode 100644 index 000000000000..be098a619aaf --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -0,0 +1,916 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_mem_mgr.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_isp_packet_parser.h" +#include "cam_debug_util.h" + +int cam_isp_add_change_base( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int rc = -EINVAL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res; + struct cam_isp_hw_get_cmd_update get_base; + struct cam_hw_update_entry *hw_entry; + uint32_t num_ent, i; + + hw_entry = prepare->hw_update_entries; + num_ent = prepare->num_hw_update_entries; + + /* Max one hw entries required for each base */ + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + list_for_each_entry(hw_mgr_res, res_list_isp_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + if (res->hw_intf->hw_idx != base_idx) + continue; + + get_base.res = res; + get_base.cmd_type = CAM_ISP_HW_CMD_GET_CHANGE_BASE; + get_base.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4; + get_base.cmd.size = kmd_buf_info->size - + kmd_buf_info->used_bytes; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_CHANGE_BASE, &get_base, + sizeof(struct cam_isp_hw_get_cmd_update)); + if (rc) + return rc; + + hw_entry[num_ent].handle = kmd_buf_info->handle; + hw_entry[num_ent].len = get_base.cmd.used_bytes; + hw_entry[num_ent].offset = kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + + kmd_buf_info->used_bytes += get_base.cmd.used_bytes; + kmd_buf_info->offset += get_base.cmd.used_bytes; + num_ent++; + prepare->num_hw_update_entries = num_ent; + + /* return success */ + return 0; + } + } + + return rc; +} + +static int cam_isp_update_dual_config( + struct cam_hw_prepare_update_args *prepare, + struct cam_cmd_buf_desc *cmd_desc, + uint32_t split_id, + uint32_t base_idx, + struct cam_ife_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out) +{ + int rc = -EINVAL; + struct cam_isp_dual_config *dual_config; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res; + struct cam_isp_hw_dual_isp_update_args dual_isp_update_args; + uint32_t outport_id; + uint32_t ports_plane_idx; + size_t len = 0, remain_len = 0; + uint32_t *cpu_addr; + uint32_t i, j; + + CAM_DBG(CAM_ISP, "cmd des size %d, length: %d", + cmd_desc->size, cmd_desc->length); + + rc = cam_packet_util_get_cmd_mem_addr( + cmd_desc->mem_handle, &cpu_addr, &len); + if (rc) + return rc; + + if ((len < sizeof(struct cam_isp_dual_config)) || + (cmd_desc->offset >= + (len - sizeof(struct cam_isp_dual_config)))) { + CAM_ERR(CAM_ISP, "not enough buffer provided"); + return -EINVAL; + } + remain_len = len - cmd_desc->offset; + cpu_addr += (cmd_desc->offset / 4); + dual_config = (struct cam_isp_dual_config *)cpu_addr; + + if ((dual_config->num_ports * + sizeof(struct cam_isp_dual_stripe_config)) > + (remain_len - offsetof(struct cam_isp_dual_config, stripes))) { + CAM_ERR(CAM_ISP, "not enough buffer for all the dual configs"); + return -EINVAL; + } + for (i = 0; i < dual_config->num_ports; i++) { + + if (i >= CAM_ISP_IFE_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, + "failed update for i:%d > size_isp_out:%d", + i, size_isp_out); + rc = -EINVAL; + goto end; + } + + hw_mgr_res = &res_list_isp_out[i]; + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + + if (res->res_id < CAM_ISP_IFE_OUT_RES_BASE || + res->res_id >= CAM_ISP_IFE_OUT_RES_MAX) + continue; + + outport_id = res->res_id & 0xFF; + + ports_plane_idx = (j * (dual_config->num_ports * + CAM_PACKET_MAX_PLANES)) + + (outport_id * CAM_PACKET_MAX_PLANES); + + if (dual_config->stripes[ports_plane_idx].port_id == 0) + continue; + + dual_isp_update_args.split_id = j; + dual_isp_update_args.res = res; + dual_isp_update_args.dual_cfg = dual_config; + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_STRIPE_UPDATE, + &dual_isp_update_args, + sizeof(struct cam_isp_hw_dual_isp_update_args)); + if (rc) + goto end; + } + } + +end: + return rc; +} + +int cam_isp_add_cmd_buf_update( + struct cam_ife_hw_mgr_res *hw_mgr_res, + uint32_t cmd_type, + uint32_t hw_cmd_type, + uint32_t base_idx, + uint32_t *cmd_buf_addr, + uint32_t kmd_buf_remain_size, + void *cmd_update_data, + uint32_t *bytes_used) +{ + int rc = 0; + struct cam_isp_resource_node *res; + struct cam_isp_hw_get_cmd_update cmd_update; + uint32_t i; + uint32_t total_used_bytes = 0; + + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + CAM_ERR(CAM_ISP, "io res id:%d not valid", + hw_mgr_res->res_type); + return -EINVAL; + } + + cmd_update.cmd_type = hw_cmd_type; + cmd_update.cmd.cmd_buf_addr = cmd_buf_addr; + cmd_update.cmd.size = kmd_buf_remain_size; + cmd_update.cmd.used_bytes = 0; + cmd_update.data = cmd_update_data; + CAM_DBG(CAM_ISP, "cmd_type %u cmd buffer 0x%pK, size %d", + cmd_update.cmd_type, + cmd_update.cmd.cmd_buf_addr, + cmd_update.cmd.size); + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->hw_res[i]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[i]; + cmd_update.res = res; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + cmd_update.cmd_type, &cmd_update, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + total_used_bytes += cmd_update.cmd.used_bytes; + } + *bytes_used = total_used_bytes; + CAM_DBG(CAM_ISP, "total_used_bytes %u", total_used_bytes); + return rc; +} + +int cam_isp_add_command_buffers( + struct cam_hw_prepare_update_args *prepare, + struct cam_kmd_buf_info *kmd_buf_info, + struct ctx_base_info *base_info, + cam_packet_generic_blob_handler blob_handler_cb, + struct cam_ife_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out) +{ + int rc = 0; + uint32_t cmd_meta_data, num_ent, i; + uint32_t base_idx; + enum cam_isp_hw_split_id split_id; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_hw_update_entry *hw_entry; + + hw_entry = prepare->hw_update_entries; + split_id = base_info->split_id; + base_idx = base_info->idx; + + /* + * set the cmd_desc to point the first command descriptor in the + * packet + */ + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint8_t *)&prepare->packet->payload + + prepare->packet->cmd_buf_offset); + + CAM_DBG(CAM_ISP, "split id = %d, number of command buffers:%d", + split_id, prepare->packet->num_cmd_buf); + + for (i = 0; i < prepare->packet->num_cmd_buf; i++) { + num_ent = prepare->num_hw_update_entries; + if (!cmd_desc[i].length) + continue; + + /* One hw entry space required for left or right or common */ + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) + return rc; + + cmd_meta_data = cmd_desc[i].meta_data; + + CAM_DBG(CAM_ISP, "meta type: %d, split_id: %d", + cmd_meta_data, split_id); + + switch (cmd_meta_data) { + case CAM_ISP_PACKET_META_BASE: + case CAM_ISP_PACKET_META_LEFT: + case CAM_ISP_PACKET_META_DMI_LEFT: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Left num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + + if (cmd_meta_data == + CAM_ISP_PACKET_META_DMI_LEFT) + hw_entry[num_ent].flags = 0x1; + + num_ent++; + } + break; + case CAM_ISP_PACKET_META_RIGHT: + case CAM_ISP_PACKET_META_DMI_RIGHT: + if (split_id == CAM_ISP_HW_SPLIT_RIGHT) { + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Right num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + + if (cmd_meta_data == + CAM_ISP_PACKET_META_DMI_RIGHT) + hw_entry[num_ent].flags = 0x1; + num_ent++; + } + break; + case CAM_ISP_PACKET_META_COMMON: + case CAM_ISP_PACKET_META_DMI_COMMON: + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Common num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON) + hw_entry[num_ent].flags = 0x1; + + num_ent++; + break; + case CAM_ISP_PACKET_META_DUAL_CONFIG: + rc = cam_isp_update_dual_config(prepare, + &cmd_desc[i], split_id, base_idx, + res_list_isp_out, size_isp_out); + + if (rc) + return rc; + break; + case CAM_ISP_PACKET_META_GENERIC_BLOB_LEFT: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + struct cam_isp_generic_blob_info blob_info; + + prepare->num_hw_update_entries = num_ent; + blob_info.prepare = prepare; + blob_info.base_info = base_info; + blob_info.kmd_buf_info = kmd_buf_info; + + rc = cam_packet_util_process_generic_cmd_buffer( + &cmd_desc[i], + blob_handler_cb, + &blob_info); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in processing blobs %d", + rc); + return rc; + } + num_ent = prepare->num_hw_update_entries; + } + break; + case CAM_ISP_PACKET_META_GENERIC_BLOB_RIGHT: + if (split_id == CAM_ISP_HW_SPLIT_RIGHT) { + struct cam_isp_generic_blob_info blob_info; + + prepare->num_hw_update_entries = num_ent; + blob_info.prepare = prepare; + blob_info.base_info = base_info; + blob_info.kmd_buf_info = kmd_buf_info; + + rc = cam_packet_util_process_generic_cmd_buffer( + &cmd_desc[i], + blob_handler_cb, + &blob_info); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in processing blobs %d", + rc); + return rc; + } + num_ent = prepare->num_hw_update_entries; + } + break; + case CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON: { + struct cam_isp_generic_blob_info blob_info; + + prepare->num_hw_update_entries = num_ent; + blob_info.prepare = prepare; + blob_info.base_info = base_info; + blob_info.kmd_buf_info = kmd_buf_info; + + rc = cam_packet_util_process_generic_cmd_buffer( + &cmd_desc[i], + blob_handler_cb, + &blob_info); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in processing blobs %d", rc); + return rc; + } + num_ent = prepare->num_hw_update_entries; + } + break; + default: + CAM_ERR(CAM_ISP, "invalid cdm command meta data %d", + cmd_meta_data); + return -EINVAL; + } + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +int cam_isp_add_io_buffers( + int iommu_hdl, + int sec_iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info, + struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, + uint32_t size_isp_out, + bool fill_fence) +{ + int rc = 0; + uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + struct cam_buf_io_cfg *io_cfg; + struct cam_isp_resource_node *res; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_get_cmd_update update_buf; + struct cam_isp_hw_get_wm_update wm_update; + struct cam_isp_hw_get_wm_update bus_rd_update; + struct cam_hw_fence_map_entry *out_map_entries; + struct cam_hw_fence_map_entry *in_map_entries; + uint32_t kmd_buf_remain_size; + uint32_t i, j, num_out_buf, num_in_buf; + uint32_t res_id_out, res_id_in, plane_id; + uint32_t io_cfg_used_bytes, num_ent; + size_t size; + int32_t hdl; + int mmu_hdl; + bool mode, is_buf_secure; + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &prepare->packet->payload + + prepare->packet->io_configs_offset); + num_out_buf = 0; + num_in_buf = 0; + io_cfg_used_bytes = 0; + prepare->pf_data->packet = prepare->packet; + + /* Max one hw entries required for each base */ + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_ISP, "======= io config idx %d ============", i); + CAM_DBG(CAM_REQ, + "i %d req_id %llu resource_type:%d fence:%d direction %d", + i, prepare->packet->header.request_id, + io_cfg[i].resource_type, io_cfg[i].fence, + io_cfg[i].direction); + CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); + + if (io_cfg[i].direction == CAM_BUF_OUTPUT) { + res_id_out = io_cfg[i].resource_type & 0xFF; + if (res_id_out >= size_isp_out) { + CAM_ERR(CAM_ISP, "invalid out restype:%x", + io_cfg[i].resource_type); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, + "configure output io with fill fence %d", + fill_fence); + out_map_entries = + &prepare->out_map_entries[num_out_buf]; + if (fill_fence) { + if (num_out_buf < + prepare->max_out_map_entries) { + out_map_entries->resource_handle = + io_cfg[i].resource_type; + out_map_entries->sync_id = + io_cfg[i].fence; + num_out_buf++; + } else { + CAM_ERR(CAM_ISP, "ln_out:%d max_ln:%d", + num_out_buf, + prepare->max_out_map_entries); + return -EINVAL; + } + } + + hw_mgr_res = &res_list_isp_out[res_id_out]; + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + CAM_ERR(CAM_ISP, "io res id:%d not valid", + io_cfg[i].resource_type); + return -EINVAL; + } + } else if (io_cfg[i].direction == CAM_BUF_INPUT) { + res_id_in = io_cfg[i].resource_type & 0xFF; + CAM_DBG(CAM_ISP, + "configure input io with fill fence %d", + fill_fence); + if (!list_empty(res_list_ife_in_rd)) { + hw_mgr_res = + list_first_entry(res_list_ife_in_rd, + struct cam_ife_hw_mgr_res, list); + } else { + CAM_ERR(CAM_ISP, + "No IFE in Read resource"); + return -EINVAL; + } + in_map_entries = + &prepare->in_map_entries[num_in_buf]; + if (fill_fence) { + if (num_in_buf < prepare->max_in_map_entries) { + in_map_entries->resource_handle = + io_cfg[i].resource_type; + in_map_entries->sync_id = + io_cfg[i].fence; + num_in_buf++; + } else { + CAM_ERR(CAM_ISP, "ln_in:%d imax_ln:%d", + num_in_buf, + prepare->max_in_map_entries); + return -EINVAL; + } + } + } else { + CAM_ERR(CAM_ISP, "Invalid io config direction :%d", + io_cfg[i].direction); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "setup mem io"); + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_OUTPUT; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + if (res->res_id != io_cfg[i].resource_type) { + CAM_ERR(CAM_ISP, + "wm err res id:%d io res id:%d", + res->res_id, io_cfg[i].resource_type); + return -EINVAL; + } + + memset(io_addr, 0, sizeof(io_addr)); + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + break; + + hdl = io_cfg[i].mem_handle[plane_id]; + if (res->process_cmd(res, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, + sizeof(bool))) + return -EINVAL; + + is_buf_secure = cam_mem_is_secure_buf(hdl); + if ((mode == CAM_SECURE_MODE_SECURE) && + is_buf_secure) { + mmu_hdl = sec_iommu_hdl; + } else if ( + (mode == CAM_SECURE_MODE_NON_SECURE) && + (!is_buf_secure)) { + mmu_hdl = iommu_hdl; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid hdl: port mode[%u], buf mode[%u]", + mode, is_buf_secure); + return -EINVAL; + } + + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane_id], + mmu_hdl, &io_addr[plane_id], &size); + if (rc) { + CAM_ERR(CAM_ISP, + "no io addr for plane%d", + plane_id); + rc = -ENOMEM; + return rc; + } + + /* need to update with offset */ + io_addr[plane_id] += + io_cfg[i].offsets[plane_id]; + CAM_DBG(CAM_ISP, + "get io_addr for plane %d: 0x%llx, mem_hdl=0x%x", + plane_id, io_addr[plane_id], + io_cfg[i].mem_handle[plane_id]); + + CAM_DBG(CAM_ISP, + "mmu_hdl=0x%x, size=%d, end=0x%x", + mmu_hdl, (int)size, + io_addr[plane_id]+size); + + } + if (!plane_id) { + CAM_ERR(CAM_ISP, "No valid planes for res%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + if ((kmd_buf_info->used_bytes + io_cfg_used_bytes) < + kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + io_cfg_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + base_idx); + rc = -ENOMEM; + return rc; + } + update_buf.res = res; + update_buf.cmd_type = CAM_ISP_HW_CMD_GET_BUF_UPDATE; + update_buf.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + io_cfg_used_bytes/4; + wm_update.image_buf = io_addr; + wm_update.num_buf = plane_id; + wm_update.io_cfg = &io_cfg[i]; + update_buf.cmd.size = kmd_buf_remain_size; + update_buf.wm_update = &wm_update; + + CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", + update_buf.cmd.cmd_buf_addr, + update_buf.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_BUF_UPDATE, &update_buf, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + io_cfg_used_bytes += update_buf.cmd.used_bytes; + } + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_INPUT; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + + memset(io_addr, 0, sizeof(io_addr)); + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + break; + + hdl = io_cfg[i].mem_handle[plane_id]; + if (res->process_cmd(res, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, + sizeof(bool))) + return -EINVAL; + + is_buf_secure = cam_mem_is_secure_buf(hdl); + if ((mode == CAM_SECURE_MODE_SECURE) && + is_buf_secure) { + mmu_hdl = sec_iommu_hdl; + } else if ( + (mode == CAM_SECURE_MODE_NON_SECURE) && + (!is_buf_secure)) { + mmu_hdl = iommu_hdl; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid hdl: port mode[%u], buf mode[%u]", + mode, is_buf_secure); + return -EINVAL; + } + + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane_id], + mmu_hdl, &io_addr[plane_id], &size); + if (rc) { + CAM_ERR(CAM_ISP, + "no io addr for plane%d", + plane_id); + rc = -ENOMEM; + return rc; + } + + /* need to update with offset */ + io_addr[plane_id] += + io_cfg[i].offsets[plane_id]; + CAM_DBG(CAM_ISP, + "get io_addr for plane %d: 0x%llx, mem_hdl=0x%x", + plane_id, io_addr[plane_id], + io_cfg[i].mem_handle[plane_id]); + + CAM_DBG(CAM_ISP, + "mmu_hdl=0x%x, size=%d, end=0x%x", + mmu_hdl, (int)size, + io_addr[plane_id]+size); + + } + if (!plane_id) { + CAM_ERR(CAM_ISP, "No valid planes for res%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + if ((kmd_buf_info->used_bytes + io_cfg_used_bytes) < + kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + io_cfg_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + base_idx); + rc = -ENOMEM; + return rc; + } + update_buf.res = res; + update_buf.cmd_type = CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM; + update_buf.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + io_cfg_used_bytes/4; + bus_rd_update.image_buf = io_addr; + bus_rd_update.num_buf = plane_id; + bus_rd_update.io_cfg = &io_cfg[i]; + update_buf.cmd.size = kmd_buf_remain_size; + update_buf.rm_update = &bus_rd_update; + + CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", + update_buf.cmd.cmd_buf_addr, + update_buf.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, &update_buf, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + io_cfg_used_bytes += update_buf.cmd.used_bytes; + } + } + + CAM_DBG(CAM_ISP, "io_cfg_used_bytes %d, fill_fence %d", + io_cfg_used_bytes, fill_fence); + if (io_cfg_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = io_cfg_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); + num_ent++; + + kmd_buf_info->used_bytes += io_cfg_used_bytes; + kmd_buf_info->offset += io_cfg_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + + if (fill_fence) { + prepare->num_out_map_entries = num_out_buf; + prepare->num_in_map_entries = num_in_buf; + } + + return rc; +} + + +int cam_isp_add_reg_update( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int rc = -EINVAL; + struct cam_isp_resource_node *res; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_update_entry *hw_entry; + struct cam_isp_hw_get_cmd_update get_regup; + uint32_t kmd_buf_remain_size, num_ent, i, reg_update_size; + + hw_entry = prepare->hw_update_entries; + /* Max one hw entries required for each base */ + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + reg_update_size = 0; + list_for_each_entry(hw_mgr_res, res_list_isp_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + if (res->hw_intf->hw_idx != base_idx) + continue; + + if (kmd_buf_info->size > (kmd_buf_info->used_bytes + + reg_update_size)) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + reg_update_size); + } else { + CAM_ERR(CAM_ISP, "no free mem %d %d %d", + base_idx, kmd_buf_info->size, + kmd_buf_info->used_bytes + + reg_update_size); + rc = -EINVAL; + return rc; + } + + get_regup.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + reg_update_size/4; + get_regup.cmd.size = kmd_buf_remain_size; + get_regup.cmd_type = CAM_ISP_HW_CMD_GET_REG_UPDATE; + get_regup.res = res; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_REG_UPDATE, &get_regup, + sizeof(struct cam_isp_hw_get_cmd_update)); + if (rc) + return rc; + + CAM_DBG(CAM_ISP, "Reg update added for res %d hw_id %d", + res->res_id, res->hw_intf->hw_idx); + reg_update_size += get_regup.cmd.used_bytes; + } + } + + if (reg_update_size) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = reg_update_size; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); + num_ent++; + + kmd_buf_info->used_bytes += reg_update_size; + kmd_buf_info->offset += reg_update_size; + prepare->num_hw_update_entries = num_ent; + /* reg update is success return status 0 */ + rc = 0; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c new file mode 100644 index 000000000000..5145dadded28 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "cam_tasklet_util.h" +#include "cam_irq_controller.h" +#include "cam_debug_util.h" + +#define CAM_TASKLETQ_SIZE 256 + +static void cam_tasklet_action(unsigned long data); + +/** + * struct cam_tasklet_queue_cmd: + * @Brief: Structure associated with each slot in the + * tasklet queue + * + * @list: list_head member for each entry in queue + * @payload: Payload structure for the event. This will be + * passed to the handler function + * @handler_priv: Private data passed at event subscribe + * @bottom_half_handler: Function pointer for event handler in bottom + * half context + * + */ +struct cam_tasklet_queue_cmd { + struct list_head list; + void *payload; + void *handler_priv; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/** + * struct cam_tasklet_info: + * @Brief: Tasklet private structure + * + * @list: list_head member for each tasklet + * @index: Instance id for the tasklet + * @tasklet_lock: Spin lock + * @tasklet_active: Atomic variable to control tasklet state + * @tasklet: Tasklet structure used to schedule bottom half + * @free_cmd_list: List of free tasklet queue cmd for use + * @used_cmd_list: List of used tasklet queue cmd + * @cmd_queue: Array of tasklet cmd for storage + * @ctx_priv: Private data passed to the handling function + * + */ +struct cam_tasklet_info { + struct list_head list; + uint32_t index; + spinlock_t tasklet_lock; + atomic_t tasklet_active; + struct tasklet_struct tasklet; + + struct list_head free_cmd_list; + struct list_head used_cmd_list; + struct cam_tasklet_queue_cmd cmd_queue[CAM_TASKLETQ_SIZE]; + + void *ctx_priv; +}; + +struct cam_irq_bh_api tasklet_bh_api = { + .bottom_half_enqueue_func = cam_tasklet_enqueue_cmd, + .get_bh_payload_func = cam_tasklet_get_cmd, + .put_bh_payload_func = cam_tasklet_put_cmd, +}; + +int cam_tasklet_get_cmd( + void *bottom_half, + void **bh_cmd) +{ + int rc = 0; + unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; + + *bh_cmd = NULL; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return -EINVAL; + } + + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active"); + rc = -EPIPE; + return rc; + } + + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + if (list_empty(&tasklet->free_cmd_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd"); + rc = -ENODEV; + goto spin_unlock; + } else { + tasklet_cmd = list_first_entry(&tasklet->free_cmd_list, + struct cam_tasklet_queue_cmd, list); + list_del_init(&(tasklet_cmd)->list); + *bh_cmd = tasklet_cmd; + } + +spin_unlock: + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + return rc; +} + +void cam_tasklet_put_cmd( + void *bottom_half, + void **bh_cmd) +{ + unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = *bh_cmd; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return; + } + + if (tasklet_cmd == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid tasklet_cmd"); + return; + } + + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_del_init(&tasklet_cmd->list); + list_add_tail(&tasklet_cmd->list, &tasklet->free_cmd_list); + *bh_cmd = NULL; + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); +} + +/** + * cam_tasklet_dequeue_cmd() + * + * @brief: Initialize the tasklet info structure + * + * @hw_mgr_ctx: Private Ctx data that will be passed to the handler + * function + * @idx: Index of tasklet used as identity + * @tasklet_action: Tasklet callback function that will be called + * when tasklet runs on CPU + * + * @return: 0: Success + * Negative: Failure + */ +static int cam_tasklet_dequeue_cmd( + struct cam_tasklet_info *tasklet, + struct cam_tasklet_queue_cmd **tasklet_cmd) +{ + int rc = 0; + unsigned long flags; + + *tasklet_cmd = NULL; + + CAM_DBG(CAM_ISP, "Dequeue before lock."); + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + if (list_empty(&tasklet->used_cmd_list)) { + CAM_DBG(CAM_ISP, "End of list reached. Exit"); + rc = -ENODEV; + goto spin_unlock; + } else { + *tasklet_cmd = list_first_entry(&tasklet->used_cmd_list, + struct cam_tasklet_queue_cmd, list); + list_del_init(&(*tasklet_cmd)->list); + CAM_DBG(CAM_ISP, "Dequeue Successful"); + } + +spin_unlock: + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + return rc; +} + +void cam_tasklet_enqueue_cmd( + void *bottom_half, + void *bh_cmd, + void *handler_priv, + void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler) +{ + unsigned long flags; + struct cam_tasklet_queue_cmd *tasklet_cmd = bh_cmd; + struct cam_tasklet_info *tasklet = bottom_half; + + if (!bottom_half) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bottom half"); + return; + } + + if (!bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bh cmd"); + return; + } + + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active\n"); + return; + } + + CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); + tasklet_cmd->bottom_half_handler = bottom_half_handler; + tasklet_cmd->payload = evt_payload_priv; + tasklet_cmd->handler_priv = handler_priv; + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_add_tail(&tasklet_cmd->list, + &tasklet->used_cmd_list); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + tasklet_schedule(&tasklet->tasklet); +} + +int cam_tasklet_init( + void **tasklet_info, + void *hw_mgr_ctx, + uint32_t idx) +{ + int i; + struct cam_tasklet_info *tasklet = NULL; + + tasklet = kzalloc(sizeof(struct cam_tasklet_info), GFP_KERNEL); + if (!tasklet) { + CAM_DBG(CAM_ISP, + "Error! Unable to allocate memory for tasklet"); + *tasklet_info = NULL; + return -ENOMEM; + } + + tasklet->ctx_priv = hw_mgr_ctx; + tasklet->index = idx; + spin_lock_init(&tasklet->tasklet_lock); + memset(tasklet->cmd_queue, 0, sizeof(tasklet->cmd_queue)); + INIT_LIST_HEAD(&tasklet->free_cmd_list); + INIT_LIST_HEAD(&tasklet->used_cmd_list); + for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { + INIT_LIST_HEAD(&tasklet->cmd_queue[i].list); + list_add_tail(&tasklet->cmd_queue[i].list, + &tasklet->free_cmd_list); + } + tasklet_init(&tasklet->tasklet, cam_tasklet_action, + (unsigned long)tasklet); + tasklet_disable(&tasklet->tasklet); + + *tasklet_info = tasklet; + + return 0; +} + +void cam_tasklet_deinit(void **tasklet_info) +{ + struct cam_tasklet_info *tasklet = *tasklet_info; + + if (atomic_read(&tasklet->tasklet_active)) { + atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); + tasklet_disable(&tasklet->tasklet); + } + kfree(tasklet); + *tasklet_info = NULL; +} + +static inline void cam_tasklet_flush(struct cam_tasklet_info *tasklet_info) +{ + cam_tasklet_action((unsigned long) tasklet_info); +} + +int cam_tasklet_start(void *tasklet_info) +{ + struct cam_tasklet_info *tasklet = tasklet_info; + int i = 0; + + if (atomic_read(&tasklet->tasklet_active)) { + CAM_ERR(CAM_ISP, "Tasklet already active. idx = %d", + tasklet->index); + return -EBUSY; + } + + /* clean up the command queue first */ + for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { + list_del_init(&tasklet->cmd_queue[i].list); + list_add_tail(&tasklet->cmd_queue[i].list, + &tasklet->free_cmd_list); + } + + atomic_set(&tasklet->tasklet_active, 1); + + tasklet_enable(&tasklet->tasklet); + + return 0; +} + +void cam_tasklet_stop(void *tasklet_info) +{ + struct cam_tasklet_info *tasklet = tasklet_info; + + atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); + tasklet_disable(&tasklet->tasklet); + cam_tasklet_flush(tasklet); +} + +/* + * cam_tasklet_action() + * + * @brief: Process function that will be called when tasklet runs + * on CPU + * + * @data: Tasklet Info structure that is passed in tasklet_init + * + * @return: Void + */ +static void cam_tasklet_action(unsigned long data) +{ + struct cam_tasklet_info *tasklet_info = NULL; + struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; + + tasklet_info = (struct cam_tasklet_info *)data; + + while (!cam_tasklet_dequeue_cmd(tasklet_info, &tasklet_cmd)) { + tasklet_cmd->bottom_half_handler(tasklet_cmd->handler_priv, + tasklet_cmd->payload); + cam_tasklet_put_cmd(tasklet_info, (void **)(&tasklet_cmd)); + } +} diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h new file mode 100644 index 000000000000..50161ea001f5 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_PARSER_H_ +#define _CAM_ISP_HW_PARSER_H_ + +#include +#include +#include "cam_isp_hw_mgr_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_hw_intf.h" +#include "cam_packet_util.h" + +/* + * struct cam_isp_generic_blob_info + * + * @prepare: Payload for prepare command + * @ctx_base_info: Base hardware information for the context + * @kmd_buf_info: Kmd buffer to store the custom cmd data + */ +struct cam_isp_generic_blob_info { + struct cam_hw_prepare_update_args *prepare; + struct ctx_base_info *base_info; + struct cam_kmd_buf_info *kmd_buf_info; +}; + +/* + * cam_isp_add_change_base() + * + * @brief Add change base in the hw entries list + * processe the isp source list get the change base from + * ISP HW instance + * + * @prepare: Contain the packet and HW update variables + * @res_list_isp_src: Resource list for IFE/VFE source + * @base_idx: Base or dev index of the IFE/VFE HW instance for + * which change change base need to be added + * @kmd_buf_info: Kmd buffer to store the change base command + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_isp_add_change_base( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info); + +/* + * cam_isp_add_cmd_buf_update() + * + * @brief Add command buffer in the HW entries list for given + * Blob Data. + * + * @hw_mgr_res: HW resource to get the update from + * @cmd_type: Cmd type to get update for + * @hw_cmd_type: HW Cmd type corresponding to cmd_type + * @base_idx: Base hardware index + * @cmd_buf_addr: Cpu buf addr of kmd scratch buffer + * @kmd_buf_remain_size: Remaining size left for cmd buffer update + * @cmd_update_data: Data needed by HW to process the cmd and provide + * cmd buffer + * @bytes_used: Address of the field to be populated with + * total bytes used as output to caller + * + * @return: Negative for Failure + * otherwise returns bytes used + */ +int cam_isp_add_cmd_buf_update( + struct cam_ife_hw_mgr_res *hw_mgr_res, + uint32_t cmd_type, + uint32_t hw_cmd_type, + uint32_t base_idx, + uint32_t *cmd_buf_addr, + uint32_t kmd_buf_remain_size, + void *cmd_update_data, + uint32_t *bytes_used); + +/* + * cam_isp_add_command_buffers() + * + * @brief Add command buffer in the HW entries list for given + * left or right VFE/IFE instance. + * + * @prepare: Contain the packet and HW update variables + * @kmd_buf_info: KMD buffer to store the custom cmd data + * @base_info: base hardware information + * @blob_handler_cb: Call_back_function for Meta handling + * @res_list_isp_out: IFE /VFE out resource list + * @size_isp_out: Size of the res_list_isp_out array + * + * @return: 0 for success + * Negative for Failure + */ +int cam_isp_add_command_buffers( + struct cam_hw_prepare_update_args *prepare, + struct cam_kmd_buf_info *kmd_buf_info, + struct ctx_base_info *base_info, + cam_packet_generic_blob_handler blob_handler_cb, + struct cam_ife_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out); + +/* + * cam_isp_add_io_buffers() + * + * @brief Add io buffer configurations in the HW entries list + * processe the io configurations based on the base + * index and update the HW entries list + * + * @iommu_hdl: Iommu handle to get the IO buf from memory manager + * @sec_iommu_hdl: Secure iommu handle to get the IO buf from + * memory manager + * @prepare: Contain the packet and HW update variables + * @base_idx: Base or dev index of the IFE/VFE HW instance + * @kmd_buf_info: Kmd buffer to store the change base command + * @res_list_isp_out: IFE /VFE out resource list + * @res_list_ife_in_rd: IFE /VFE in rd resource list + * @size_isp_out: Size of the res_list_isp_out array + * @fill_fence: If true, Fence map table will be filled + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_isp_add_io_buffers( + int iommu_hdl, + int sec_iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info, + struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, + uint32_t size_isp_out, + bool fill_fence); + +/* + * cam_isp_add_reg_update() + * + * @brief Add reg update in the hw entries list + * processe the isp source list get the reg update from + * ISP HW instance + * + * @prepare: Contain the packet and HW update variables + * @res_list_isp_src: Resource list for IFE/VFE source + * @base_idx: Base or dev index of the IFE/VFE HW instance + * @kmd_buf_info: Kmd buffer to store the change base command + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_isp_add_reg_update( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info); + +#endif /*_CAM_ISP_HW_PARSER_H */ diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h new file mode 100644 index 000000000000..22beb49ef6fc --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TASKLET_UTIL_H_ +#define _CAM_TASKLET_UTIL_H_ + +#include "cam_irq_controller.h" + +/* + * cam_tasklet_init() + * + * @brief: Initialize the tasklet info structure + * + * @tasklet: Tasklet to initialize + * @hw_mgr_ctx: Private Ctx data that will be passed to the handler + * function + * @idx: Index of tasklet used as identity + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_init( + void **tasklet, + void *hw_mgr_ctx, + uint32_t idx); + +/* + * cam_tasklet_deinit() + * + * @brief: Deinitialize the tasklet info structure + * + * @tasklet: Tasklet to deinitialize + * + * @return: Void + */ +void cam_tasklet_deinit(void **tasklet); + +/* + * cam_tasklet_start() + * + * @brief: Enable the tasklet to be scheduled and run. + * Caller should make sure this function is called + * before trying to enqueue. + * + * @tasklet: Tasklet to start + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_start(void *tasklet); + +/* + * cam_tasklet_stop() + * + * @brief: Disable the tasklet so it can no longer be scheduled. + * Need to enable again to run. + * + * @tasklet: Tasklet to stop + * + * @return: Void + */ +void cam_tasklet_stop(void *tasklet); + +/* + * cam_tasklet_enqueue_cmd() + * + * @brief: Enqueue the tasklet_cmd to used list + * + * @bottom_half: Tasklet info to enqueue onto + * @bh_cmd: Tasklet cmd used to enqueue task + * @handler_priv: Private Handler data that will be passed to the + * handler function + * @evt_payload_priv: Event payload that will be passed to the handler + * function + * @bottom_half_handler: Callback function that will be called by tasklet + * for handling event + * + * @return: Void + */ +void cam_tasklet_enqueue_cmd( + void *bottom_half, + void *bh_cmd, + void *handler_priv, + void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler); + +/** + * cam_tasklet_get_cmd() + * + * @brief: Get free cmd from tasklet + * + * @bottom_half: Tasklet Info structure to get cmd from + * @bh_cmd: Return tasklet_cmd pointer if successful + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_get_cmd(void *bottom_half, void **bh_cmd); + +/** + * cam_tasklet_put_cmd() + * + * @brief: Put back cmd to free list + * + * @bottom_half: Tasklet Info structure to put cmd into + * @bh_cmd: tasklet_cmd pointer that needs to be put back + * + * @return: Void + */ +void cam_tasklet_put_cmd(void *bottom_half, void **bh_cmd); + +extern struct cam_irq_bh_api tasklet_bh_api; + +#endif /* _CAM_TASKLET_UTIL_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile new file mode 100644 index 000000000000..fb595fe8f02a --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_irq_controller.o \ No newline at end of file diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c new file mode 100644 index 000000000000..8ed8b9f8b1a8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -0,0 +1,730 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "cam_irq_controller.h" +#include "cam_debug_util.h" + +/** + * struct cam_irq_evt_handler: + * @Brief: Event handler information + * + * @priority: Priority level of this event + * @evt_bit_mask_arr: evt_bit_mask that has the bits set for IRQs to + * subscribe for + * @handler_priv: Private data that will be passed to the Top/Bottom + * Half handler function + * @top_half_handler: Top half Handler callback function + * @bottom_half_handler: Bottom half Handler callback function + * @bottom_half: Pointer to bottom_half implementation on which to + * enqueue the event for further handling + * @bottom_half_enqueue_func: + * Function used to enqueue the bottom_half event + * @list_node: list_head struct used for overall handler List + * @th_list_node: list_head struct used for top half handler List + */ +struct cam_irq_evt_handler { + enum cam_irq_priority_level priority; + uint32_t *evt_bit_mask_arr; + void *handler_priv; + CAM_IRQ_HANDLER_TOP_HALF top_half_handler; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; + void *bottom_half; + struct cam_irq_bh_api irq_bh_api; + struct list_head list_node; + struct list_head th_list_node; + int index; +}; + +/** + * struct cam_irq_register_obj: + * @Brief: Structure containing information related to + * a particular register Set + * + * @index: Index of set in Array + * @mask_reg_offset: Offset of IRQ MASK register + * @clear_reg_offset: Offset of IRQ CLEAR register + * @status_reg_offset: Offset of IRQ STATUS register + * @top_half_enable_mask: Array of enabled bit_mask sorted by priority + */ +struct cam_irq_register_obj { + uint32_t index; + uint32_t mask_reg_offset; + uint32_t clear_reg_offset; + uint32_t status_reg_offset; + uint32_t top_half_enable_mask[CAM_IRQ_PRIORITY_MAX]; +}; + +/** + * struct cam_irq_controller: + * + * @brief: IRQ Controller structure. + * + * @name: Name of IRQ Controller block + * @mem_base: Mapped base address of register space to which + * register offsets are added to access registers + * @num_registers: Number of sets(mask/clear/status) of IRQ registers + * @irq_register_arr: Array of Register object associated with this + * Controller + * @irq_status_arr: Array of IRQ Status values + * @global_clear_offset: Offset of Global IRQ Clear register. This register + * contains the BIT that needs to be set for the CLEAR + * to take effect + * @global_clear_bitmask: Bitmask needed to be used in Global Clear register + * for Clear IRQ cmd to take effect + * @evt_handler_list_head: List of all event handlers + * @th_list_head: List of handlers sorted by priority + * @hdl_idx: Unique identity of handler assigned on Subscribe. + * Used to Unsubscribe. + * @lock: Lock for use by controller + */ +struct cam_irq_controller { + const char *name; + void __iomem *mem_base; + uint32_t num_registers; + struct cam_irq_register_obj *irq_register_arr; + uint32_t *irq_status_arr; + uint32_t global_clear_offset; + uint32_t global_clear_bitmask; + struct list_head evt_handler_list_head; + struct list_head th_list_head[CAM_IRQ_PRIORITY_MAX]; + uint32_t hdl_idx; + spinlock_t lock; + struct cam_irq_th_payload th_payload; +}; + +int cam_irq_controller_deinit(void **irq_controller) +{ + struct cam_irq_controller *controller = *irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + + while (!list_empty(&controller->evt_handler_list_head)) { + evt_handler = list_first_entry( + &controller->evt_handler_list_head, + struct cam_irq_evt_handler, list_node); + list_del_init(&evt_handler->list_node); + kfree(evt_handler->evt_bit_mask_arr); + kfree(evt_handler); + } + + kfree(controller->th_payload.evt_status_arr); + kfree(controller->irq_status_arr); + kfree(controller->irq_register_arr); + kfree(controller); + *irq_controller = NULL; + return 0; +} + +int cam_irq_controller_init(const char *name, + void __iomem *mem_base, + struct cam_irq_controller_reg_info *register_info, + void **irq_controller) +{ + struct cam_irq_controller *controller = NULL; + int i, rc = 0; + + *irq_controller = NULL; + + if (!register_info->num_registers || !register_info->irq_reg_set || + !name || !mem_base) { + CAM_ERR(CAM_IRQ_CTRL, "Invalid parameters"); + rc = -EINVAL; + return rc; + } + + controller = kzalloc(sizeof(struct cam_irq_controller), GFP_KERNEL); + if (!controller) { + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ Controller"); + return -ENOMEM; + } + + controller->irq_register_arr = kzalloc(register_info->num_registers * + sizeof(struct cam_irq_register_obj), GFP_KERNEL); + if (!controller->irq_register_arr) { + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ register Arr"); + rc = -ENOMEM; + goto reg_alloc_error; + } + + controller->irq_status_arr = kzalloc(register_info->num_registers * + sizeof(uint32_t), GFP_KERNEL); + if (!controller->irq_status_arr) { + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ status Arr"); + rc = -ENOMEM; + goto status_alloc_error; + } + + controller->th_payload.evt_status_arr = + kzalloc(register_info->num_registers * sizeof(uint32_t), + GFP_KERNEL); + if (!controller->th_payload.evt_status_arr) { + CAM_DBG(CAM_IRQ_CTRL, + "Failed to allocate BH payload bit mask Arr"); + rc = -ENOMEM; + goto evt_mask_alloc_error; + } + + controller->name = name; + + CAM_DBG(CAM_IRQ_CTRL, "num_registers: %d", + register_info->num_registers); + for (i = 0; i < register_info->num_registers; i++) { + controller->irq_register_arr[i].index = i; + controller->irq_register_arr[i].mask_reg_offset = + register_info->irq_reg_set[i].mask_reg_offset; + controller->irq_register_arr[i].clear_reg_offset = + register_info->irq_reg_set[i].clear_reg_offset; + controller->irq_register_arr[i].status_reg_offset = + register_info->irq_reg_set[i].status_reg_offset; + CAM_DBG(CAM_IRQ_CTRL, "i %d mask_reg_offset: 0x%x", i, + controller->irq_register_arr[i].mask_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "i %d clear_reg_offset: 0x%x", i, + controller->irq_register_arr[i].clear_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "i %d status_reg_offset: 0x%x", i, + controller->irq_register_arr[i].status_reg_offset); + } + controller->num_registers = register_info->num_registers; + controller->global_clear_bitmask = register_info->global_clear_bitmask; + controller->global_clear_offset = register_info->global_clear_offset; + controller->mem_base = mem_base; + + CAM_DBG(CAM_IRQ_CTRL, "global_clear_bitmask: 0x%x", + controller->global_clear_bitmask); + CAM_DBG(CAM_IRQ_CTRL, "global_clear_offset: 0x%x", + controller->global_clear_offset); + CAM_DBG(CAM_IRQ_CTRL, "mem_base: %pK", + (void __iomem *)controller->mem_base); + + INIT_LIST_HEAD(&controller->evt_handler_list_head); + for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) + INIT_LIST_HEAD(&controller->th_list_head[i]); + + spin_lock_init(&controller->lock); + + controller->hdl_idx = 1; + *irq_controller = controller; + + return rc; + +evt_mask_alloc_error: + kfree(controller->irq_status_arr); +status_alloc_error: + kfree(controller->irq_register_arr); +reg_alloc_error: + kfree(controller); + + return rc; +} + +int cam_irq_controller_subscribe_irq(void *irq_controller, + enum cam_irq_priority_level priority, + uint32_t *evt_bit_mask_arr, + void *handler_priv, + CAM_IRQ_HANDLER_TOP_HALF top_half_handler, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, + void *bottom_half, + struct cam_irq_bh_api *irq_bh_api) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + int i; + int rc = 0; + uint32_t irq_mask; + unsigned long flags = 0; + bool need_lock; + + if (!controller || !handler_priv || !evt_bit_mask_arr) { + CAM_ERR(CAM_IRQ_CTRL, + "Inval params: ctlr=%pK hdl_priv=%pK bit_mask_arr=%pK", + controller, handler_priv, evt_bit_mask_arr); + return -EINVAL; + } + + if (!top_half_handler) { + CAM_ERR(CAM_IRQ_CTRL, "Missing top half handler"); + return -EINVAL; + } + + if (bottom_half_handler && + (!bottom_half || !irq_bh_api)) { + CAM_ERR(CAM_IRQ_CTRL, + "Invalid params: bh_handler=%pK bh=%pK bh_enq_f=%pK", + bottom_half_handler, + bottom_half, + irq_bh_api); + return -EINVAL; + } + + if (irq_bh_api && + (!irq_bh_api->bottom_half_enqueue_func || + !irq_bh_api->get_bh_payload_func || + !irq_bh_api->put_bh_payload_func)) { + CAM_ERR(CAM_IRQ_CTRL, + "Invalid: enqueue_func=%pK get_bh=%pK put_bh=%pK", + irq_bh_api->bottom_half_enqueue_func, + irq_bh_api->get_bh_payload_func, + irq_bh_api->put_bh_payload_func); + return -EINVAL; + } + + if (priority >= CAM_IRQ_PRIORITY_MAX) { + CAM_ERR(CAM_IRQ_CTRL, "Invalid priority=%u, max=%u", priority, + CAM_IRQ_PRIORITY_MAX); + return -EINVAL; + } + + evt_handler = kzalloc(sizeof(struct cam_irq_evt_handler), GFP_KERNEL); + if (!evt_handler) { + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); + return -ENOMEM; + } + + evt_handler->evt_bit_mask_arr = kzalloc(sizeof(uint32_t) * + controller->num_registers, GFP_KERNEL); + if (!evt_handler->evt_bit_mask_arr) { + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); + rc = -ENOMEM; + goto free_evt_handler; + } + + INIT_LIST_HEAD(&evt_handler->list_node); + INIT_LIST_HEAD(&evt_handler->th_list_node); + + for (i = 0; i < controller->num_registers; i++) + evt_handler->evt_bit_mask_arr[i] = evt_bit_mask_arr[i]; + + evt_handler->priority = priority; + evt_handler->handler_priv = handler_priv; + evt_handler->top_half_handler = top_half_handler; + evt_handler->bottom_half_handler = bottom_half_handler; + evt_handler->bottom_half = bottom_half; + evt_handler->index = controller->hdl_idx++; + + if (irq_bh_api) + evt_handler->irq_bh_api = *irq_bh_api; + + /* Avoid rollover to negative values */ + if (controller->hdl_idx > 0x3FFFFFFF) + controller->hdl_idx = 1; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + for (i = 0; i < controller->num_registers; i++) { + controller->irq_register_arr[i].top_half_enable_mask[priority] + |= evt_bit_mask_arr[i]; + + irq_mask = cam_io_r_mb(controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + irq_mask |= evt_bit_mask_arr[i]; + + cam_io_w_mb(irq_mask, controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + } + + list_add_tail(&evt_handler->list_node, + &controller->evt_handler_list_head); + list_add_tail(&evt_handler->th_list_node, + &controller->th_list_head[priority]); + + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return evt_handler->index; + +free_evt_handler: + kfree(evt_handler); + evt_handler = NULL; + + return rc; +} + +int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_evt_handler *evt_handler_temp; + struct cam_irq_register_obj *irq_register = NULL; + enum cam_irq_priority_level priority; + unsigned long flags = 0; + unsigned int i; + uint32_t irq_mask; + uint32_t found = 0; + int rc = -EINVAL; + bool need_lock; + + if (!controller) + return rc; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + + list_for_each_entry_safe(evt_handler, evt_handler_temp, + &controller->evt_handler_list_head, list_node) { + if (evt_handler->index == handle) { + CAM_DBG(CAM_IRQ_CTRL, "enable item %d", handle); + found = 1; + rc = 0; + break; + } + } + + if (!found) { + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + return rc; + } + + priority = evt_handler->priority; + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + irq_register->top_half_enable_mask[priority] |= + evt_handler->evt_bit_mask_arr[i]; + + irq_mask = cam_io_r_mb(controller->mem_base + + irq_register->mask_reg_offset); + irq_mask |= evt_handler->evt_bit_mask_arr[i]; + + cam_io_w_mb(irq_mask, controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + } + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return rc; +} + +int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_evt_handler *evt_handler_temp; + struct cam_irq_register_obj *irq_register; + enum cam_irq_priority_level priority; + unsigned long flags = 0; + unsigned int i; + uint32_t irq_mask; + uint32_t found = 0; + int rc = -EINVAL; + bool need_lock; + + if (!controller) + return rc; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + + list_for_each_entry_safe(evt_handler, evt_handler_temp, + &controller->evt_handler_list_head, list_node) { + if (evt_handler->index == handle) { + CAM_DBG(CAM_IRQ_CTRL, "disable item %d", handle); + found = 1; + rc = 0; + break; + } + } + + if (!found) { + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + return rc; + } + + priority = evt_handler->priority; + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + irq_register->top_half_enable_mask[priority] &= + ~(evt_handler->evt_bit_mask_arr[i]); + + irq_mask = cam_io_r_mb(controller->mem_base + + irq_register->mask_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x before disable 0x%x", + irq_register->mask_reg_offset, irq_mask); + irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]); + + cam_io_w_mb(irq_mask, controller->mem_base + + irq_register->mask_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x after disable 0x%x", + irq_register->mask_reg_offset, irq_mask); + + /* Clear the IRQ bits of this handler */ + cam_io_w_mb(evt_handler->evt_bit_mask_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + + if (controller->global_clear_offset) + cam_io_w_mb( + controller->global_clear_bitmask, + controller->mem_base + + controller->global_clear_offset); + } + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return rc; +} + +int cam_irq_controller_unsubscribe_irq(void *irq_controller, + uint32_t handle) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_evt_handler *evt_handler_temp; + struct cam_irq_register_obj *irq_register; + enum cam_irq_priority_level priority; + uint32_t i; + uint32_t found = 0; + uint32_t irq_mask; + unsigned long flags = 0; + int rc = -EINVAL; + bool need_lock; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + + list_for_each_entry_safe(evt_handler, evt_handler_temp, + &controller->evt_handler_list_head, list_node) { + if (evt_handler->index == handle) { + CAM_DBG(CAM_IRQ_CTRL, "unsubscribe item %d", handle); + list_del_init(&evt_handler->list_node); + list_del_init(&evt_handler->th_list_node); + found = 1; + rc = 0; + break; + } + } + + priority = evt_handler->priority; + if (found) { + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + irq_register->top_half_enable_mask[priority] &= + ~(evt_handler->evt_bit_mask_arr[i]); + + irq_mask = cam_io_r_mb(controller->mem_base + + irq_register->mask_reg_offset); + irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]); + + cam_io_w_mb(irq_mask, controller->mem_base + + irq_register->mask_reg_offset); + + /* Clear the IRQ bits of this handler */ + cam_io_w_mb(evt_handler->evt_bit_mask_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + if (controller->global_clear_offset) + cam_io_w_mb( + controller->global_clear_bitmask, + controller->mem_base + + controller->global_clear_offset); + } + + kfree(evt_handler->evt_bit_mask_arr); + kfree(evt_handler); + } + + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return rc; +} + +/** + * cam_irq_controller_match_bit_mask() + * + * @Brief: This function checks if any of the enabled IRQ bits + * for a certain handler is Set in the Status values + * of the controller. + * + * @controller: IRQ Controller structure + * @evt_handler: Event handler structure + * + * @Return: True: If any interested IRQ Bit is Set + * False: Otherwise + */ +static bool cam_irq_controller_match_bit_mask( + struct cam_irq_controller *controller, + struct cam_irq_evt_handler *evt_handler) +{ + int i; + + for (i = 0; i < controller->num_registers; i++) { + if (evt_handler->evt_bit_mask_arr[i] & + controller->irq_status_arr[i]) + return true; + } + + return false; +} + +static void cam_irq_controller_th_processing( + struct cam_irq_controller *controller, + struct list_head *th_list_head) +{ + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_th_payload *th_payload = &controller->th_payload; + bool is_irq_match; + int rc = -EINVAL; + int i; + void *bh_cmd = NULL; + struct cam_irq_bh_api *irq_bh_api = NULL; + + CAM_DBG(CAM_IRQ_CTRL, "Enter"); + + if (list_empty(th_list_head)) + return; + + list_for_each_entry(evt_handler, th_list_head, th_list_node) { + is_irq_match = cam_irq_controller_match_bit_mask(controller, + evt_handler); + + if (!is_irq_match) + continue; + + CAM_DBG(CAM_IRQ_CTRL, "match found"); + + cam_irq_th_payload_init(th_payload); + th_payload->handler_priv = evt_handler->handler_priv; + th_payload->num_registers = controller->num_registers; + for (i = 0; i < controller->num_registers; i++) { + th_payload->evt_status_arr[i] = + controller->irq_status_arr[i] & + evt_handler->evt_bit_mask_arr[i]; + } + + irq_bh_api = &evt_handler->irq_bh_api; + bh_cmd = NULL; + + if (evt_handler->bottom_half_handler) { + rc = irq_bh_api->get_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No payload, IRQ handling frozen"); + continue; + } + } + + /* + * irq_status_arr[0] is dummy argument passed. the entire + * status array is passed in th_payload. + */ + if (evt_handler->top_half_handler) + rc = evt_handler->top_half_handler( + controller->irq_status_arr[0], + (void *)th_payload); + + if (rc && bh_cmd) { + irq_bh_api->put_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + continue; + } + + if (evt_handler->bottom_half_handler) { + CAM_DBG(CAM_IRQ_CTRL, "Enqueuing bottom half for %s", + controller->name); + irq_bh_api->bottom_half_enqueue_func( + evt_handler->bottom_half, + bh_cmd, + evt_handler->handler_priv, + th_payload->evt_payload_priv, + evt_handler->bottom_half_handler); + } + } + + CAM_DBG(CAM_IRQ_CTRL, "Exit"); +} + +irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv) +{ + struct cam_irq_controller *controller = priv; + uint32_t i = 0; + + if (!controller) + return IRQ_NONE; + + for (i = 0; i < controller->num_registers; i++) { + + cam_io_w_mb(0x0, controller->mem_base + + controller->irq_register_arr[i].clear_reg_offset); + } + + if (controller->global_clear_offset) + cam_io_w_mb(controller->global_clear_bitmask, + controller->mem_base + + controller->global_clear_offset); + + for (i = 0; i < controller->num_registers; i++) { + cam_io_w_mb(0x0, controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + } + + return IRQ_HANDLED; +} + +irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv) +{ + struct cam_irq_controller *controller = priv; + struct cam_irq_register_obj *irq_register; + bool need_th_processing[CAM_IRQ_PRIORITY_MAX] = {false}; + int i; + int j; + + if (!controller) + return IRQ_NONE; + + CAM_DBG(CAM_IRQ_CTRL, "locking controller %pK name %s lock %pK", + controller, controller->name, &controller->lock); + spin_lock(&controller->lock); + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + controller->irq_status_arr[i] = cam_io_r_mb( + controller->mem_base + + controller->irq_register_arr[i].status_reg_offset); + cam_io_w_mb(controller->irq_status_arr[i], + controller->mem_base + + controller->irq_register_arr[i].clear_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "Read irq status%d (0x%x) = 0x%x", i, + controller->irq_register_arr[i].status_reg_offset, + controller->irq_status_arr[i]); + for (j = 0; j < CAM_IRQ_PRIORITY_MAX; j++) { + if (irq_register->top_half_enable_mask[j] & + controller->irq_status_arr[i]) + need_th_processing[j] = true; + CAM_DBG(CAM_IRQ_CTRL, + "i %d j %d need_th_processing = %d", + i, j, need_th_processing[j]); + } + } + + CAM_DBG(CAM_IRQ_CTRL, "Status Registers read Successful"); + + if (controller->global_clear_offset) + cam_io_w_mb(controller->global_clear_bitmask, + controller->mem_base + controller->global_clear_offset); + + CAM_DBG(CAM_IRQ_CTRL, "Status Clear done"); + + for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) { + if (need_th_processing[i]) { + CAM_DBG(CAM_IRQ_CTRL, "Invoke TH processing"); + cam_irq_controller_th_processing(controller, + &controller->th_list_head[i]); + } + } + spin_unlock(&controller->lock); + CAM_DBG(CAM_IRQ_CTRL, "unlocked controller %pK name %s lock %pK", + controller, controller->name, &controller->lock); + + return IRQ_HANDLED; +} diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h new file mode 100644 index 000000000000..caf21c5caf12 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h @@ -0,0 +1,272 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IRQ_CONTROLLER_H_ +#define _CAM_IRQ_CONTROLLER_H_ + +#include + +#define CAM_IRQ_BITS_PER_REGISTER 32 + +/* + * enum cam_irq_priority_level: + * @Brief: Priority levels for IRQ events. + * Priority_0 events will be serviced before + * Priority_1 if they these bits are set in the same + * Status Read. And so on upto Priority_4. + * + * Default Priority is Priority_4. + */ +enum cam_irq_priority_level { + CAM_IRQ_PRIORITY_0, + CAM_IRQ_PRIORITY_1, + CAM_IRQ_PRIORITY_2, + CAM_IRQ_PRIORITY_3, + CAM_IRQ_PRIORITY_4, + CAM_IRQ_PRIORITY_MAX, +}; + +/* + * struct cam_irq_register_set: + * @Brief: Structure containing offsets of IRQ related + * registers belonging to a Set + * + * @mask_reg_offset: Offset of IRQ MASK register + * @clear_reg_offset: Offset of IRQ CLEAR register + * @status_reg_offset: Offset of IRQ STATUS register + */ +struct cam_irq_register_set { + uint32_t mask_reg_offset; + uint32_t clear_reg_offset; + uint32_t status_reg_offset; +}; + +/* + * struct cam_irq_controller_reg_info: + * @Brief: Structure describing the IRQ registers + * + * @num_registers: Number of sets(mask/clear/status) of IRQ registers + * @irq_reg_set: Array of Register Set Offsets. + * Length of array = num_registers + * @global_clear_offset: Offset of Global IRQ Clear register. This register + * contains the BIT that needs to be set for the CLEAR + * to take effect + * @global_clear_bitmask: Bitmask needed to be used in Global Clear register + * for Clear IRQ cmd to take effect + */ +struct cam_irq_controller_reg_info { + uint32_t num_registers; + struct cam_irq_register_set *irq_reg_set; + uint32_t global_clear_offset; + uint32_t global_clear_bitmask; +}; + +/* + * struct cam_irq_th_payload: + * @Brief: Event payload structure. This structure will be + * passed to the Top Half handler functions. + * + * @handler_priv: Private Data of handling object set when + * subscribing to IRQ event. + * @num_registers: Length of evt_bit_mask Array below + * @evt_status_arr: Array of Status bitmask read from registers. + * Length of array = num_registers + * @evt_payload_priv: Private payload pointer which can be set by Top + * Half handler for use in Bottom Half. + */ +struct cam_irq_th_payload { + void *handler_priv; + uint32_t num_registers; + uint32_t *evt_status_arr; + void *evt_payload_priv; +}; + +/* + * cam_irq_th_payload_init() + * + * @brief: Initialize the top half payload structure + * + * @th_payload: Top Half payload structure to Initialize + * + * @return: Void + */ +static inline void cam_irq_th_payload_init( + struct cam_irq_th_payload *th_payload) { + th_payload->handler_priv = NULL; + th_payload->evt_payload_priv = NULL; +} + +typedef int (*CAM_IRQ_HANDLER_TOP_HALF)(uint32_t evt_id, + struct cam_irq_th_payload *th_payload); + +typedef int (*CAM_IRQ_HANDLER_BOTTOM_HALF)(void *handler_priv, + void *evt_payload_priv); + +typedef void (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF); + +typedef int (*CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +typedef void (*CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +struct cam_irq_bh_api { + CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func; + CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC get_bh_payload_func; + CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC put_bh_payload_func; +}; + +/* + * cam_irq_controller_init() + * + * @brief: Create and Initialize IRQ Controller. + * + * @name: Name of IRQ Controller block + * @mem_base: Mapped base address of register space to which + * register offsets are added to access registers + * @register_info: Register Info structure associated with this Controller + * @irq_controller: Pointer to IRQ Controller that will be filled if + * initialization is successful + * + * @return: 0: Success + * Negative: Failure + */ +int cam_irq_controller_init(const char *name, + void __iomem *mem_base, + struct cam_irq_controller_reg_info *register_info, + void **irq_controller); + +/* + * cam_irq_controller_subscribe_irq() + * + * @brief: Subscribe to certain IRQ events. + * + * @irq_controller: Pointer to IRQ Controller that controls this event IRQ + * @priority: Priority level of these events used if multiple events + * are SET in the Status Register + * @evt_bit_mask_arr: evt_bit_mask that has the bits set for IRQs to + * subscribe for + * @handler_priv: Private data that will be passed to the Top/Bottom Half + * handler function + * @top_half_handler: Top half Handler callback function + * @bottom_half_handler: Bottom half Handler callback function + * @bottom_half: Pointer to bottom_half implementation on which to + * enqueue the event for further handling + * @bottom_half_enqueue_func: + * Function used to enqueue the bottom_half event + * + * @return: Positive: Success. Value represents handle which is + * to be used to unsubscribe + * Negative: Failure + */ +int cam_irq_controller_subscribe_irq(void *irq_controller, + enum cam_irq_priority_level priority, + uint32_t *evt_bit_mask_arr, + void *handler_priv, + CAM_IRQ_HANDLER_TOP_HALF top_half_handler, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, + void *bottom_half, + struct cam_irq_bh_api *irq_bh_api); + +/* + * cam_irq_controller_unsubscribe_irq() + * + * @brief: Unsubscribe to IRQ events previously subscribed to. + * + * @irq_controller: Pointer to IRQ Controller that controls this event IRQ + * @handle: Handle returned on successful subscribe used to + * identify the handler object + * + * @return: 0: Success + * Negative: Failure + */ +int cam_irq_controller_unsubscribe_irq(void *irq_controller, + uint32_t handle); + +/* + * cam_irq_controller_deinit() + * + * @brief: Deinitialize IRQ Controller. + * + * @irq_controller: Pointer to IRQ Controller that needs to be + * deinitialized + * + * @return: 0: Success + * Negative: Failure + */ +int cam_irq_controller_deinit(void **irq_controller); + +/* + * cam_irq_controller_handle_irq() + * + * @brief: Function that should be registered with the IRQ line. + * This is the first function to be called when the IRQ + * is fired. It will read the Status register and Clear + * the IRQ bits. It will then call the top_half handlers + * and enqueue the result to bottom_half. + * + * @irq_num: Number of IRQ line that was set that lead to this + * function being called + * @priv: Private data registered with request_irq is passed back + * here. This private data should be the irq_controller + * structure. + * + * @return: IRQ_HANDLED/IRQ_NONE + */ +irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv); + +/* + * cam_irq_controller_disable_irq() + * + * @brief: Disable the interrupts on given controller. + * Unsubscribe will disable the IRQ by default, so this is + * only needed if between subscribe/unsubscribe there is + * need to disable IRQ again + * + * @irq_controller: Pointer to IRQ Controller that controls the registered + * events to it. + * @handle: Handle returned on successful subscribe, used to + * identify the handler object + * + * @return: 0: events found and disabled + * Negative: events not registered on this controller + */ +int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle); + +/* + * cam_irq_controller_enable_irq() + * + * @brief: Enable the interrupts on given controller. + * Subscribe will enable the IRQ by default, so this is + * only needed if between subscribe/unsubscribe there is + * need to enable IRQ again + * + * @irq_controller: Pointer to IRQ Controller that controls the registered + * events to it. + * @handle: Handle returned on successful subscribe, used to + * identify the handler object + * + * @return: 0: events found and enabled + * Negative: events not registered on this controller + */ +int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle); + +/* + * cam_irq_controller_clear_and_mask() + * + * @brief: This function clears and masks all the irq bits + * + * @irq_num: Number of IRQ line that was set that lead to this + * function being called + * @priv: Private data registered with request_irq is passed back + * here. This private data should be the irq_controller + * structure. + * + * @return: IRQ_HANDLED/IRQ_NONE + */ +irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv); +#endif /* _CAM_IRQ_CONTROLLER_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h new file mode 100644 index 000000000000..fb39c02e25c8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_MGR_INTF_H_ +#define _CAM_ISP_HW_MGR_INTF_H_ + +#include +#include +#include +#include +#include "cam_hw_mgr_intf.h" + +/* MAX IFE instance */ +#define CAM_IFE_HW_NUM_MAX 7 +#define CAM_IFE_RDI_NUM_MAX 4 +#define CAM_ISP_BW_CONFIG_V1 1 +#define CAM_ISP_BW_CONFIG_V2 2 + +/* Appliacble vote paths for dual ife, based on no. of UAPI definitions */ +#define CAM_ISP_MAX_PER_PATH_VOTES 30 +/** + * enum cam_isp_hw_event_type - Collection of the ISP hardware events + */ +enum cam_isp_hw_event_type { + CAM_ISP_HW_EVENT_ERROR, + CAM_ISP_HW_EVENT_SOF, + CAM_ISP_HW_EVENT_REG_UPDATE, + CAM_ISP_HW_EVENT_EPOCH, + CAM_ISP_HW_EVENT_EOF, + CAM_ISP_HW_EVENT_DONE, + CAM_ISP_HW_EVENT_MAX +}; + + +/** + * enum cam_isp_hw_err_type - Collection of the ISP error types for + * ISP hardware event CAM_ISP_HW_EVENT_ERROR + */ +enum cam_isp_hw_err_type { + CAM_ISP_HW_ERROR_NONE, + CAM_ISP_HW_ERROR_OVERFLOW, + CAM_ISP_HW_ERROR_P2I_ERROR, + CAM_ISP_HW_ERROR_VIOLATION, + CAM_ISP_HW_ERROR_BUSIF_OVERFLOW, + CAM_ISP_HW_ERROR_MAX, +}; + +/** + * enum cam_isp_hw_stop_cmd - Specify the stop command type + */ +enum cam_isp_hw_stop_cmd { + CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY, + CAM_ISP_HW_STOP_IMMEDIATELY, + CAM_ISP_HW_STOP_MAX, +}; + +/** + * struct cam_isp_stop_args - hardware stop arguments + * + * @hw_stop_cmd: Hardware stop command type information + * @stop_only Send stop only to hw drivers. No Deinit to be + * done. + * + */ +struct cam_isp_stop_args { + enum cam_isp_hw_stop_cmd hw_stop_cmd; + bool stop_only; +}; + +/** + * struct cam_isp_start_args - isp hardware start arguments + * + * @config_args: Hardware configuration commands. + * @start_only Send start only to hw drivers. No init to + * be done. + * + */ +struct cam_isp_start_args { + struct cam_hw_config_args hw_config; + bool start_only; +}; + +/** + * struct cam_isp_bw_config_internal_v2 - Bandwidth configuration + * + * @usage_type: ife hw index + * @num_paths: Number of data paths + * @axi_path per path vote info + */ +struct cam_isp_bw_config_internal_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ISP_MAX_PER_PATH_VOTES]; +}; + +/** + * struct cam_isp_bw_config_internal - Internal Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_vote: Bandwidth vote for left ISP + * @right_pix_vote: Bandwidth vote for right ISP + * @rdi_vote: RDI bandwidth requirements + */ +struct cam_isp_bw_config_internal { + uint32_t usage_type; + uint32_t num_rdi; + struct cam_isp_bw_vote left_pix_vote; + struct cam_isp_bw_vote right_pix_vote; + struct cam_isp_bw_vote rdi_vote[CAM_IFE_RDI_NUM_MAX]; +}; + +/** + * struct cam_isp_prepare_hw_update_data - hw prepare data + * + * @packet_opcode_type: Packet header opcode in the packet header + * this opcode defines, packet is init packet or + * update packet + * @bw_config_version: BW config version indicator + * @bw_config: BW config information + * @bw_config_v2: BW config info for AXI bw voting v2 + * @bw_config_valid: Flag indicating whether the bw_config at the index + * is valid or not + * + */ +struct cam_isp_prepare_hw_update_data { + uint32_t packet_opcode_type; + uint32_t bw_config_version; + struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; + struct cam_isp_bw_config_internal_v2 bw_config_v2[CAM_IFE_HW_NUM_MAX]; + bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; +}; + + +/** + * struct cam_isp_hw_sof_event_data - Event payload for CAM_HW_EVENT_SOF + * + * @timestamp: Time stamp for the sof event + * @boot_time: Boot time stamp for the sof event + * + */ +struct cam_isp_hw_sof_event_data { + uint64_t timestamp; + uint64_t boot_time; +}; + +/** + * struct cam_isp_hw_reg_update_event_data - Event payload for + * CAM_HW_EVENT_REG_UPDATE + * + * @timestamp: Time stamp for the reg update event + * + */ +struct cam_isp_hw_reg_update_event_data { + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_epoch_event_data - Event payload for CAM_HW_EVENT_EPOCH + * + * @timestamp: Time stamp for the epoch event + * + */ +struct cam_isp_hw_epoch_event_data { + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_done_event_data - Event payload for CAM_HW_EVENT_DONE + * + * @num_handles: Number of resource handeles + * @resource_handle: Resource handle array + * @timestamp: Timestamp for the buf done event + * + */ +struct cam_isp_hw_done_event_data { + uint32_t num_handles; + uint32_t resource_handle[ + CAM_NUM_OUT_PER_COMP_IRQ_MAX]; + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_eof_event_data - Event payload for CAM_HW_EVENT_EOF + * + * @timestamp: Timestamp for the eof event + * + */ +struct cam_isp_hw_eof_event_data { + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_error_event_data - Event payload for CAM_HW_EVENT_ERROR + * + * @error_type: Error type for the error event + * @timestamp: Timestamp for the error event + * @recovery_enabled: Identifies if the context needs to recover & reapply + * this request + * @enable_req_dump: Enable request dump on HW errors + */ +struct cam_isp_hw_error_event_data { + uint32_t error_type; + uint64_t timestamp; + bool recovery_enabled; + bool enable_req_dump; +}; + +/* enum cam_isp_hw_mgr_command - Hardware manager command type */ +enum cam_isp_hw_mgr_command { + CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT, + CAM_ISP_HW_MGR_CMD_PAUSE_HW, + CAM_ISP_HW_MGR_CMD_RESUME_HW, + CAM_ISP_HW_MGR_CMD_SOF_DEBUG, + CAM_ISP_HW_MGR_CMD_CTX_TYPE, + CAM_ISP_HW_MGR_CMD_MAX, +}; + +enum cam_isp_ctx_type { + CAM_ISP_CTX_FS2 = 1, + CAM_ISP_CTX_RDI, + CAM_ISP_CTX_PIX, + CAM_ISP_CTX_MAX, +}; +/** + * struct cam_isp_hw_cmd_args - Payload for hw manager command + * + * @cmd_type HW command type + * @sof_irq_enable To debug if SOF irq is enabled + * @ctx_type RDI_ONLY, PIX and RDI, or FS2 + */ +struct cam_isp_hw_cmd_args { + uint32_t cmd_type; + union { + uint32_t sof_irq_enable; + uint32_t ctx_type; + } u; +}; + + +/** + * cam_isp_hw_mgr_init() + * + * @brief: Initialization function for the ISP hardware manager + * + * @of_node: Device node input + * @hw_mgr: Input/output structure for the ISP hardware manager + * initialization + * @iommu_hdl: Iommu handle to be returned + */ +int cam_isp_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl); + +#endif /* __CAM_ISP_HW_MGR_INTF_H__ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile new file mode 100644 index 000000000000..41c244c96572 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_hw/ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile new file mode 100644 index 000000000000..8ccd9f0b3f62 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ife_csid_dev.o cam_ife_csid_soc.o cam_ife_csid_core.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ife_csid17x.o cam_ife_csid_lite17x.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h new file mode 100644 index 000000000000..714fa8ef2b31 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h @@ -0,0 +1,305 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_170_H_ +#define _CAM_IFE_CSID_170_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_170_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_170_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_170_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_170_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_170_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_170_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_170_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0x0, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_170_reg_offset = { + .cmn_reg = &cam_ife_csid_170_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_170_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_170_ipp_reg_offset, + .ppp_reg = NULL, + .rdi_reg = { + &cam_ife_csid_170_rdi_0_reg_offset, + &cam_ife_csid_170_rdi_1_reg_offset, + &cam_ife_csid_170_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_170_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_170_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h new file mode 100644 index 000000000000..70f96ea416d8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_175_H_ +#define _CAM_IFE_CSID_175_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_175_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_175_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_175_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_175_reg_offset = { + .cmn_reg = &cam_ife_csid_175_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_175_rdi_0_reg_offset, + &cam_ife_csid_175_rdi_1_reg_offset, + &cam_ife_csid_175_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_175_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_175_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h new file mode 100644 index 000000000000..7d47da31e4a8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h @@ -0,0 +1,362 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_175_200_H_ +#define _CAM_IFE_CSID_175_200_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, +}; + + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_175_200_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + .csid_csi2_rx_de_scramble_type3_cfg0_addr = 0x170, + .csid_csi2_rx_de_scramble_type3_cfg1_addr = 0x174, + .csid_csi2_rx_de_scramble_type2_cfg0_addr = 0x178, + .csid_csi2_rx_de_scramble_type2_cfg1_addr = 0x17c, + .csid_csi2_rx_de_scramble_type1_cfg0_addr = 0x180, + .csid_csi2_rx_de_scramble_type1_cfg1_addr = 0x184, + .csid_csi2_rx_de_scramble_type0_cfg0_addr = 0x188, + .csid_csi2_rx_de_scramble_type0_cfg1_addr = 0x18c, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x7, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_175_200_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_175_200_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 5, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0xFFFF, + .rdi_irq_mask_all = 0xFFFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_175_200_reg_offset = { + .cmn_reg = &cam_ife_csid_175_200_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_200_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_200_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_200_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_175_200_rdi_0_reg_offset, + &cam_ife_csid_175_200_rdi_1_reg_offset, + &cam_ife_csid_175_200_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_175_200_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_175_200_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c new file mode 100644 index 000000000000..d88347caa388 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + + +#include +#include "cam_ife_csid_core.h" +#include "cam_ife_csid170.h" +#include "cam_ife_csid175.h" +#include "cam_ife_csid175_200.h" +#include "cam_ife_csid480.h" +#include "cam_ife_csid_dev.h" + +#define CAM_CSID_DRV_NAME "csid_17x" +#define CAM_CSID_VERSION_V170 0x10070000 +#define CAM_CSID_VERSION_V175 0x10070050 +#define CAM_CSID_VERSION_V480 0x40080000 + +static struct cam_ife_csid_hw_info cam_ife_csid170_hw_info = { + .csid_reg = &cam_ife_csid_170_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V170, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid175_hw_info = { + .csid_reg = &cam_ife_csid_175_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid175_200_hw_info = { + .csid_reg = &cam_ife_csid_175_200_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid480_hw_info = { + .csid_reg = &cam_ife_csid_480_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V480, +}; + +static const struct of_device_id cam_ife_csid17x_dt_match[] = { + { + .compatible = "qcom,csid170", + .data = &cam_ife_csid170_hw_info, + }, + { + .compatible = "qcom,csid175", + .data = &cam_ife_csid175_hw_info, + }, + { + .compatible = "qcom,csid175_200", + .data = &cam_ife_csid175_200_hw_info, + }, + { + .compatible = "qcom,csid480", + .data = &cam_ife_csid480_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_ife_csid17x_dt_match); + +static struct platform_driver cam_ife_csid17x_driver = { + .probe = cam_ife_csid_probe, + .remove = cam_ife_csid_remove, + .driver = { + .name = CAM_CSID_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_ife_csid17x_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ife_csid17x_init_module(void) +{ + return platform_driver_register(&cam_ife_csid17x_driver); +} + +static void __exit cam_ife_csid17x_exit_module(void) +{ + platform_driver_unregister(&cam_ife_csid17x_driver); +} + +module_init(cam_ife_csid17x_init_module); +module_exit(cam_ife_csid17x_exit_module); +MODULE_DESCRIPTION("CAM IFE_CSID17X driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h new file mode 100644 index 000000000000..c18a21ff7c32 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h @@ -0,0 +1,379 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_480_H_ +#define _CAM_IFE_CSID_480_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_480_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + .csid_pxl_err_recovery_cfg0_addr = 0x2d0, + .csid_pxl_err_recovery_cfg1_addr = 0x2d4, + .csid_pxl_err_recovery_cfg2_addr = 0x2d8, + .csid_pxl_multi_vcdt_cfg0_addr = 0x2dc, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_480_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + .csid_pxl_err_recovery_cfg0_addr = 0x7d0, + .csid_pxl_err_recovery_cfg1_addr = 0x7d4, + .csid_pxl_err_recovery_cfg2_addr = 0x7d8, + .csid_pxl_multi_vcdt_cfg0_addr = 0x7dc, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_480_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_err_recovery_cfg0_addr = 0x3b0, + .csid_rdi_err_recovery_cfg1_addr = 0x3b4, + .csid_rdi_err_recovery_cfg2_addr = 0x3b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x3bc, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_480_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_err_recovery_cfg0_addr = 0x4b0, + .csid_rdi_err_recovery_cfg1_addr = 0x4b4, + .csid_rdi_err_recovery_cfg2_addr = 0x4b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x4bc, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_480_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_err_recovery_cfg0_addr = 0x5b0, + .csid_rdi_err_recovery_cfg1_addr = 0x5b4, + .csid_rdi_err_recovery_cfg2_addr = 0x5b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x5bc, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_480_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_480_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_480_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_480_reg_offset = { + .cmn_reg = &cam_ife_csid_480_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_480_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_480_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_480_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_480_rdi_0_reg_offset, + &cam_ife_csid_480_rdi_1_reg_offset, + &cam_ife_csid_480_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_480_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_480_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c new file mode 100644 index 000000000000..cce05296f04a --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -0,0 +1,3704 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_ife_csid_core.h" +#include "cam_isp_hw.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +/* Timeout value in msec */ +#define IFE_CSID_TIMEOUT 1000 + +/* TPG VC/DT values */ +#define CAM_IFE_CSID_TPG_VC_VAL 0xA +#define CAM_IFE_CSID_TPG_DT_VAL 0x2B + +/* Timeout values in usec */ +#define CAM_IFE_CSID_TIMEOUT_SLEEP_US 1000 +#define CAM_IFE_CSID_TIMEOUT_ALL_US 100000 + +/* + * Constant Factors needed to change QTimer ticks to nanoseconds + * QTimer Freq = 19.2 MHz + * Time(us) = ticks/19.2 + * Time(ns) = ticks/19.2 * 1000 + */ +#define CAM_IFE_CSID_QTIMER_MUL_FACTOR 10000 +#define CAM_IFE_CSID_QTIMER_DIV_FACTOR 192 + +/* Max number of sof irq's triggered in case of SOF freeze */ +#define CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX 12 + +/* Max CSI Rx irq error count threshold value */ +#define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 + +static int cam_ife_csid_is_ipp_ppp_format_supported( + uint32_t in_format) +{ + int rc = -EINVAL; + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_DPCM_10_6_10: + case CAM_FORMAT_DPCM_10_8_10: + case CAM_FORMAT_DPCM_12_6_12: + case CAM_FORMAT_DPCM_12_8_12: + case CAM_FORMAT_DPCM_14_8_14: + case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_DPCM_12_10_12: + rc = 0; + break; + default: + break; + } + return rc; +} + +static int cam_ife_csid_get_format_rdi( + uint32_t in_format, uint32_t out_format, + uint32_t *decode_fmt, uint32_t *plain_fmt) +{ + int rc = 0; + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_6: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN8: + *decode_fmt = 0x0; + *plain_fmt = 0x0; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_8: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN128: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN8: + *decode_fmt = 0x1; + *plain_fmt = 0x0; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_10: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_PLAIN128: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_10: + *decode_fmt = 0x2; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_12: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_12: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_12: + *decode_fmt = 0x3; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_14: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_14: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_14: + *decode_fmt = 0x4; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_16: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_16: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN16_16: + *decode_fmt = 0x5; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_20: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_20: + *decode_fmt = 0xf; + break; + case CAM_FORMAT_PLAIN32_20: + *decode_fmt = 0x6; + *plain_fmt = 0x2; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_DPCM_10_6_10: + *decode_fmt = 0x7; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_10_8_10: + *decode_fmt = 0x8; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_6_12: + *decode_fmt = 0x9; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_8_12: + *decode_fmt = 0xA; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_8_14: + *decode_fmt = 0xB; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_10_14: + *decode_fmt = 0xC; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + + if (rc) + CAM_ERR(CAM_ISP, "Unsupported format pair in %d out %d", + in_format, out_format); + + return rc; +} + +static int cam_ife_csid_get_format_ipp_ppp( + uint32_t in_format, + uint32_t *decode_fmt, uint32_t *plain_fmt) +{ + int rc = 0; + + CAM_DBG(CAM_ISP, "input format:%d", + in_format); + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + *decode_fmt = 0; + *plain_fmt = 0; + break; + case CAM_FORMAT_MIPI_RAW_8: + *decode_fmt = 0x1; + *plain_fmt = 0; + break; + case CAM_FORMAT_MIPI_RAW_10: + *decode_fmt = 0x2; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_12: + *decode_fmt = 0x3; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_14: + *decode_fmt = 0x4; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_16: + *decode_fmt = 0x5; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_20: + *decode_fmt = 0x6; + *plain_fmt = 0x2; + break; + case CAM_FORMAT_DPCM_10_6_10: + *decode_fmt = 0x7; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_10_8_10: + *decode_fmt = 0x8; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_6_12: + *decode_fmt = 0x9; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_8_12: + *decode_fmt = 0xA; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_8_14: + *decode_fmt = 0xB; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_10_14: + *decode_fmt = 0xC; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported format %d", + in_format); + rc = -EINVAL; + } + + CAM_DBG(CAM_ISP, "decode_fmt:%d plain_fmt:%d", + *decode_fmt, *plain_fmt); + + return rc; +} + +static int cam_ife_match_vc_dt_pair(int32_t *vc, uint32_t *dt, + uint32_t num_valid_vc_dt, struct cam_ife_csid_cid_data *cid_data) +{ + uint32_t camera_hw_version; + int rc = 0; + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + return -EINVAL; + } + + if (camera_hw_version != CAM_CPAS_TITAN_480_V100) + num_valid_vc_dt = 1; + + switch (num_valid_vc_dt) { + case 2: + if (vc[1] != cid_data->vc1 || + dt[1] != cid_data->dt1) + return -EINVAL; + case 1: + if (vc[0] != cid_data->vc || + dt[0] != cid_data->dt) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node **res, int32_t *vc, uint32_t *dt, + uint32_t num_valid_vc_dt) +{ + struct cam_ife_csid_cid_data *cid_data; + uint32_t i = 0; + + *res = NULL; + + /* Return already reserved CID if the VC/DT matches */ + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) { + if (csid_hw->cid_res[i].res_state >= + CAM_ISP_RESOURCE_STATE_RESERVED) { + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[i].res_priv; + if (!cam_ife_match_vc_dt_pair(vc, dt, + num_valid_vc_dt, cid_data)) { + cid_data->cnt++; + *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); + return 0; + } + } + } + + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) { + if (csid_hw->cid_res[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[i].res_priv; + cid_data->vc = vc[0]; + cid_data->dt = dt[0]; + if (num_valid_vc_dt > 1) { + cid_data->vc1 = vc[1]; + cid_data->dt1 = dt[1]; + cid_data->is_valid_vc1_dt1 = 1; + } + cid_data->cnt = 1; + csid_hw->cid_res[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); + return 0; + } + } + + CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available", + csid_hw->hw_intf->hw_idx); + + return -EINVAL; +} + + +static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) +{ + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + int rc = 0; + uint32_t val = 0, i; + uint32_t status; + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid HW State:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d Csid reset", + csid_hw->hw_intf->hw_idx); + + /* Mask all interrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_mask_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + + /* clear all interrupts */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(csid_reg->csi2_reg->csi2_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(csid_reg->cmn_reg->ipp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(csid_reg->cmn_reg->ppp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); + + for (i = 0 ; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + cam_io_w_mb(0x80, soc_info->reg_map[0].mem_base + + csid_hw->csid_info->csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + /* enable the IPP and RDI format measure */ + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_cfg0_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_cfg0_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr); + + /* perform the top CSID HW registers reset */ + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + } + + /* perform the SW registers reset */ + cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + } + + usleep_range(3000, 3010); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + if (val != 0) + CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d", + csid_hw->hw_intf->hw_idx, val); + csid_hw->error_irq_count = 0; + + return rc; +} + +static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_reset_cfg_args *reset) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t reset_strb_addr, reset_strb_val, val, id; + struct completion *complete; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + res = reset->node_res; + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid hw state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d resource:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + if (!csid_reg->ipp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = csid_reg->ipp_reg->csid_pxl_rst_strobes_addr; + complete = &csid_hw->csid_ipp_complete; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + if (!csid_reg->ppp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d PPP not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = csid_reg->ppp_reg->csid_pxl_rst_strobes_addr; + complete = &csid_hw->csid_ppp_complete; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_mask_addr); + } else { + id = res->res_id; + if (!csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d RDI res not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = + csid_reg->rdi_reg[id]->csid_rdi_rst_strobes_addr; + complete = + &csid_hw->csid_rdin_complete[id]; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + } + + init_completion(complete); + reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all; + + /* Enable the Test gen before reset */ + cam_io_w_mb(1, csid_hw->hw_info->soc_info.reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_ctrl_addr); + + /* Reset the corresponding ife csid path */ + cam_io_w_mb(reset_strb_val, soc_info->reg_map[0].mem_base + + reset_strb_addr); + + rc = wait_for_completion_timeout(complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, "CSID:%d Res id %d fail rc = %d", + csid_hw->hw_intf->hw_idx, + res->res_id, rc); + if (rc == 0) + rc = -ETIMEDOUT; + } + + /* Disable Test Gen after reset*/ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_ctrl_addr); + +end: + return rc; + +} + +static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *cid_reserv) +{ + int rc = 0, i; + struct cam_ife_csid_cid_data *cid_data; + uint32_t camera_hw_version; + uint32_t valid_vc_dt; + + CAM_DBG(CAM_ISP, + "CSID:%d res_sel:0x%x Lane type:%d lane_num:%d dt:%d vc:%d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type, + cid_reserv->in_port->lane_type, + cid_reserv->in_port->lane_num, + cid_reserv->in_port->dt[0], + cid_reserv->in_port->vc[0]); + + if (cid_reserv->in_port->res_type >= CAM_ISP_IFE_IN_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid phy sel %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type); + rc = -EINVAL; + goto end; + } + + if (cid_reserv->in_port->lane_type >= CAM_ISP_LANE_TYPE_MAX && + cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid lane type %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_type); + rc = -EINVAL; + goto end; + } + + if ((cid_reserv->in_port->lane_type == CAM_ISP_LANE_TYPE_DPHY && + cid_reserv->in_port->lane_num > 4) && + cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid lane num %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_num); + rc = -EINVAL; + goto end; + } + if ((cid_reserv->in_port->lane_type == CAM_ISP_LANE_TYPE_CPHY && + cid_reserv->in_port->lane_num > 3) && + cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, " CSID:%d Invalid lane type %d & num %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_type, + cid_reserv->in_port->lane_num); + rc = -EINVAL; + goto end; + } + + valid_vc_dt = cid_reserv->in_port->num_valid_vc_dt; + + /* CSID CSI2 v2.0 supports 31 vc */ + for (i = 0; i < valid_vc_dt; i++) { + if (cid_reserv->in_port->vc[i] > 0x1f || + cid_reserv->in_port->dt[i] > 0x3f) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d or dt: %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->vc[i], + cid_reserv->in_port->dt[i]); + rc = -EINVAL; + goto end; + } + } + + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG && ( + (cid_reserv->in_port->format < CAM_FORMAT_MIPI_RAW_8 && + cid_reserv->in_port->format > CAM_FORMAT_MIPI_RAW_16))) { + CAM_ERR(CAM_ISP, " CSID:%d Invalid tpg decode fmt %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->format); + rc = -EINVAL; + goto end; + } + + if (csid_hw->csi2_reserve_cnt == UINT_MAX) { + CAM_ERR(CAM_ISP, + "CSID%d reserve cnt reached max", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + goto end; + } + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_NONE: + case CAM_CPAS_TITAN_MAX: + CAM_ERR(CAM_ISP, "Invalid HW version: %x", camera_hw_version); + break; + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && + csid_hw->hw_intf->hw_idx != 2) { + rc = -EINVAL; + goto end; + } + break; + case CAM_CPAS_TITAN_480_V100: + if (cid_reserv->in_port->cust_node == 1) { + if (cid_reserv->in_port->usage_type == 1) { + CAM_ERR(CAM_ISP, "Dual IFE is not supported"); + rc = -EINVAL; + goto end; + } + if (csid_hw->hw_intf->hw_idx != 0) { + CAM_DBG(CAM_ISP, "CSID%d not eligible", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + } + break; + default: + break; + } + CAM_DBG(CAM_ISP, "Reserve_cnt %u", csid_hw->csi2_reserve_cnt); + + if (csid_hw->csi2_reserve_cnt) { + /* current configure res type should match requested res type */ + if (csid_hw->res_type != cid_reserv->in_port->res_type) { + rc = -EINVAL; + goto end; + } + + if (cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + if (csid_hw->csi2_rx_cfg.lane_cfg != + cid_reserv->in_port->lane_cfg || + csid_hw->csi2_rx_cfg.lane_type != + cid_reserv->in_port->lane_type || + csid_hw->csi2_rx_cfg.lane_num != + cid_reserv->in_port->lane_num) { + rc = -EINVAL; + goto end; + } + } else { + if (csid_hw->tpg_cfg.in_format != + cid_reserv->in_port->format || + csid_hw->tpg_cfg.width != + cid_reserv->in_port->left_width || + csid_hw->tpg_cfg.height != + cid_reserv->in_port->height || + csid_hw->tpg_cfg.test_pattern != + cid_reserv->in_port->test_pattern) { + rc = -EINVAL; + goto end; + } + } + } + + switch (cid_reserv->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource not available", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + break; + case CAM_IFE_PIX_PATH_RES_PPP: + if (csid_hw->ppp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d PPP resource not available state %d", + csid_hw->hw_intf->hw_idx, + csid_hw->ppp_res.res_state); + rc = -EINVAL; + goto end; + } + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (csid_hw->rdi_res[cid_reserv->res_id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d RDI:%d resource not available", + csid_hw->hw_intf->hw_idx, + cid_reserv->res_id); + rc = -EINVAL; + goto end; + } + break; + default: + CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + rc = cam_ife_csid_cid_get(csid_hw, + &cid_reserv->node_res, + cid_reserv->in_port->vc, + cid_reserv->in_port->dt, + cid_reserv->in_port->num_valid_vc_dt); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type); + goto end; + } + cid_data = (struct cam_ife_csid_cid_data *) + cid_reserv->node_res->res_priv; + + if (!csid_hw->csi2_reserve_cnt) { + csid_hw->res_type = cid_reserv->in_port->res_type; + + csid_hw->csi2_rx_cfg.lane_cfg = + cid_reserv->in_port->lane_cfg; + csid_hw->csi2_rx_cfg.lane_type = + cid_reserv->in_port->lane_type; + csid_hw->csi2_rx_cfg.lane_num = + cid_reserv->in_port->lane_num; + + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG) { + csid_hw->csi2_rx_cfg.phy_sel = 0; + if (cid_reserv->in_port->format > + CAM_FORMAT_MIPI_RAW_16) { + CAM_ERR(CAM_ISP, " Wrong TPG format"); + rc = -EINVAL; + goto end; + } + csid_hw->tpg_cfg.in_format = + cid_reserv->in_port->format; + csid_hw->tpg_cfg.usage_type = + cid_reserv->in_port->usage_type; + if (cid_reserv->in_port->usage_type) + csid_hw->tpg_cfg.width = + (cid_reserv->in_port->right_stop + 1); + else + csid_hw->tpg_cfg.width = + cid_reserv->in_port->left_width; + + csid_hw->tpg_cfg.height = cid_reserv->in_port->height; + csid_hw->tpg_cfg.test_pattern = + cid_reserv->in_port->test_pattern; + + CAM_DBG(CAM_ISP, "CSID:%d TPG width:%d height:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->tpg_cfg.width, + csid_hw->tpg_cfg.height); + + cid_data->tpg_set = 1; + } else { + csid_hw->csi2_rx_cfg.phy_sel = + (cid_reserv->in_port->res_type & 0xFF) - 1; + } + } + + csid_hw->csi2_reserve_cnt++; + CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired", + csid_hw->hw_intf->hw_idx, + cid_reserv->node_res->res_id); + +end: + return rc; +} + + +static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *reserve) +{ + int rc = 0, i; + struct cam_ife_csid_path_cfg *path_data; + struct cam_isp_resource_node *res; + + /* CSID CSI2 v2.0 supports 31 vc */ + if (reserve->sync_mode >= CAM_ISP_HW_SYNC_MAX) { + CAM_ERR(CAM_ISP, "CSID: %d Sync Mode: %d", + reserve->sync_mode); + return -EINVAL; + } + + for (i = 0; i < reserve->in_port->num_valid_vc_dt; i++) { + if (reserve->in_port->dt[i] > 0x3f || + reserve->in_port->vc[i] > 0x1f) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d", + csid_hw->hw_intf->hw_idx, + reserve->in_port->vc, reserve->in_port->dt); + rc = -EINVAL; + goto end; + } + } + + switch (reserve->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d IPP resource not available %d", + csid_hw->hw_intf->hw_idx, + csid_hw->ipp_res.res_state); + rc = -EINVAL; + goto end; + } + + if (cam_ife_csid_is_ipp_ppp_format_supported( + reserve->in_port->format)) { + CAM_ERR(CAM_ISP, + "CSID:%d res id:%d un support format %d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + reserve->in_port->format); + rc = -EINVAL; + goto end; + } + + /* assign the IPP resource */ + res = &csid_hw->ipp_res; + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource:%d acquired successfully", + csid_hw->hw_intf->hw_idx, res->res_id); + + break; + case CAM_IFE_PIX_PATH_RES_PPP: + if (csid_hw->ppp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d PPP resource not available %d", + csid_hw->hw_intf->hw_idx, + csid_hw->ppp_res.res_state); + rc = -EINVAL; + goto end; + } + + if (cam_ife_csid_is_ipp_ppp_format_supported( + reserve->in_port->format)) { + CAM_ERR(CAM_ISP, + "CSID:%d res id:%d unsupported format %d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + reserve->in_port->format); + rc = -EINVAL; + goto end; + } + + /* assign the PPP resource */ + res = &csid_hw->ppp_res; + CAM_DBG(CAM_ISP, + "CSID:%d PPP resource:%d acquired successfully", + csid_hw->hw_intf->hw_idx, res->res_id); + + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (csid_hw->rdi_res[reserve->res_id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d RDI:%d resource not available %d", + csid_hw->hw_intf->hw_idx, + reserve->res_id, + csid_hw->rdi_res[reserve->res_id].res_state); + rc = -EINVAL; + goto end; + } else { + res = &csid_hw->rdi_res[reserve->res_id]; + CAM_DBG(CAM_ISP, + "CSID:%d RDI resource:%d acquire success", + csid_hw->hw_intf->hw_idx, + res->res_id); + } + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id:%d", + csid_hw->hw_intf->hw_idx, reserve->res_id); + rc = -EINVAL; + goto end; + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; + + path_data->cid = reserve->cid; + path_data->in_format = reserve->in_port->format; + path_data->out_format = reserve->out_port->format; + path_data->sync_mode = reserve->sync_mode; + path_data->height = reserve->in_port->height; + path_data->start_line = reserve->in_port->line_start; + path_data->end_line = reserve->in_port->line_stop; + path_data->crop_enable = reserve->crop_enable; + + CAM_DBG(CAM_ISP, + "Res id: %d height:%d line_start %d line_stop %d crop_en %d", + reserve->res_id, reserve->in_port->height, + reserve->in_port->line_start, reserve->in_port->line_stop, + path_data->crop_enable); + + if (reserve->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG) { + path_data->dt = CAM_IFE_CSID_TPG_DT_VAL; + path_data->vc = CAM_IFE_CSID_TPG_VC_VAL; + } else { + path_data->dt = reserve->in_port->dt[0]; + path_data->vc = reserve->in_port->vc[0]; + if (reserve->in_port->num_valid_vc_dt) { + path_data->dt1 = reserve->in_port->dt[1]; + path_data->vc1 = reserve->in_port->vc[1]; + path_data->is_valid_vc1_dt1 = 1; + } + } + + if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) { + path_data->start_pixel = reserve->in_port->left_start; + path_data->end_pixel = reserve->in_port->left_stop; + path_data->width = reserve->in_port->left_width; + CAM_DBG(CAM_ISP, "CSID:%d master:startpixel 0x%x endpixel:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_pixel, + path_data->end_pixel); + CAM_DBG(CAM_ISP, "CSID:%d master:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_line, + path_data->end_line); + } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { + path_data->master_idx = reserve->master_idx; + CAM_DBG(CAM_ISP, "CSID:%d master_idx=%d", + csid_hw->hw_intf->hw_idx, path_data->master_idx); + path_data->start_pixel = reserve->in_port->right_start; + path_data->end_pixel = reserve->in_port->right_stop; + path_data->width = reserve->in_port->right_width; + CAM_DBG(CAM_ISP, "CSID:%d slave:start:0x%x end:0x%x width 0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_pixel, + path_data->end_pixel, path_data->width); + CAM_DBG(CAM_ISP, "CSID:%d slave:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_line, + path_data->end_line); + } else { + path_data->width = reserve->in_port->left_width; + path_data->start_pixel = reserve->in_port->left_start; + path_data->end_pixel = reserve->in_port->left_stop; + CAM_DBG(CAM_ISP, "Res id: %d left width %d start: %d stop:%d", + reserve->res_id, reserve->in_port->left_width, + reserve->in_port->left_start, + reserve->in_port->left_stop); + } + + CAM_DBG(CAM_ISP, "Res %d width %d height %d", reserve->res_id, + path_data->width, path_data->height); + reserve->node_res = res; + +end: + return rc; +} + +static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) +{ + int rc = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t i, val, clk_lvl; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* overflow check before increment */ + if (csid_hw->hw_info->open_count == UINT_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Open count reached max", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + + /* Increment ref Count */ + csid_hw->hw_info->open_count++; + if (csid_hw->hw_info->open_count > 1) { + CAM_DBG(CAM_ISP, "CSID hw has already been enabled"); + return rc; + } + + CAM_DBG(CAM_ISP, "CSID:%d init CSID HW", + csid_hw->hw_intf->hw_idx); + + clk_lvl = cam_soc_util_get_vote_level(soc_info, csid_hw->clk_rate); + CAM_DBG(CAM_ISP, "CSID clock lvl %u", clk_lvl); + + rc = cam_ife_csid_enable_soc_resources(soc_info, clk_lvl); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d Enable SOC failed", + csid_hw->hw_intf->hw_idx); + goto err; + } + + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_UP; + /* Reset CSID top */ + rc = cam_ife_csid_global_reset(csid_hw); + if (rc) + goto disable_soc; + + /* clear all interrupts */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(csid_reg->csi2_reg->csi2_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(csid_reg->cmn_reg->ipp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(csid_reg->cmn_reg->ppp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_hw_version_addr); + CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + return 0; + +disable_soc: + cam_ife_csid_disable_soc_resources(soc_info); + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; +err: + csid_hw->hw_info->open_count--; + return rc; +} + +static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) +{ + int rc = -EINVAL; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; + + /* Check for refcount */ + if (!csid_hw->hw_info->open_count) { + CAM_WARN(CAM_ISP, "Unbalanced disable_hw"); + return rc; + } + + /* Decrement ref Count */ + csid_hw->hw_info->open_count--; + + if (csid_hw->hw_info->open_count) { + rc = 0; + return rc; + } + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + CAM_DBG(CAM_ISP, "%s:Calling Global Reset\n", __func__); + cam_ife_csid_global_reset(csid_hw); + CAM_DBG(CAM_ISP, "%s:Global Reset Done\n", __func__); + + CAM_DBG(CAM_ISP, "CSID:%d De-init CSID HW", + csid_hw->hw_intf->hw_idx); + + /*disable the top IRQ interrupt */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + + rc = cam_ife_csid_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", + csid_hw->hw_intf->hw_idx); + + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 0; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + csid_hw->error_irq_count = 0; + + return rc; +} + + +static int cam_ife_csid_tpg_start(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t val = 0; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg = NULL; + + csid_hw->tpg_start_cnt++; + if (csid_hw->tpg_start_cnt == 1) { + /*Enable the TPG */ + CAM_DBG(CAM_ISP, "CSID:%d start CSID TPG", + csid_hw->hw_intf->hw_idx); + + soc_info = &csid_hw->hw_info->soc_info; + { + uint32_t val; + uint32_t i; + uint32_t base = 0x600; + + CAM_DBG(CAM_ISP, "================ TPG ============"); + for (i = 0; i < 16; i++) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + base + i * 4); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", + (base + i*4), val); + } + + CAM_DBG(CAM_ISP, "================ IPP ============="); + base = 0x200; + for (i = 0; i < 10; i++) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + base + i * 4); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", + (base + i*4), val); + } + + CAM_DBG(CAM_ISP, "================ RX ============="); + base = 0x100; + for (i = 0; i < 5; i++) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + base + i * 4); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", + (base + i*4), val); + } + } + + /* Enable the IFE force clock on for dual isp case */ + csid_reg = csid_hw->csid_info->csid_reg; + if (csid_hw->tpg_cfg.usage_type) { + rc = cam_ife_csid_enable_ife_force_clock_on(soc_info, + csid_reg->tpg_reg->tpg_cpas_ife_reg_offset); + if (rc) + return rc; + } + + CAM_DBG(CAM_ISP, "============ TPG control ============"); + val = (4 << 20); + val |= (0x80 << 8); + val |= (((csid_hw->csi2_rx_cfg.lane_num - 1) & 0x3) << 4); + val |= 7; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_ctrl_addr); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + 0x600); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", 0x600, val); + } + + return 0; +} + +static int cam_ife_csid_tpg_stop(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg = NULL; + + if (csid_hw->tpg_start_cnt) + csid_hw->tpg_start_cnt--; + + if (csid_hw->tpg_start_cnt) + return 0; + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + /* disable the TPG */ + if (!csid_hw->tpg_start_cnt) { + CAM_DBG(CAM_ISP, "CSID:%d stop CSID TPG", + csid_hw->hw_intf->hw_idx); + + /* Disable the IFE force clock on for dual isp case */ + if (csid_hw->tpg_cfg.usage_type) + rc = cam_ife_csid_disable_ife_force_clock_on(soc_info, + csid_reg->tpg_reg->tpg_cpas_ife_reg_offset); + + /*stop the TPG */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_hw->csid_info->csid_reg->tpg_reg->csid_tpg_ctrl_addr); + } + + return 0; +} + + +static int cam_ife_csid_config_tpg(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t val = 0; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + CAM_DBG(CAM_ISP, "CSID:%d TPG config", + csid_hw->hw_intf->hw_idx); + + /* configure one DT, infinite frames */ + val = (0 << 16) | (1 << 10) | CAM_IFE_CSID_TPG_VC_VAL; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_vc_cfg0_addr); + + /* vertical blanking count = 0x3FF, horzontal blanking count = 0x740*/ + val = (0x3FF << 12) | 0x740; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_vc_cfg1_addr); + + cam_io_w_mb(0x12345678, soc_info->reg_map[0].mem_base + + csid_hw->csid_info->csid_reg->tpg_reg->csid_tpg_lfsr_seed_addr); + + val = csid_hw->tpg_cfg.width << 16 | + csid_hw->tpg_cfg.height; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_dt_n_cfg_0_addr); + + cam_io_w_mb(CAM_IFE_CSID_TPG_DT_VAL, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_dt_n_cfg_1_addr); + + /* + * in_format is the same as the input resource format. + * it is one larger than the register spec format. + */ + val = ((csid_hw->tpg_cfg.in_format - 1) << 16) | 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_dt_n_cfg_2_addr); + + /* static frame with split color bar */ + val = 1 << 5; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_color_bars_cfg_addr); + /* config pix pattern */ + cam_io_w_mb(csid_hw->tpg_cfg.test_pattern, + soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_common_gen_cfg_addr); + + return 0; +} + +static int cam_ife_csid_enable_csi2( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_cid_data *cid_data; + uint32_t val = 0; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_DBG(CAM_ISP, "CSID:%d count:%d config csi2 rx", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + + /* overflow check before increment */ + if (csid_hw->csi2_cfg_cnt == UINT_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Open count reached max", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + + cid_data = (struct cam_ife_csid_cid_data *)res->res_priv; + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + csid_hw->csi2_cfg_cnt++; + if (csid_hw->csi2_cfg_cnt > 1) + return rc; + + /* rx cfg0 */ + val = 0; + val = (csid_hw->csi2_rx_cfg.lane_num - 1) | + (csid_hw->csi2_rx_cfg.lane_cfg << 4) | + (csid_hw->csi2_rx_cfg.lane_type << 24); + val |= (csid_hw->csi2_rx_cfg.phy_sel & + csid_reg->csi2_reg->csi2_rx_phy_num_mask) << 20; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + + /* rx cfg1*/ + val = (1 << csid_reg->csi2_reg->csi2_misr_enable_shift_val); + /* if VC value is more than 3 than set full width of VC */ + if (cid_data->vc > 3 || (cid_data->is_valid_vc1_dt1 && + cid_data->vc1 > 3)) + val |= (1 << csid_reg->csi2_reg->csi2_vc_mode_shift_val); + + /* enable packet ecc correction */ + val |= 1; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) { + /* Config the TPG */ + rc = cam_ife_csid_config_tpg(csid_hw, res); + if (rc) { + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; + } + } + + /*Enable the CSI2 rx inerrupts */ + val = CSID_CSI2_RX_INFO_RST_DONE | + CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION | + CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION | + CSID_CSI2_RX_ERROR_CRC | + CSID_CSI2_RX_ERROR_ECC | + CSID_CSI2_RX_ERROR_MMAPPED_VC_DT | + CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW | + CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME | + CSID_CSI2_RX_ERROR_CPHY_PH_CRC; + + /* Enable the interrupt based on csid debug info set */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) + val |= CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) + val |= CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + return 0; +} + +static int cam_ife_csid_disable_csi2( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + if (res->res_id >= CAM_IFE_CSID_CID_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id :%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_DBG(CAM_ISP, "CSID:%d cnt : %d Disable csi2 rx", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + + if (csid_hw->csi2_cfg_cnt) + csid_hw->csi2_cfg_cnt--; + + if (csid_hw->csi2_cfg_cnt) + return 0; + + /* Disable the CSI2 rx inerrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + /* Reset the Rx CFG registers */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return 0; +} + +static void cam_ife_csid_halt_csi2( + struct cam_ife_csid_hw *csid_hw) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_INFO(CAM_ISP, "CSID: %d cnt: %d Halt csi2 rx", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + + /* Disable the CSI2 rx inerrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + /* Reset the Rx CFG registers */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); +} + +static int cam_ife_csid_init_config_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; + bool is_ipp; + uint32_t decode_format = 0, plain_format = 0, val = 0; + uint32_t camera_hw_version; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Config %s Path", (is_ipp) ? "IPP" : "PPP"); + rc = cam_ife_csid_get_format_ipp_ppp(path_data->in_format, + &decode_format, &plain_format); + if (rc) + return rc; + + /* + * configure Pxl path and enable the time stamp capture. + * enable the HW measrurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (decode_format << csid_reg->cmn_reg->fmt_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << 1) | 1; + + val |= (1 << pxl_reg->pix_store_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + camera_hw_version = 0; + } + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + + if (path_data->is_valid_vc1_dt1 && + camera_hw_version == CAM_CPAS_TITAN_480_V100) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_multi_vcdt_cfg0_addr); + val |= ((path_data->vc1 << 2) | + (path_data->dt1 << 7) | 1); + } + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg1_addr); + + /* select the post irq sub sample strobe for time stamp capture */ + val |= CSID_TIMESTAMP_STB_POST_IRQ; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg1_addr); + + if (path_data->crop_enable) { + val = (((path_data->end_pixel & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_pixel & 0xFFFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_hcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Horizontal crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + val = (((path_data->end_line & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_line & 0xFFFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_vcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + /* Enable generating early eof strobe based on crop config */ + if (!(csid_hw->csid_debug & CSID_DEBUG_DISABLE_EARLY_EOF)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + val |= (1 << pxl_reg->early_eof_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + } + } + + /* set frame drop pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_frm_drop_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_frm_drop_pattern_addr); + /* set irq sub sample pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_subsample_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_subsample_pattern_addr); + /* set pxl drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_pix_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_pix_drop_period_addr); + /* set line drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_line_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_line_drop_period_addr); + + + /* Enable the Pxl path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) + val |= csid_reg->cmn_reg->format_measure_en_val; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + /* Enable Error Detection */ + if (pxl_reg->overflow_ctrl_en) { + val = pxl_reg->overflow_ctrl_en; + /* Overflow ctrl mode: 2 -> Detect overflow */ + val |= 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_err_recovery_cfg0_addr); + } + + /* Enable the HBI/VBI counter */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + val |= csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + } + + /* configure the rx packet capture based on csid debug set */ + val = 0; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + CAM_DBG(CAM_ISP, "rx capture control value 0x%x", val); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_ife_csid_deinit_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t val; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; + bool is_ipp; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d %s Res type %d res_id:%d in wrong state %d", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", + res->res_type, res->res_id, res->res_state); + rc = -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s %d is not supported on HW", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id); + rc = -EINVAL; + goto end; + } + + /* Disable Error Recovery */ + if (pxl_reg->overflow_ctrl_en) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_err_recovery_cfg0_addr); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + if (val & csid_reg->cmn_reg->format_measure_en_val) { + val &= ~csid_reg->cmn_reg->format_measure_en_val; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + /* Disable the HBI/VBI counter */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + val &= ~csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + } + +end: + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_ife_csid_enable_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; + bool is_ipp; + uint32_t val = 0; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d %s path res type:%d res_id:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s %d not supported on HW", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enable %s path", (is_ipp) ? "IPP" : "PPP"); + + /* Set master or slave path */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) + /*Set halt mode as master */ + val = CSID_HALT_MODE_MASTER << 2; + else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + /*Set halt mode as slave and set master idx */ + val = path_data->master_idx << 4 | CSID_HALT_MODE_SLAVE << 2; + else + /* Default is internal halt mode */ + val = 0; + + /* + * Resume at frame boundary if Master or No Sync. + * Slave will get resume command from Master. + */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + CAM_DBG(CAM_ISP, "CSID:%d %s Ctrl val: 0x%x", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", val); + + /* Enable the required pxl path interrupts */ + val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + + if (pxl_reg->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + + if (pxl_reg->overflow_ctrl_en) + val |= CSID_PATH_OVERFLOW_RECOVERY; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) + val |= CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + CAM_DBG(CAM_ISP, "Enable %s IRQ mask 0x%x", + (is_ipp) ? "IPP" : "PPP", val); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_ife_csid_disable_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_ife_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t val = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg; + bool is_ipp; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, res->res_state); + return rc; + } + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_DBG(CAM_ISP, "CSID:%d %s path Res:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id, res->res_state); + return -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s %d is not supported on HW", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id); + return -EINVAL; + } + + if (stop_cmd != CAM_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, "CSID:%d %s path un supported stop command:%d", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d %s path", + csid_hw->hw_intf->hw_idx, res->res_id, + (is_ipp) ? "IPP" : "PPP"); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { + /* configure Halt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + return rc; +} + +static int cam_ife_csid_init_config_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t path_format = 0, plain_fmt = 0, val = 0, id; + uint32_t format_measure_addr; + uint32_t camera_hw_version; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + id = res->res_id; + if (!csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d RDI:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, id); + return -EINVAL; + } + + rc = cam_ife_csid_get_format_rdi(path_data->in_format, + path_data->out_format, &path_format, &plain_fmt); + if (rc) + return rc; + + /* if path decode format is payload only then RDI crop is not applied */ + if (path_format == 0xF) + path_data->crop_enable = 0; + + /* + * RDI path config and enable the time stamp capture + * Enable the measurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (path_format << csid_reg->cmn_reg->fmt_shift_val) | + (plain_fmt << csid_reg->cmn_reg->plain_fmt_shit_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << 2) | 3; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + camera_hw_version = 0; + } + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + + if (path_data->is_valid_vc1_dt1 && + camera_hw_version == CAM_CPAS_TITAN_480_V100) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_multi_vcdt_cfg0_addr); + val |= ((path_data->vc1 << 2) | + (path_data->dt1 << 7) | 1); + } + + /* select the post irq sub sample strobe for time stamp capture */ + cam_io_w_mb(CSID_TIMESTAMP_STB_POST_IRQ, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr); + + if (path_data->crop_enable) { + val = (((path_data->end_pixel & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_pixel & 0xFFFF)); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_hcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Horizontal crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + val = (((path_data->end_line & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_line & 0xFFFF)); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_vcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + } + + /* Enable Error Detection */ + if (csid_reg->rdi_reg[id]->overflow_ctrl_en) { + val = csid_reg->rdi_reg[id]->overflow_ctrl_en; + /* Overflow ctrl mode: 2 -> Detect overflow */ + val |= 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_err_recovery_cfg0_addr); + } + + /* set frame drop pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_frm_drop_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_frm_drop_pattern_addr); + /* set IRQ sum sabmple */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_subsample_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_subsample_pattern_addr); + + /* set pixel drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_period_addr); + /* set line drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_line_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_line_drop_period_addr); + + /* Configure the halt mode */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + /* Enable the RPP path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) + val |= csid_reg->cmn_reg->format_measure_en_val; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + format_measure_addr = + csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg0_addr; + + /* Enable the HBI/VBI counter */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val |= csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + format_measure_addr); + } + + /* configure the rx packet capture based on csid debug set */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_ife_csid_deinit_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t id, val, format_measure_addr; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if (res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3 || + res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW || + !csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + /* Disable Error Recovery */ + if (csid_reg->rdi_reg[id]->overflow_ctrl_en) { + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_err_recovery_cfg0_addr); + } + + format_measure_addr = + csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg0_addr; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + val &= ~csid_reg->cmn_reg->format_measure_en_val; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + /* Disable the HBI/VBI counter */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val &= ~csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + format_measure_addr); + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_ife_csid_enable_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t id, val; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3 || + !csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, + "CSID:%d invalid res type:%d res_id:%d state%d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + /*resume at frame boundary */ + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + /* Enable the required RDI interrupts */ + val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + + if (csid_reg->rdi_reg[id]->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + + if (csid_reg->rdi_reg[id]->overflow_ctrl_en) + val |= CSID_PATH_OVERFLOW_RECOVERY; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) + val |= CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + + +static int cam_ife_csid_disable_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_ife_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t id, val = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if ((res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3) || + (!csid_reg->rdi_reg[res->res_id])) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, res->res_state); + return rc; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d Invalid res_state%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + if (stop_cmd != CAM_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, "CSID:%d un supported stop command:%d", + csid_hw->hw_intf->hw_idx, stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + + /* Halt the RDI path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + return rc; +} + +static int cam_ife_csid_poll_stop_status( + struct cam_ife_csid_hw *csid_hw, + uint32_t res_mask) +{ + int rc = 0; + uint32_t csid_status_addr = 0, val = 0, res_id = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + for (; res_id < CAM_IFE_PIX_PATH_RES_MAX; res_id++, res_mask >>= 1) { + if ((res_mask & 0x1) == 0) + continue; + val = 0; + + if (res_id == CAM_IFE_PIX_PATH_RES_IPP) { + csid_status_addr = + csid_reg->ipp_reg->csid_pxl_status_addr; + } else if (res_id == CAM_IFE_PIX_PATH_RES_PPP) { + csid_status_addr = + csid_reg->ppp_reg->csid_pxl_status_addr; + } else { + csid_status_addr = + csid_reg->rdi_reg[res_id]->csid_rdi_status_addr; + } + + CAM_DBG(CAM_ISP, "start polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_status_addr, val, (val & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, + CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d res:%d halt failed rc %d", + csid_hw->hw_intf->hw_idx, res_id, rc); + rc = -ETIMEDOUT; + break; + } + CAM_DBG(CAM_ISP, "End polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + } + + return rc; +} + +static int cam_ife_csid_get_hbi_vbi( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + uint32_t hbi, vbi; + const struct cam_ife_csid_reg_offset *csid_reg; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH || + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res_type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid dev state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_format_measure2_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_format_measure2_addr); + } else { + rdi_reg = csid_reg->rdi_reg[res->res_id]; + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_format_measure2_addr); + } + + CAM_INFO_RATE_LIMIT(CAM_ISP, + "Device %s index %u Resource %u HBI: 0x%x VBI: 0x%x", + soc_info->dev_name, soc_info->index, + res->res_id, hbi, vbi); + + return 0; +} + + +static int cam_ife_csid_get_time_stamp( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_csid_get_time_stamp_args *time_stamp; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg; + struct timespec64 ts; + uint32_t time_32, id; + + time_stamp = (struct cam_csid_get_time_stamp_args *)cmd_args; + res = time_stamp->node_res; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH || + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res_type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid dev state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_timestamp_curr0_sof_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_timestamp_curr0_sof_addr); + } else { + id = res->res_id; + rdi_reg = csid_reg->rdi_reg[id]; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_timestamp_curr0_sof_addr); + } + + time_stamp->time_stamp_val |= (uint64_t) time_32; + time_stamp->time_stamp_val = mul_u64_u32_div( + time_stamp->time_stamp_val, + CAM_IFE_CSID_QTIMER_MUL_FACTOR, + CAM_IFE_CSID_QTIMER_DIV_FACTOR); + + get_monotonic_boottime64(&ts); + time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + + return 0; +} + +static int cam_ife_csid_set_csid_debug(struct cam_ife_csid_hw *csid_hw, + void *cmd_args) +{ + uint32_t *csid_debug; + + csid_debug = (uint32_t *) cmd_args; + csid_hw->csid_debug = *csid_debug; + CAM_DBG(CAM_ISP, "CSID:%d set csid debug value:%d", + csid_hw->hw_intf->hw_idx, csid_hw->csid_debug); + + return 0; +} + +static int cam_ife_csid_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw_caps *hw_caps; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + const struct cam_ife_csid_reg_offset *csid_reg; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + csid_reg = csid_hw->csid_info->csid_reg; + hw_caps = (struct cam_ife_csid_hw_caps *) get_hw_cap_args; + + hw_caps->num_rdis = csid_reg->cmn_reg->num_rdis; + hw_caps->num_pix = csid_reg->cmn_reg->num_pix; + hw_caps->num_ppp = csid_reg->cmn_reg->num_ppp; + hw_caps->major_version = csid_reg->cmn_reg->major_version; + hw_caps->minor_version = csid_reg->cmn_reg->minor_version; + hw_caps->version_incr = csid_reg->cmn_reg->version_incr; + + CAM_DBG(CAM_ISP, + "CSID:%d No rdis:%d, no pix:%d, major:%d minor:%d ver :%d", + csid_hw->hw_intf->hw_idx, hw_caps->num_rdis, + hw_caps->num_pix, hw_caps->major_version, + hw_caps->minor_version, hw_caps->version_incr); + + return rc; +} + +static int cam_ife_csid_reset(void *hw_priv, + void *reset_args, uint32_t arg_size) +{ + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_csid_reset_cfg_args *reset; + int rc = 0; + + if (!hw_priv || !reset_args || (arg_size != + sizeof(struct cam_csid_reset_cfg_args))) { + CAM_ERR(CAM_ISP, "CSID:Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + reset = (struct cam_csid_reset_cfg_args *)reset_args; + + switch (reset->reset_type) { + case CAM_IFE_CSID_RESET_GLOBAL: + rc = cam_ife_csid_global_reset(csid_hw); + break; + case CAM_IFE_CSID_RESET_PATH: + rc = cam_ife_csid_path_reset(csid_hw, reset); + break; + default: + CAM_ERR(CAM_ISP, "CSID:Invalid reset type :%d", + reset->reset_type); + rc = -EINVAL; + break; + } + + return rc; +} + +static int cam_ife_csid_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_csid_hw_reserve_resource_args *reserv; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_csid_hw_reserve_resource_args))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + reserv = (struct cam_csid_hw_reserve_resource_args *)reserve_args; + + CAM_DBG(CAM_ISP, "res_type %d, CSID: %u", + reserv->res_type, csid_hw->hw_intf->hw_idx); + + mutex_lock(&csid_hw->hw_info->hw_mutex); + switch (reserv->res_type) { + case CAM_ISP_RESOURCE_CID: + rc = cam_ife_csid_cid_reserve(csid_hw, reserv); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + rc = cam_ife_csid_path_reserve(csid_hw, reserv); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type :%d", + csid_hw->hw_intf->hw_idx, reserv->res_type); + rc = -EINVAL; + break; + } + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_ife_csid_release(void *hw_priv, + void *release_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + struct cam_ife_csid_cid_data *cid_data; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + res = (struct cam_isp_resource_node *)release_args; + + mutex_lock(&csid_hw->hw_info->hw_mutex); + if ((res->res_type == CAM_ISP_RESOURCE_CID && + res->res_id >= CAM_IFE_CSID_CID_MAX) || + (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + if ((res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE) || + (res->res_state >= CAM_ISP_RESOURCE_STATE_STREAMING)) { + CAM_WARN(CAM_ISP, + "CSID:%d res type:%d Res %d in state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, + res->res_state); + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d res type :%d Resource id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + cid_data = (struct cam_ife_csid_cid_data *) res->res_priv; + if (cid_data->cnt) + cid_data->cnt--; + + if (!cid_data->cnt) + res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + if (csid_hw->csi2_reserve_cnt) + csid_hw->csi2_reserve_cnt--; + + if (!csid_hw->csi2_reserve_cnt) + memset(&csid_hw->csi2_rx_cfg, 0, + sizeof(struct cam_ife_csid_csi2_rx_cfg)); + + CAM_DBG(CAM_ISP, "CSID:%d res id :%d cnt:%d reserv cnt:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, cid_data->cnt, csid_hw->csi2_reserve_cnt); + + break; + case CAM_ISP_RESOURCE_PIX_PATH: + res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + break; + } + +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_ife_csid_reset_retain_sw_reg( + struct cam_ife_csid_hw *csid_hw) +{ + int rc = 0; + uint32_t status; + const struct cam_ife_csid_reg_offset *csid_reg = + csid_hw->csid_info->csid_reg; + struct cam_hw_soc_info *soc_info; + + soc_info = &csid_hw->hw_info->soc_info; + /* clear the top interrupt first */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + } else { + CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", + csid_hw->hw_intf->hw_idx, rc); + rc = 0; + } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + return rc; +} + +static int cam_ife_csid_init_hw(void *hw_priv, + void *init_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; + + if (!hw_priv || !init_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + res = (struct cam_isp_resource_node *)init_args; + csid_reg = csid_hw->csid_info->csid_reg; + + mutex_lock(&csid_hw->hw_info->hw_mutex); + if ((res->res_type == CAM_ISP_RESOURCE_CID && + res->res_id >= CAM_IFE_CSID_CID_MAX) || + (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res tpe:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + if ((res->res_type == CAM_ISP_RESOURCE_PIX_PATH) && + (res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED)) { + CAM_ERR(CAM_ISP, + "CSID:%d res type:%d res_id:%dInvalid state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d res type :%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + /* Initialize the csid hardware */ + rc = cam_ife_csid_enable_hw(csid_hw); + if (rc) + goto end; + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + rc = cam_ife_csid_enable_csi2(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + rc = cam_ife_csid_init_config_pxl_path(csid_hw, res); + else + rc = cam_ife_csid_init_config_rdi_path(csid_hw, res); + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type state %d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + + rc = cam_ife_csid_reset_retain_sw_reg(csid_hw); + if (rc < 0) + CAM_ERR(CAM_ISP, "CSID: Failed in SW reset"); + + if (rc) + cam_ife_csid_disable_hw(csid_hw); + + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_ife_csid_deinit_hw(void *hw_priv, + void *deinit_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + + if (!hw_priv || !deinit_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID:Invalid arguments"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enter"); + res = (struct cam_isp_resource_node *)deinit_args; + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + + mutex_lock(&csid_hw->hw_info->hw_mutex); + if (res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in De-init state", + csid_hw->hw_intf->hw_idx, + res->res_id); + goto end; + } + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + CAM_DBG(CAM_ISP, "De-Init ife_csid"); + rc = cam_ife_csid_disable_csi2(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + CAM_DBG(CAM_ISP, "De-Init Pix Path: %d\n", res->res_id); + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + rc = cam_ife_csid_deinit_pxl_path(csid_hw, res); + else + rc = cam_ife_csid_deinit_rdi_path(csid_hw, res); + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid Res type %d", + csid_hw->hw_intf->hw_idx, + res->res_type); + goto end; + } + + /* Disable CSID HW */ + CAM_DBG(CAM_ISP, "Disabling CSID Hw\n"); + cam_ife_csid_disable_hw(csid_hw); + CAM_DBG(CAM_ISP, "%s: Exit\n", __func__); + +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_ife_csid_start(void *hw_priv, void *start_args, + uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + res = (struct cam_isp_resource_node *)start_args; + csid_reg = csid_hw->csid_info->csid_reg; + + if ((res->res_type == CAM_ISP_RESOURCE_CID && + res->res_id >= CAM_IFE_CSID_CID_MAX) || + (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX)) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res tpe:%d res id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + /* Reset sof irq debug fields */ + csid_hw->sof_irq_triggered = false; + csid_hw->irq_debug_cnt = 0; + + CAM_DBG(CAM_ISP, "CSID:%d res_type :%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) + rc = cam_ife_csid_tpg_start(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + rc = cam_ife_csid_enable_pxl_path(csid_hw, res); + else + rc = cam_ife_csid_enable_rdi_path(csid_hw, res); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } +end: + return rc; +} + +static int cam_ife_csid_stop(void *hw_priv, + void *stop_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + struct cam_csid_hw_stop_args *csid_stop; + uint32_t i; + uint32_t res_mask = 0; + + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_csid_hw_stop_args))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + csid_stop = (struct cam_csid_hw_stop_args *) stop_args; + + if (!csid_stop->num_res) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + CAM_DBG(CAM_ISP, "CSID:%d num_res %d", + csid_hw->hw_intf->hw_idx, + csid_stop->num_res); + + /* Stop the resource first */ + for (i = 0; i < csid_stop->num_res; i++) { + res = csid_stop->node_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) + rc = cam_ife_csid_tpg_stop(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + res_mask |= (1 << res->res_id); + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + rc = cam_ife_csid_disable_pxl_path(csid_hw, + res, csid_stop->stop_cmd); + else + rc = cam_ife_csid_disable_rdi_path(csid_hw, + res, csid_stop->stop_cmd); + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + } + + if (res_mask) + rc = cam_ife_csid_poll_stop_status(csid_hw, res_mask); + + for (i = 0; i < csid_stop->num_res; i++) { + res = csid_stop->node_res[i]; + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + } + + CAM_DBG(CAM_ISP, "%s: Exit\n", __func__); + + return rc; + +} + +static int cam_ife_csid_read(void *hw_priv, + void *read_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "CSID: un supported"); + + return -EINVAL; +} + +static int cam_ife_csid_write(void *hw_priv, + void *write_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "CSID: un supported"); + return -EINVAL; +} + +static int cam_ife_csid_sof_irq_debug( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + int i = 0; + uint32_t val = 0; + bool sof_irq_enable = false; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (*((uint32_t *)cmd_args) == 1) + sof_irq_enable = true; + + if (csid_hw->hw_info->hw_state == + CAM_HW_STATE_POWER_DOWN) { + CAM_WARN(CAM_ISP, + "CSID powered down unable to %s sof irq", + (sof_irq_enable == true) ? "enable" : "disable"); + return 0; + } + + if (csid_reg->ipp_reg) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + val = 0; + } + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + val = 0; + } + } + + if (sof_irq_enable) { + csid_hw->csid_debug |= CSID_DEBUG_ENABLE_SOF_IRQ; + csid_hw->sof_irq_triggered = true; + } else { + csid_hw->csid_debug &= ~CSID_DEBUG_ENABLE_SOF_IRQ; + csid_hw->sof_irq_triggered = false; + } + + CAM_INFO(CAM_ISP, "SOF freeze: CSID SOF irq %s", + (sof_irq_enable == true) ? "enabled" : "disabled"); + + return 0; +} + +static int cam_ife_csid_set_csid_clock( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_ife_csid_clock_update_args *clk_update = NULL; + + if (!csid_hw) + return -EINVAL; + + clk_update = + (struct cam_ife_csid_clock_update_args *)cmd_args; + + csid_hw->clk_rate = clk_update->clk_rate; + CAM_INFO(CAM_ISP, "CSID clock rate %llu", csid_hw->clk_rate); + + return 0; +} + +static int cam_ife_csid_process_cmd(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res = NULL; + + if (!hw_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + + switch (cmd_type) { + case CAM_IFE_CSID_CMD_GET_TIME_STAMP: + rc = cam_ife_csid_get_time_stamp(csid_hw, cmd_args); + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + res = ((struct cam_csid_get_time_stamp_args *) + cmd_args)->node_res; + cam_ife_csid_get_hbi_vbi(csid_hw, res); + } + break; + case CAM_IFE_CSID_SET_CSID_DEBUG: + rc = cam_ife_csid_set_csid_debug(csid_hw, cmd_args); + break; + case CAM_IFE_CSID_SOF_IRQ_DEBUG: + rc = cam_ife_csid_sof_irq_debug(csid_hw, cmd_args); + break; + case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: + rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", + csid_hw->hw_intf->hw_idx, cmd_type); + rc = -EINVAL; + break; + } + + return rc; + +} + +irqreturn_t cam_ife_csid_irq(int irq_num, void *data) +{ + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; + uint32_t irq_status_rdi[4] = {0, 0, 0, 0}; + uint32_t val, irq_status_ppp = 0; + bool fatal_err_detected = false; + uint32_t sof_irq_debug_en = 0; + unsigned long flags; + + csid_hw = (struct cam_ife_csid_hw *)data; + + CAM_DBG(CAM_ISP, "CSID %d IRQ Handling", csid_hw->hw_intf->hw_idx); + + if (!data) { + CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); + return IRQ_HANDLED; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + csi2_reg = csid_reg->csi2_reg; + + /* read */ + irq_status_top = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr); + + irq_status_rx = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_status_addr); + + if (csid_reg->cmn_reg->num_pix) + irq_status_ipp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_status_addr); + + if (csid_reg->cmn_reg->num_ppp) + irq_status_ppp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_status_addr); + + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + irq_status_rdi[i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); + + /* clear */ + cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(irq_status_ipp, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(irq_status_ppp, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + cam_io_w_mb(irq_status_rdi[i], soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); + CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); + CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); + CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); + CAM_DBG(CAM_ISP, "irq_status_rdi0= 0x%x", irq_status_rdi[0]); + CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]); + CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]); + + if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "csi rx reset complete"); + complete(&csid_hw->csid_csi2_complete); + } + + spin_lock_irqsave(&csid_hw->lock_state, flags); + if (csid_hw->device_enabled == 1) { + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_EOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_SOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d ERROR_STREAM_UNDERFLOW", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + } + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + + if (csid_hw->error_irq_count > + CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT) { + fatal_err_detected = true; + csid_hw->error_irq_count = 0; + } + + if (fatal_err_detected) + cam_ife_csid_halt_csi2(csid_hw); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + } + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) { + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + } + + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) && + (irq_status_rx & CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d LONG_PKT_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_0_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d long packet VC :%d DT:%d WC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_1_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d long packet ECC :%d", + csid_hw->hw_intf->hw_idx, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_ftr_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d long pkt cal CRC:%d expected CRC:%d", + csid_hw->hw_intf->hw_idx, (val >> 16), (val & 0xFFFF)); + } + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) && + (irq_status_rx & CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d SHORT_PKT_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_short_pkt_0_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d short pkt VC :%d DT:%d LC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_short_pkt_1_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short packet ECC :%d", + csid_hw->hw_intf->hw_idx, val); + } + + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) && + (irq_status_rx & CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PKT_HDR_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_cphy_pkt_hdr_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d cphy packet VC :%d DT:%d WC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + } + + /*read the IPP errors */ + if (csid_reg->cmn_reg->num_pix) { + /* IPP reset done bit */ + if (irq_status_ipp & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID IPP reset complete"); + complete(&csid_hw->csid_ipp_complete); + } + + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP SOF received", + csid_hw->hw_intf->hw_idx); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP CCIF violation", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ipp & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP Overflow due to back pressure", + csid_hw->hw_intf->hw_idx); + + if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop IPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_ctrl_addr); + } + } + + /*read PPP errors */ + if (csid_reg->cmn_reg->num_ppp) { + /* PPP reset done bit */ + if (irq_status_ppp & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID PPP reset complete"); + complete(&csid_hw->csid_ppp_complete); + } + + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP SOF received", + csid_hw->hw_intf->hw_idx); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ppp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP CCIF violation", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ppp & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP Overflow due to back pressure", + csid_hw->hw_intf->hw_idx); + + if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop PPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_ctrl_addr); + } + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + if (irq_status_rdi[i] & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); + complete(&csid_hw->csid_rdin_complete[i]); + } + + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d SOF received", i); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d EOF received", i); + + if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI :%d CCIF violation", i); + + if ((irq_status_rdi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI :%d Overflow due to back pressure", + i); + + if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RDI fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop RDI path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_ctrl_addr); + } + } + + if (csid_hw->irq_debug_cnt >= CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX) { + cam_ife_csid_sof_irq_debug(csid_hw, &sof_irq_debug_en); + csid_hw->irq_debug_cnt = 0; + } + + CAM_DBG(CAM_ISP, "IRQ Handling exit"); + return IRQ_HANDLED; +} + +int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, + uint32_t csid_idx) +{ + int rc = -EINVAL; + uint32_t i; + uint32_t num_paths; + struct cam_ife_csid_path_cfg *path_data; + struct cam_ife_csid_cid_data *cid_data; + struct cam_hw_info *csid_hw_info; + struct cam_ife_csid_hw *ife_csid_hw = NULL; + + if (csid_idx >= CAM_IFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid csid index:%d", csid_idx); + return rc; + } + + csid_hw_info = (struct cam_hw_info *) csid_hw_intf->hw_priv; + ife_csid_hw = (struct cam_ife_csid_hw *) csid_hw_info->core_info; + + ife_csid_hw->hw_intf = csid_hw_intf; + ife_csid_hw->hw_info = csid_hw_info; + + CAM_DBG(CAM_ISP, "type %d index %d", + ife_csid_hw->hw_intf->hw_type, csid_idx); + + + ife_csid_hw->device_enabled = 0; + ife_csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&ife_csid_hw->hw_info->hw_mutex); + spin_lock_init(&ife_csid_hw->hw_info->hw_lock); + spin_lock_init(&ife_csid_hw->lock_state); + init_completion(&ife_csid_hw->hw_info->hw_complete); + + init_completion(&ife_csid_hw->csid_top_complete); + init_completion(&ife_csid_hw->csid_csi2_complete); + init_completion(&ife_csid_hw->csid_ipp_complete); + init_completion(&ife_csid_hw->csid_ppp_complete); + for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) + init_completion(&ife_csid_hw->csid_rdin_complete[i]); + + + rc = cam_ife_csid_init_soc_resources(&ife_csid_hw->hw_info->soc_info, + cam_ife_csid_irq, ife_csid_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d Failed to init_soc", csid_idx); + goto err; + } + + ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps; + ife_csid_hw->hw_intf->hw_ops.init = cam_ife_csid_init_hw; + ife_csid_hw->hw_intf->hw_ops.deinit = cam_ife_csid_deinit_hw; + ife_csid_hw->hw_intf->hw_ops.reset = cam_ife_csid_reset; + ife_csid_hw->hw_intf->hw_ops.reserve = cam_ife_csid_reserve; + ife_csid_hw->hw_intf->hw_ops.release = cam_ife_csid_release; + ife_csid_hw->hw_intf->hw_ops.start = cam_ife_csid_start; + ife_csid_hw->hw_intf->hw_ops.stop = cam_ife_csid_stop; + ife_csid_hw->hw_intf->hw_ops.read = cam_ife_csid_read; + ife_csid_hw->hw_intf->hw_ops.write = cam_ife_csid_write; + ife_csid_hw->hw_intf->hw_ops.process_cmd = cam_ife_csid_process_cmd; + + num_paths = ife_csid_hw->csid_info->csid_reg->cmn_reg->num_pix + + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + /* Initialize the CID resource */ + for (i = 0; i < num_paths; i++) { + ife_csid_hw->cid_res[i].res_type = CAM_ISP_RESOURCE_CID; + ife_csid_hw->cid_res[i].res_id = i; + ife_csid_hw->cid_res[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->cid_res[i].hw_intf = ife_csid_hw->hw_intf; + + cid_data = kzalloc(sizeof(struct cam_ife_csid_cid_data), + GFP_KERNEL); + if (!cid_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->cid_res[i].res_priv = cid_data; + } + + /* Initialize the IPP resources */ + if (ife_csid_hw->csid_info->csid_reg->cmn_reg->num_pix) { + ife_csid_hw->ipp_res.res_type = CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->ipp_res.res_id = CAM_IFE_PIX_PATH_RES_IPP; + ife_csid_hw->ipp_res.res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->ipp_res.hw_intf = ife_csid_hw->hw_intf; + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->ipp_res.res_priv = path_data; + } + + /* Initialize PPP resource */ + if (ife_csid_hw->csid_info->csid_reg->cmn_reg->num_ppp) { + ife_csid_hw->ppp_res.res_type = CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->ppp_res.res_id = CAM_IFE_PIX_PATH_RES_PPP; + ife_csid_hw->ppp_res.res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->ppp_res.hw_intf = ife_csid_hw->hw_intf; + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->ppp_res.res_priv = path_data; + } + + /* Initialize the RDI resource */ + for (i = 0; i < ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) { + /* res type is from RDI 0 to RDI3 */ + ife_csid_hw->rdi_res[i].res_type = + CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->rdi_res[i].res_id = i; + ife_csid_hw->rdi_res[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->rdi_res[i].hw_intf = ife_csid_hw->hw_intf; + + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->rdi_res[i].res_priv = path_data; + } + + ife_csid_hw->csid_debug = 0; + ife_csid_hw->error_irq_count = 0; + + return 0; +err: + if (rc) { + kfree(ife_csid_hw->ipp_res.res_priv); + kfree(ife_csid_hw->ppp_res.res_priv); + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) + kfree(ife_csid_hw->rdi_res[i].res_priv); + + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) + kfree(ife_csid_hw->cid_res[i].res_priv); + + } + + return rc; +} + + +int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw) +{ + int rc = -EINVAL; + uint32_t i; + + if (!ife_csid_hw) { + CAM_ERR(CAM_ISP, "Invalid param"); + return rc; + } + + /* release the privdate data memory from resources */ + kfree(ife_csid_hw->ipp_res.res_priv); + kfree(ife_csid_hw->ppp_res.res_priv); + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) { + kfree(ife_csid_hw->rdi_res[i].res_priv); + } + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) + kfree(ife_csid_hw->cid_res[i].res_priv); + + cam_ife_csid_deinit_soc_resources(&ife_csid_hw->hw_info->soc_info); + + return 0; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h new file mode 100644 index 000000000000..a3c54fed7c03 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -0,0 +1,513 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_HW_H_ +#define _CAM_IFE_CSID_HW_H_ + +#include "cam_hw.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_ife_csid_soc.h" + +#define CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED BIT(0) +#define CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED BIT(1) +#define CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED BIT(2) +#define CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED BIT(3) +#define CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED BIT(4) +#define CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED BIT(5) +#define CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED BIT(6) +#define CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED BIT(7) +#define CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED BIT(8) +#define CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED BIT(9) +#define CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED BIT(10) +#define CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION BIT(11) +#define CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION BIT(12) +#define CSID_CSI2_RX_ERROR_CPHY_PH_CRC BIT(13) +#define CSID_CSI2_RX_WARNING_ECC BIT(14) +#define CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW BIT(15) +#define CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW BIT(16) +#define CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW BIT(17) +#define CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW BIT(18) +#define CSID_CSI2_RX_ERROR_CRC BIT(19) +#define CSID_CSI2_RX_ERROR_ECC BIT(20) +#define CSID_CSI2_RX_ERROR_MMAPPED_VC_DT BIT(21) +#define CSID_CSI2_RX_ERROR_UNMAPPED_VC_DT BIT(22) +#define CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW BIT(23) +#define CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME BIT(24) +#define CSID_CSI2_RX_INFO_TG_DONE BIT(25) +#define CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW BIT(26) +#define CSID_CSI2_RX_INFO_RST_DONE BIT(27) + +#define CSID_PATH_INFO_RST_DONE BIT(1) +#define CSID_PATH_ERROR_FIFO_OVERFLOW BIT(2) +#define CSID_PATH_INFO_SUBSAMPLED_EOF BIT(3) +#define CSID_PATH_INFO_SUBSAMPLED_SOF BIT(4) +#define CSID_PATH_INFO_FRAME_DROP_EOF BIT(5) +#define CSID_PATH_INFO_FRAME_DROP_EOL BIT(6) +#define CSID_PATH_INFO_FRAME_DROP_SOL BIT(7) +#define CSID_PATH_INFO_FRAME_DROP_SOF BIT(8) +#define CSID_PATH_INFO_INPUT_EOF BIT(9) +#define CSID_PATH_INFO_INPUT_EOL BIT(10) +#define CSID_PATH_INFO_INPUT_SOL BIT(11) +#define CSID_PATH_INFO_INPUT_SOF BIT(12) +#define CSID_PATH_ERROR_PIX_COUNT BIT(13) +#define CSID_PATH_ERROR_LINE_COUNT BIT(14) +#define CSID_PATH_ERROR_CCIF_VIOLATION BIT(15) +#define CSID_PATH_OVERFLOW_RECOVERY BIT(17) + +/* + * Debug values enable the corresponding interrupts and debug logs provide + * necessary information + */ +#define CSID_DEBUG_ENABLE_SOF_IRQ BIT(0) +#define CSID_DEBUG_ENABLE_EOF_IRQ BIT(1) +#define CSID_DEBUG_ENABLE_SOT_IRQ BIT(2) +#define CSID_DEBUG_ENABLE_EOT_IRQ BIT(3) +#define CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE BIT(4) +#define CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE BIT(5) +#define CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE BIT(6) +#define CSID_DEBUG_ENABLE_HBI_VBI_INFO BIT(7) +#define CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) + +/* enum cam_csid_path_halt_mode select the path halt mode control */ +enum cam_csid_path_halt_mode { + CSID_HALT_MODE_INTERNAL, + CSID_HALT_MODE_GLOBAL, + CSID_HALT_MODE_MASTER, + CSID_HALT_MODE_SLAVE, +}; + +/** + *enum cam_csid_path_timestamp_stb_sel - select the sof/eof strobes used to + * capture the timestamp + */ +enum cam_csid_path_timestamp_stb_sel { + CSID_TIMESTAMP_STB_PRE_HALT, + CSID_TIMESTAMP_STB_POST_HALT, + CSID_TIMESTAMP_STB_POST_IRQ, + CSID_TIMESTAMP_STB_MAX, +}; + +struct cam_ife_csid_pxl_reg_offset { + /* Pxl path register offsets*/ + uint32_t csid_pxl_irq_status_addr; + uint32_t csid_pxl_irq_mask_addr; + uint32_t csid_pxl_irq_clear_addr; + uint32_t csid_pxl_irq_set_addr; + + uint32_t csid_pxl_cfg0_addr; + uint32_t csid_pxl_cfg1_addr; + uint32_t csid_pxl_ctrl_addr; + uint32_t csid_pxl_frm_drop_pattern_addr; + uint32_t csid_pxl_frm_drop_period_addr; + uint32_t csid_pxl_irq_subsample_pattern_addr; + uint32_t csid_pxl_irq_subsample_period_addr; + uint32_t csid_pxl_hcrop_addr; + uint32_t csid_pxl_vcrop_addr; + uint32_t csid_pxl_pix_drop_pattern_addr; + uint32_t csid_pxl_pix_drop_period_addr; + uint32_t csid_pxl_line_drop_pattern_addr; + uint32_t csid_pxl_line_drop_period_addr; + uint32_t csid_pxl_rst_strobes_addr; + uint32_t csid_pxl_status_addr; + uint32_t csid_pxl_misr_val_addr; + uint32_t csid_pxl_format_measure_cfg0_addr; + uint32_t csid_pxl_format_measure_cfg1_addr; + uint32_t csid_pxl_format_measure0_addr; + uint32_t csid_pxl_format_measure1_addr; + uint32_t csid_pxl_format_measure2_addr; + uint32_t csid_pxl_timestamp_curr0_sof_addr; + uint32_t csid_pxl_timestamp_curr1_sof_addr; + uint32_t csid_pxl_timestamp_perv0_sof_addr; + uint32_t csid_pxl_timestamp_perv1_sof_addr; + uint32_t csid_pxl_timestamp_curr0_eof_addr; + uint32_t csid_pxl_timestamp_curr1_eof_addr; + uint32_t csid_pxl_timestamp_perv0_eof_addr; + uint32_t csid_pxl_timestamp_perv1_eof_addr; + uint32_t csid_pxl_err_recovery_cfg0_addr; + uint32_t csid_pxl_err_recovery_cfg1_addr; + uint32_t csid_pxl_err_recovery_cfg2_addr; + uint32_t csid_pxl_multi_vcdt_cfg0_addr; + + /* configuration */ + uint32_t pix_store_en_shift_val; + uint32_t early_eof_en_shift_val; + uint32_t quad_cfa_bin_en_shift_val; + uint32_t ccif_violation_en; + uint32_t overflow_ctrl_en; +}; + +struct cam_ife_csid_rdi_reg_offset { + uint32_t csid_rdi_irq_status_addr; + uint32_t csid_rdi_irq_mask_addr; + uint32_t csid_rdi_irq_clear_addr; + uint32_t csid_rdi_irq_set_addr; + + /*RDI N register address */ + uint32_t csid_rdi_cfg0_addr; + uint32_t csid_rdi_cfg1_addr; + uint32_t csid_rdi_ctrl_addr; + uint32_t csid_rdi_frm_drop_pattern_addr; + uint32_t csid_rdi_frm_drop_period_addr; + uint32_t csid_rdi_irq_subsample_pattern_addr; + uint32_t csid_rdi_irq_subsample_period_addr; + uint32_t csid_rdi_rpp_hcrop_addr; + uint32_t csid_rdi_rpp_vcrop_addr; + uint32_t csid_rdi_rpp_pix_drop_pattern_addr; + uint32_t csid_rdi_rpp_pix_drop_period_addr; + uint32_t csid_rdi_rpp_line_drop_pattern_addr; + uint32_t csid_rdi_rpp_line_drop_period_addr; + uint32_t csid_rdi_yuv_chroma_conversion_addr; + uint32_t csid_rdi_rst_strobes_addr; + uint32_t csid_rdi_status_addr; + uint32_t csid_rdi_misr_val0_addr; + uint32_t csid_rdi_misr_val1_addr; + uint32_t csid_rdi_misr_val2_addr; + uint32_t csid_rdi_misr_val3_addr; + uint32_t csid_rdi_format_measure_cfg0_addr; + uint32_t csid_rdi_format_measure_cfg1_addr; + uint32_t csid_rdi_format_measure0_addr; + uint32_t csid_rdi_format_measure1_addr; + uint32_t csid_rdi_format_measure2_addr; + uint32_t csid_rdi_timestamp_curr0_sof_addr; + uint32_t csid_rdi_timestamp_curr1_sof_addr; + uint32_t csid_rdi_timestamp_prev0_sof_addr; + uint32_t csid_rdi_timestamp_prev1_sof_addr; + uint32_t csid_rdi_timestamp_curr0_eof_addr; + uint32_t csid_rdi_timestamp_curr1_eof_addr; + uint32_t csid_rdi_timestamp_prev0_eof_addr; + uint32_t csid_rdi_timestamp_prev1_eof_addr; + uint32_t csid_rdi_err_recovery_cfg0_addr; + uint32_t csid_rdi_err_recovery_cfg1_addr; + uint32_t csid_rdi_err_recovery_cfg2_addr; + uint32_t csid_rdi_multi_vcdt_cfg0_addr; + uint32_t csid_rdi_byte_cntr_ping_addr; + uint32_t csid_rdi_byte_cntr_pong_addr; + + /* configuration */ + uint32_t packing_format; + uint32_t ccif_violation_en; + uint32_t overflow_ctrl_en; +}; + +struct cam_ife_csid_csi2_rx_reg_offset { + uint32_t csid_csi2_rx_irq_status_addr; + uint32_t csid_csi2_rx_irq_mask_addr; + uint32_t csid_csi2_rx_irq_clear_addr; + uint32_t csid_csi2_rx_irq_set_addr; + uint32_t csid_csi2_rx_cfg0_addr; + uint32_t csid_csi2_rx_cfg1_addr; + uint32_t csid_csi2_rx_capture_ctrl_addr; + uint32_t csid_csi2_rx_rst_strobes_addr; + uint32_t csid_csi2_rx_de_scramble_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_cfg1_addr; + uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr; + uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr; + uint32_t csid_csi2_rx_captured_short_pkt_0_addr; + uint32_t csid_csi2_rx_captured_short_pkt_1_addr; + uint32_t csid_csi2_rx_captured_long_pkt_0_addr; + uint32_t csid_csi2_rx_captured_long_pkt_1_addr; + uint32_t csid_csi2_rx_captured_long_pkt_ftr_addr; + uint32_t csid_csi2_rx_captured_cphy_pkt_hdr_addr; + uint32_t csid_csi2_rx_lane0_misr_addr; + uint32_t csid_csi2_rx_lane1_misr_addr; + uint32_t csid_csi2_rx_lane2_misr_addr; + uint32_t csid_csi2_rx_lane3_misr_addr; + uint32_t csid_csi2_rx_total_pkts_rcvd_addr; + uint32_t csid_csi2_rx_stats_ecc_addr; + uint32_t csid_csi2_rx_total_crc_err_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg1_addr; + + /*configurations */ + uint32_t csi2_rst_srb_all; + uint32_t csi2_rst_done_shift_val; + uint32_t csi2_irq_mask_all; + uint32_t csi2_misr_enable_shift_val; + uint32_t csi2_vc_mode_shift_val; + uint32_t csi2_capture_long_pkt_en_shift; + uint32_t csi2_capture_short_pkt_en_shift; + uint32_t csi2_capture_cphy_pkt_en_shift; + uint32_t csi2_capture_long_pkt_dt_shift; + uint32_t csi2_capture_long_pkt_vc_shift; + uint32_t csi2_capture_short_pkt_vc_shift; + uint32_t csi2_capture_cphy_pkt_dt_shift; + uint32_t csi2_capture_cphy_pkt_vc_shift; + uint32_t csi2_rx_phy_num_mask; +}; + +struct cam_ife_csid_csi2_tpg_reg_offset { + uint32_t csid_tpg_ctrl_addr; + uint32_t csid_tpg_vc_cfg0_addr; + uint32_t csid_tpg_vc_cfg1_addr; + uint32_t csid_tpg_lfsr_seed_addr; + uint32_t csid_tpg_dt_n_cfg_0_addr; + uint32_t csid_tpg_dt_n_cfg_1_addr; + uint32_t csid_tpg_dt_n_cfg_2_addr; + uint32_t csid_tpg_color_bars_cfg_addr; + uint32_t csid_tpg_color_box_cfg_addr; + uint32_t csid_tpg_common_gen_cfg_addr; + uint32_t csid_tpg_cgen_n_cfg_addr; + uint32_t csid_tpg_cgen_n_x0_addr; + uint32_t csid_tpg_cgen_n_x1_addr; + uint32_t csid_tpg_cgen_n_x2_addr; + uint32_t csid_tpg_cgen_n_xy_addr; + uint32_t csid_tpg_cgen_n_y1_addr; + uint32_t csid_tpg_cgen_n_y2_addr; + + /*configurations */ + uint32_t tpg_dtn_cfg_offset; + uint32_t tpg_cgen_cfg_offset; + uint32_t tpg_cpas_ife_reg_offset; + +}; +struct cam_ife_csid_common_reg_offset { + /* MIPI CSID registers */ + uint32_t csid_hw_version_addr; + uint32_t csid_cfg0_addr; + uint32_t csid_ctrl_addr; + uint32_t csid_reset_addr; + uint32_t csid_rst_strobes_addr; + + uint32_t csid_test_bus_ctrl_addr; + uint32_t csid_top_irq_status_addr; + uint32_t csid_top_irq_mask_addr; + uint32_t csid_top_irq_clear_addr; + uint32_t csid_top_irq_set_addr; + uint32_t csid_irq_cmd_addr; + + /*configurations */ + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; + uint32_t num_rdis; + uint32_t num_pix; + uint32_t num_ppp; + uint32_t csid_reg_rst_stb; + uint32_t csid_rst_stb; + uint32_t csid_rst_stb_sw_all; + uint32_t path_rst_stb_all; + uint32_t path_rst_done_shift_val; + uint32_t path_en_shift_val; + uint32_t dt_id_shift_val; + uint32_t vc_shift_val; + uint32_t dt_shift_val; + uint32_t fmt_shift_val; + uint32_t plain_fmt_shit_val; + uint32_t crop_v_en_shift_val; + uint32_t crop_h_en_shift_val; + uint32_t crop_shift; + uint32_t ipp_irq_mask_all; + uint32_t rdi_irq_mask_all; + uint32_t ppp_irq_mask_all; + uint32_t measure_en_hbi_vbi_cnt_mask; + uint32_t format_measure_en_val; +}; + +/** + * struct cam_ife_csid_reg_offset- CSID instance register info + * + * @cmn_reg: csid common registers info + * @ipp_reg: ipp register offset information + * @ppp_reg: ppp register offset information + * @rdi_reg: rdi register offser information + * + */ +struct cam_ife_csid_reg_offset { + const struct cam_ife_csid_common_reg_offset *cmn_reg; + const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + const struct cam_ife_csid_pxl_reg_offset *ipp_reg; + const struct cam_ife_csid_pxl_reg_offset *ppp_reg; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg[CAM_IFE_CSID_RDI_MAX]; + const struct cam_ife_csid_csi2_tpg_reg_offset *tpg_reg; +}; + + +/** + * struct cam_ife_csid_hw_info- CSID HW info + * + * @csid_reg: csid register offsets + * @hw_dts_version: HW DTS version + * @csid_max_clk: maximim csid clock + * + */ +struct cam_ife_csid_hw_info { + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t hw_dts_version; + uint32_t csid_max_clk; + +}; + + + +/** + * struct cam_ife_csid_csi2_rx_cfg- csid csi2 rx configuration data + * @phy_sel: input resource type for sensor only + * @lane_type: lane type: c-phy or d-phy + * @lane_num : active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * + */ +struct cam_ife_csid_csi2_rx_cfg { + uint32_t phy_sel; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; +}; + +/** + * struct cam_ife_csid_tpg_cfg- csid tpg configuration data + * @width: width + * @height: height + * @test_pattern : pattern + * @in_format: decode format + * @usage_type: whether dual isp is required + * + */ +struct cam_ife_csid_tpg_cfg { + uint32_t width; + uint32_t height; + uint32_t test_pattern; + uint32_t in_format; + uint32_t usage_type; +}; + +/** + * struct cam_ife_csid_cid_data- cid configuration private data + * + * @vc: Virtual channel + * @dt: Data type + * @cnt: Cid resource reference count. + * @tpg_set: Tpg used for this cid resource + * @is_valid_vc1_dt1: Valid vc1 and dt1 + * + */ +struct cam_ife_csid_cid_data { + uint32_t vc; + uint32_t dt; + uint32_t vc1; + uint32_t dt1; + uint32_t cnt; + uint32_t tpg_set; + uint32_t is_valid_vc1_dt1; +}; + + +/** + * struct cam_ife_csid_path_cfg- csid path configuration details. It is stored + * as private data for IPP/ RDI paths + * @vc : Virtual channel number + * @dt : Data type number + * @cid cid number, it is same as DT_ID number in HW + * @in_format: input decode format + * @out_format: output format + * @crop_enable: crop is enable or disabled, if enabled + * then remaining parameters are valid. + * @start_pixel: start pixel + * @end_pixel: end_pixel + * @width: width + * @start_line: start line + * @end_line: end_line + * @height: heigth + * @sync_mode: Applicable for IPP/RDI path reservation + * Reserving the path for master IPP or slave IPP + * master (set value 1), Slave ( set value 2) + * for RDI, set mode to none + * @master_idx: For Slave reservation, Give master IFE instance Index. + * Slave will synchronize with master Start and stop operations + * @clk_rate Clock rate + * + */ +struct cam_ife_csid_path_cfg { + uint32_t vc; + uint32_t dt; + uint32_t vc1; + uint32_t dt1; + uint32_t is_valid_vc1_dt1; + uint32_t cid; + uint32_t in_format; + uint32_t out_format; + bool crop_enable; + uint32_t start_pixel; + uint32_t end_pixel; + uint32_t width; + uint32_t start_line; + uint32_t end_line; + uint32_t height; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t master_idx; + uint64_t clk_rate; +}; + +/** + * struct cam_ife_csid_hw- csid hw device resources data + * + * @hw_intf: contain the csid hw interface information + * @hw_info: csid hw device information + * @csid_info: csid hw specific information + * @res_type: CSID in resource type + * @csi2_rx_cfg: Csi2 rx decoder configuration for csid + * @tpg_cfg: TPG configuration + * @csi2_rx_reserve_cnt: CSI2 reservations count value + * @csi2_cfg_cnt: csi2 configuration count + * @tpg_start_cnt: tpg start count + * @ipp_res: image pixel path resource + * @ppp_res: phase pxl path resource + * @rdi_res: raw dump image path resources + * @cid_res: cid resources state + * @csid_top_reset_complete: csid top reset completion + * @csid_csi2_reset_complete: csi2 reset completion + * @csid_ipp_reset_complete: ipp reset completion + * @csid_ppp_complete: ppp reset completion + * @csid_rdin_reset_complete: rdi n completion + * @csid_debug: csid debug information to enable the SOT, EOT, + * SOF, EOF, measure etc in the csid hw + * @clk_rate Clock rate + * @sof_irq_triggered: Flag is set on receiving event to enable sof irq + * incase of SOF freeze. + * @irq_debug_cnt: Counter to track sof irq's when above flag is set. + * @error_irq_count Error IRQ count, if continuous error irq comes + * need to stop the CSID and mask interrupts. + * + */ +struct cam_ife_csid_hw { + struct cam_hw_intf *hw_intf; + struct cam_hw_info *hw_info; + struct cam_ife_csid_hw_info *csid_info; + uint32_t res_type; + struct cam_ife_csid_csi2_rx_cfg csi2_rx_cfg; + struct cam_ife_csid_tpg_cfg tpg_cfg; + uint32_t csi2_reserve_cnt; + uint32_t csi2_cfg_cnt; + uint32_t tpg_start_cnt; + struct cam_isp_resource_node ipp_res; + struct cam_isp_resource_node ppp_res; + struct cam_isp_resource_node rdi_res[CAM_IFE_CSID_RDI_MAX]; + struct cam_isp_resource_node cid_res[CAM_IFE_CSID_CID_MAX]; + struct completion csid_top_complete; + struct completion csid_csi2_complete; + struct completion csid_ipp_complete; + struct completion csid_ppp_complete; + struct completion csid_rdin_complete[CAM_IFE_CSID_RDI_MAX]; + uint64_t csid_debug; + uint64_t clk_rate; + bool sof_irq_triggered; + uint32_t irq_debug_cnt; + uint32_t error_irq_count; + uint32_t device_enabled; + spinlock_t lock_state; +}; + +int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, + uint32_t csid_idx); + +int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw); + +#endif /* _CAM_IFE_CSID_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c new file mode 100644 index 000000000000..05bf36899392 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "cam_ife_csid_core.h" +#include "cam_ife_csid_dev.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_ife_csid_hw_list[CAM_IFE_CSID_HW_NUM_MAX] = { + 0, 0, 0, 0}; + +static char csid_dev_name[8]; + +int cam_ife_csid_probe(struct platform_device *pdev) +{ + + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + struct cam_ife_csid_hw *csid_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_ife_csid_hw_info *csid_hw_data = NULL; + uint32_t csid_dev_idx; + int rc = 0; + + CAM_DBG(CAM_ISP, "probe called"); + + csid_hw_intf = kzalloc(sizeof(*csid_hw_intf), GFP_KERNEL); + if (!csid_hw_intf) { + rc = -ENOMEM; + goto err; + } + + csid_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!csid_hw_info) { + rc = -ENOMEM; + goto free_hw_intf; + } + + csid_dev = kzalloc(sizeof(struct cam_ife_csid_hw), GFP_KERNEL); + if (!csid_dev) { + rc = -ENOMEM; + goto free_hw_info; + } + + /* get ife csid hw index */ + of_property_read_u32(pdev->dev.of_node, "cell-index", &csid_dev_idx); + /* get ife csid hw information */ + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "No matching table for the IFE CSID HW!"); + rc = -EINVAL; + goto free_dev; + } + + memset(csid_dev_name, 0, sizeof(csid_dev_name)); + snprintf(csid_dev_name, sizeof(csid_dev_name), + "csid%1u", csid_dev_idx); + + csid_hw_intf->hw_idx = csid_dev_idx; + csid_hw_intf->hw_type = CAM_ISP_HW_TYPE_IFE_CSID; + csid_hw_intf->hw_priv = csid_hw_info; + + csid_hw_info->core_info = csid_dev; + csid_hw_info->soc_info.pdev = pdev; + csid_hw_info->soc_info.dev = &pdev->dev; + csid_hw_info->soc_info.dev_name = csid_dev_name; + csid_hw_info->soc_info.index = csid_dev_idx; + + csid_hw_data = (struct cam_ife_csid_hw_info *)match_dev->data; + /* need to setup the pdev before call the ife hw probe init */ + csid_dev->csid_info = csid_hw_data; + + rc = cam_ife_csid_hw_probe_init(csid_hw_intf, csid_dev_idx); + if (rc) + goto free_dev; + + platform_set_drvdata(pdev, csid_dev); + CAM_DBG(CAM_ISP, "CSID:%d probe successful", + csid_hw_intf->hw_idx); + + + if (csid_hw_intf->hw_idx < CAM_IFE_CSID_HW_NUM_MAX) + cam_ife_csid_hw_list[csid_hw_intf->hw_idx] = csid_hw_intf; + else + goto free_dev; + + return 0; + +free_dev: + kfree(csid_dev); +free_hw_info: + kfree(csid_hw_info); +free_hw_intf: + kfree(csid_hw_intf); +err: + return rc; +} + +int cam_ife_csid_remove(struct platform_device *pdev) +{ + struct cam_ife_csid_hw *csid_dev = NULL; + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + + csid_dev = (struct cam_ife_csid_hw *)platform_get_drvdata(pdev); + csid_hw_intf = csid_dev->hw_intf; + csid_hw_info = csid_dev->hw_info; + + CAM_DBG(CAM_ISP, "CSID:%d remove", + csid_dev->hw_intf->hw_idx); + + cam_ife_csid_hw_deinit(csid_dev); + + /*release the csid device memory */ + kfree(csid_dev); + kfree(csid_hw_info); + kfree(csid_hw_intf); + return 0; +} + +int cam_ife_csid_hw_init(struct cam_hw_intf **ife_csid_hw, + uint32_t hw_idx) +{ + int rc = 0; + + if (cam_ife_csid_hw_list[hw_idx]) { + *ife_csid_hw = cam_ife_csid_hw_list[hw_idx]; + } else { + *ife_csid_hw = NULL; + rc = -1; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h new file mode 100644 index 000000000000..1f8e4d05b74b --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_DEV_H_ +#define _CAM_IFE_CSID_DEV_H_ + +#include "cam_isp_hw.h" + +irqreturn_t cam_ife_csid_irq(int irq_num, void *data); + +int cam_ife_csid_probe(struct platform_device *pdev); +int cam_ife_csid_remove(struct platform_device *pdev); + +#endif /*_CAM_IFE_CSID_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c new file mode 100644 index 000000000000..0a80f1a51cf5 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_ife_csid_lite17x.h" +#include "cam_ife_csid_core.h" +#include "cam_ife_csid_dev.h" + +#define CAM_CSID_LITE_DRV_NAME "csid_lite" + +static struct cam_ife_csid_hw_info cam_ife_csid_lite_hw_info = { + .csid_reg = &cam_ife_csid_lite_17x_reg_offset, +}; + +static const struct of_device_id cam_ife_csid_lite_dt_match[] = { + { + .compatible = "qcom,csid-lite170", + .data = &cam_ife_csid_lite_hw_info, + }, + { + .compatible = "qcom,csid-lite175", + .data = &cam_ife_csid_lite_hw_info, + }, + { + .compatible = "qcom,csid-lite480", + .data = &cam_ife_csid_lite_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_ife_csid_lite_dt_match); + +static struct platform_driver cam_ife_csid_lite_driver = { + .probe = cam_ife_csid_probe, + .remove = cam_ife_csid_remove, + .driver = { + .name = CAM_CSID_LITE_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_ife_csid_lite_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ife_csid_lite_init_module(void) +{ + return platform_driver_register(&cam_ife_csid_lite_driver); +} + +static void __exit cam_ife_csid_lite_exit_module(void) +{ + platform_driver_unregister(&cam_ife_csid_lite_driver); +} + +module_init(cam_ife_csid_lite_init_module); +module_exit(cam_ife_csid_lite_exit_module); +MODULE_DESCRIPTION("CAM IFE_CSID_LITE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h new file mode 100644 index 000000000000..0573e30d151e --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h @@ -0,0 +1,315 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_LITE17X_H_ +#define _CAM_IFE_CSID_LITE17X_H_ +#include "cam_ife_csid_core.h" + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_0_reg_offset = { + + .csid_rdi_irq_status_addr = 0x30, + .csid_rdi_irq_mask_addr = 0x34, + .csid_rdi_irq_clear_addr = 0x38, + .csid_rdi_irq_set_addr = 0x3c, + .csid_rdi_cfg0_addr = 0x200, + .csid_rdi_cfg1_addr = 0x204, + .csid_rdi_ctrl_addr = 0x208, + .csid_rdi_frm_drop_pattern_addr = 0x20c, + .csid_rdi_frm_drop_period_addr = 0x210, + .csid_rdi_irq_subsample_pattern_addr = 0x214, + .csid_rdi_irq_subsample_period_addr = 0x218, + .csid_rdi_rpp_hcrop_addr = 0x21c, + .csid_rdi_rpp_vcrop_addr = 0x220, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x224, + .csid_rdi_rpp_pix_drop_period_addr = 0x228, + .csid_rdi_rpp_line_drop_pattern_addr = 0x22c, + .csid_rdi_rpp_line_drop_period_addr = 0x230, + .csid_rdi_rst_strobes_addr = 0x240, + .csid_rdi_status_addr = 0x250, + .csid_rdi_misr_val0_addr = 0x254, + .csid_rdi_misr_val1_addr = 0x258, + .csid_rdi_misr_val2_addr = 0x25c, + .csid_rdi_misr_val3_addr = 0x260, + .csid_rdi_format_measure_cfg0_addr = 0x270, + .csid_rdi_format_measure_cfg1_addr = 0x274, + .csid_rdi_format_measure0_addr = 0x278, + .csid_rdi_format_measure1_addr = 0x27c, + .csid_rdi_format_measure2_addr = 0x280, + .csid_rdi_timestamp_curr0_sof_addr = 0x290, + .csid_rdi_timestamp_curr1_sof_addr = 0x294, + .csid_rdi_timestamp_prev0_sof_addr = 0x298, + .csid_rdi_timestamp_prev1_sof_addr = 0x29c, + .csid_rdi_timestamp_curr0_eof_addr = 0x2a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x2a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x2a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x2ac, + .csid_rdi_byte_cntr_ping_addr = 0x2e0, + .csid_rdi_byte_cntr_pong_addr = 0x2e4, +}; + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_1_reg_offset = { + + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, +}; + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_2_reg_offset = { + + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_yuv_chroma_conversion_addr = 0x434, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, +}; + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_3_reg_offset = { + + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, +}; + +static const struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_lite_17x_csi2_reg_offset = { + + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + + +static const struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_lite_17x_tpg_reg_offset = { + + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /*configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + + +static const struct cam_ife_csid_common_reg_offset + cam_csid_lite_17x_cmn_reg_offset = { + + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 4, + .num_pix = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, +}; + +static const struct cam_ife_csid_reg_offset cam_ife_csid_lite_17x_reg_offset = { + .cmn_reg = &cam_csid_lite_17x_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_lite_17x_csi2_reg_offset, + .ipp_reg = NULL, + .rdi_reg = { + &cam_ife_csid_lite_17x_rdi_0_reg_offset, + &cam_ife_csid_lite_17x_rdi_1_reg_offset, + &cam_ife_csid_lite_17x_rdi_2_reg_offset, + &cam_ife_csid_lite_17x_rdi_3_reg_offset, + }, + .tpg_reg = &cam_ife_csid_lite_17x_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_LITE17X_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c new file mode 100644 index 000000000000..3a6d3e8abf98 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#include +#include "cam_ife_csid_soc.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static int cam_ife_csid_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + struct device_node *of_node = NULL; + struct csid_device_soc_info *csid_soc_info = NULL; + int rc = 0; + + of_node = soc_info->pdev->dev.of_node; + csid_soc_info = (struct csid_device_soc_info *)soc_info->soc_private; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) + return rc; + + return rc; +} + +static int cam_ife_csid_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, + void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, csid_irq_handler, + irq_data); + if (rc) + return rc; + + return rc; +} + +int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, void *irq_data) +{ + int rc = 0; + struct cam_cpas_register_params cpas_register_param; + struct cam_csid_soc_private *soc_private; + + soc_private = kzalloc(sizeof(struct cam_csid_soc_private), GFP_KERNEL); + if (!soc_private) + return -ENOMEM; + + soc_info->soc_private = soc_private; + + rc = cam_ife_csid_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + /* Need to see if we want post process the clock list */ + + rc = cam_ife_csid_request_platform_resource(soc_info, csid_irq_handler, + irq_data); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Error Request platform resources failed rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "csid", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } else { + soc_private->cpas_handle = cpas_register_param.client_handle; + } + + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); +free_soc_private: + kfree(soc_private); + + return rc; +} + +int cam_ife_csid_deinit_soc_resources( + struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -ENODEV; + } + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_ife_csid_enable_soc_resources( + struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + CAM_DBG(CAM_ISP, "csid camnoc_bw:%lld mnoc_ab_bw:%lld mnoc_ib_bw:%lld ", + axi_vote.axi_path[0].camnoc_bw, + axi_vote.axi_path[0].mnoc_ab_bw, + axi_vote.axi_path[0].mnoc_ib_bw); + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS start failed"); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + clk_level, true); + if (rc) { + CAM_ERR(CAM_ISP, "enable platform failed"); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_ife_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_ISP, "Disable platform failed"); + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} + +int cam_ife_csid_enable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + uint32_t cpass_ife_force_clk_offset; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + + soc_private = soc_info->soc_private; + cpass_ife_force_clk_offset = + cpas_ife_base_offset + (0x4 * soc_info->index); + rc = cam_cpas_reg_write(soc_private->cpas_handle, CAM_CPAS_REG_CPASTOP, + cpass_ife_force_clk_offset, 1, 1); + + if (rc) + CAM_ERR(CAM_ISP, "CPASS set IFE:%d Force clock On failed", + soc_info->index); + else + CAM_DBG(CAM_ISP, "CPASS set IFE:%d Force clock On", + soc_info->index); + + return rc; +} + +int cam_ife_csid_disable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + uint32_t cpass_ife_force_clk_offset; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + + soc_private = soc_info->soc_private; + cpass_ife_force_clk_offset = + cpas_ife_base_offset + (0x4 * soc_info->index); + rc = cam_cpas_reg_write(soc_private->cpas_handle, CAM_CPAS_REG_CPASTOP, + cpass_ife_force_clk_offset, 1, 0); + + if (rc) + CAM_ERR(CAM_ISP, "CPASS set IFE:%d Force clock Off failed", + soc_info->index); + else + CAM_DBG(CAM_ISP, "CPASS set IFE:%d Force clock off", + soc_info->index); + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h new file mode 100644 index 000000000000..317dcb39a59b --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_SOC_H_ +#define _CAM_IFE_CSID_SOC_H_ + +#include "cam_isp_hw.h" + +/* + * struct cam_csid_soc_private: + * + * @Brief: Private SOC data specific to CSID HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + */ +struct cam_csid_soc_private { + uint32_t cpas_handle; +}; + +/** + * struct csid_device_soc_info - CSID SOC info object + * + * @csi_vdd_voltage: csi vdd voltage value + * + */ +struct csid_device_soc_info { + int csi_vdd_voltage; +}; + +/** + * cam_ife_csid_init_soc_resources() + * + * @brief: csid initialization function for the soc info + * + * @soc_info: soc info structure pointer + * @csid_irq_handler: irq handler function to be registered + * @irq_data: irq data for the callback function + * + */ +int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, void *irq_data); + + +/** + * cam_ife_csid_deinit_soc_resources() + * + * @brief: csid de initialization function for the soc info + * + * @soc_info: soc info structure pointer + * + */ +int cam_ife_csid_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * cam_ife_csid_enable_soc_resources() + * + * @brief: csid soc resource enable function + * + * @soc_info: soc info structure pointer + * @clk_lvl: vote level to start with + * + */ +int cam_ife_csid_enable_soc_resources(struct cam_hw_soc_info *soc_info, + uint32_t clk_lvl); + +/** + * cam_ife_csid_disable_soc_resources() + * + * @brief: csid soc resource disable function + * + * @soc_info: soc info structure pointer + * + */ +int cam_ife_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * cam_ife_csid_enable_ife_force_clock() + * + * @brief: if csid testgen used for dual isp case, before + * starting csid test gen, enable ife force clock on + * through cpas + * + * @soc_info: soc info structure pointer + * @cpas_ife_base_offset: cpas ife force clock base reg offset value + * + */ +int cam_ife_csid_enable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset); + +/** + * cam_ife_csid_disable_ife_force_clock_on() + * + * @brief: disable the IFE force clock on after dual ISP + * CSID test gen stop + * + * @soc_info: soc info structure pointer + * @cpas_ife_base_offset: cpas ife force clock base reg offset value + * + */ +int cam_ife_csid_disable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset); + +/** + * cam_ife_csid_get_vote_level() + * + * @brief: get the vote level from clock rate + * + * @soc_info: soc info structure pointer + * @clock_rate clock rate + * + */ +uint32_t cam_ife_csid_get_vote_level(struct cam_hw_soc_info *soc_info, + uint64_t clock_rate); + +#endif diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h new file mode 100644 index 000000000000..247dfc5960fb --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -0,0 +1,222 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSID_HW_INTF_H_ +#define _CAM_CSID_HW_INTF_H_ + +#include "cam_isp_hw.h" +#include "cam_hw_intf.h" + +/* MAX IFE CSID instance */ +#define CAM_IFE_CSID_HW_NUM_MAX 7 +#define CAM_IFE_CSID_RDI_MAX 4 + +/** + * enum cam_ife_pix_path_res_id - Specify the csid patch + */ +enum cam_ife_pix_path_res_id { + CAM_IFE_PIX_PATH_RES_RDI_0, + CAM_IFE_PIX_PATH_RES_RDI_1, + CAM_IFE_PIX_PATH_RES_RDI_2, + CAM_IFE_PIX_PATH_RES_RDI_3, + CAM_IFE_PIX_PATH_RES_IPP, + CAM_IFE_PIX_PATH_RES_PPP, + CAM_IFE_PIX_PATH_RES_MAX, +}; + +/** + * enum cam_ife_cid_res_id - Specify the csid cid + */ +enum cam_ife_cid_res_id { + CAM_IFE_CSID_CID_0, + CAM_IFE_CSID_CID_1, + CAM_IFE_CSID_CID_2, + CAM_IFE_CSID_CID_3, + CAM_IFE_CSID_CID_MAX, +}; + +/** + * struct cam_ife_csid_hw_caps- get the CSID hw capability + * @num_rdis: number of rdis supported by CSID HW device + * @num_pix: number of pxl paths supported by CSID HW device + * @num_ppp: number of ppp paths supported by CSID HW device + * @major_version : major version + * @minor_version: minor version + * @version_incr: version increment + * + */ +struct cam_ife_csid_hw_caps { + uint32_t num_rdis; + uint32_t num_pix; + uint32_t num_ppp; + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; +}; + +struct cam_isp_out_port_generic_info { + uint32_t res_type; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t comp_grp_id; + uint32_t split_point; + uint32_t secure_mode; + uint32_t reserved; +}; + +struct cam_isp_in_port_generic_info { + uint32_t major_ver; + uint32_t minor_ver; + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc[CAM_ISP_VC_DT_CFG]; + uint32_t dt[CAM_ISP_VC_DT_CFG]; + uint32_t num_valid_vc_dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t hbi_cnt; + uint32_t cust_node; + uint32_t num_out_res; + struct cam_isp_out_port_generic_info *data; +}; + +/** + * struct cam_csid_hw_reserve_resource- hw reserve + * @res_type : Reource type CID or PATH + * if type is CID, then res_id is not required, + * if type is path then res id need to be filled + * @res_id : Resource id to be reserved + * @in_port : Input port resource info + * @out_port: Output port resource info, used for RDI path only + * @sync_mode: Sync mode + * Sync mode could be master, slave or none + * @master_idx: Master device index to be configured in the slave path + * for master path, this value is not required. + * only slave need to configure the master index value + * @cid: cid (DT_ID) value for path, this is applicable for CSID path + * reserve + * @node_res : Reserved resource structure pointer + * @crop_enable : Flag to indicate CSID crop enable + * + */ +struct cam_csid_hw_reserve_resource_args { + enum cam_isp_resource_type res_type; + uint32_t res_id; + struct cam_isp_in_port_generic_info *in_port; + struct cam_isp_out_port_generic_info *out_port; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t master_idx; + uint32_t cid; + struct cam_isp_resource_node *node_res; + bool crop_enable; +}; + +/** + * enum cam_ife_csid_halt_cmd - Specify the halt command type + */ +enum cam_ife_csid_halt_cmd { + CAM_CSID_HALT_AT_FRAME_BOUNDARY, + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + CAM_CSID_HALT_IMMEDIATELY, + CAM_CSID_HALT_MAX, +}; + +/** + * struct cam_csid_hw_stop- stop all resources + * @stop_cmd : Applicable only for PATH resources + * if stop command set to Halt immediately,driver will stop + * path immediately, manager need to reset the path after HI + * if stop command set to halt at frame boundary, driver will set + * halt at frame boundary and wait for frame boundary + * @node_res : reource pointer array( ie cid or CSID) + * @num_res : number of resources to be stopped + * + */ +struct cam_csid_hw_stop_args { + enum cam_ife_csid_halt_cmd stop_cmd; + struct cam_isp_resource_node **node_res; + uint32_t num_res; +}; + +/** + * enum cam_ife_csid_reset_type - Specify the reset type + */ +enum cam_ife_csid_reset_type { + CAM_IFE_CSID_RESET_GLOBAL, + CAM_IFE_CSID_RESET_PATH, + CAM_IFE_CSID_RESET_MAX, +}; + +/** + * struct cam_ife_csid_reset_cfg- csid reset configuration + * @ reset_type : Global reset or path reset + * @res_node : resource need to be reset + * + */ +struct cam_csid_reset_cfg_args { + enum cam_ife_csid_reset_type reset_type; + struct cam_isp_resource_node *node_res; +}; + +/** + * struct cam_csid_get_time_stamp_args- time stamp capture arguments + * @res_node : resource to get the time stamp + * @time_stamp_val : captured time stamp + * @boot_timestamp : boot time stamp + */ +struct cam_csid_get_time_stamp_args { + struct cam_isp_resource_node *node_res; + uint64_t time_stamp_val; + uint64_t boot_timestamp; +}; + +/** + * enum cam_ife_csid_cmd_type - Specify the csid command + */ +enum cam_ife_csid_cmd_type { + CAM_IFE_CSID_CMD_GET_TIME_STAMP, + CAM_IFE_CSID_SET_CSID_DEBUG, + CAM_IFE_CSID_SOF_IRQ_DEBUG, + CAM_IFE_CSID_CMD_MAX, +}; + +/** + * cam_ife_csid_hw_init() + * + * @brief: Initialize function for the CSID hardware + * + * @ife_csid_hw: CSID hardware instance returned + * @hw_idex: CSID hardware instance id + */ +int cam_ife_csid_hw_init(struct cam_hw_intf **ife_csid_hw, + uint32_t hw_idx); + +/* + * struct cam_ife_csid_clock_update_args: + * + * @clk_rate: Clock rate requested + */ +struct cam_ife_csid_clock_update_args { + uint64_t clk_rate; +}; + + +#endif /* _CAM_CSID_HW_INTF_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h new file mode 100644 index 000000000000..33254c1610ae --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -0,0 +1,250 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_H_ +#define _CAM_ISP_HW_H_ + +#include +#include +#include "cam_hw.h" +#include "cam_soc_util.h" +#include "cam_irq_controller.h" +#include "cam_hw_intf.h" + +/* + * struct cam_isp_timestamp: + * + * @mono_time: Monotonic boot time + * @vt_time: AV Timer time + * @ticks: Qtimer ticks + */ +struct cam_isp_timestamp { + struct timeval mono_time; + struct timeval vt_time; + uint64_t ticks; +}; + +/* + * cam_isp_hw_get_timestamp() + * + * @Brief: Get timestamp values + * + * @time_stamp: Structure that holds different time values + * + * @Return: Void + */ +void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp); + +enum cam_isp_hw_type { + CAM_ISP_HW_TYPE_CSID = 0, + CAM_ISP_HW_TYPE_ISPIF = 1, + CAM_ISP_HW_TYPE_VFE = 2, + CAM_ISP_HW_TYPE_IFE_CSID = 3, + CAM_ISP_HW_TYPE_MAX = 4, +}; + +enum cam_isp_hw_split_id { + CAM_ISP_HW_SPLIT_LEFT = 0, + CAM_ISP_HW_SPLIT_RIGHT, + CAM_ISP_HW_SPLIT_MAX, +}; + +enum cam_isp_hw_sync_mode { + CAM_ISP_HW_SYNC_NONE, + CAM_ISP_HW_SYNC_MASTER, + CAM_ISP_HW_SYNC_SLAVE, + CAM_ISP_HW_SYNC_MAX, +}; + +enum cam_isp_resource_state { + CAM_ISP_RESOURCE_STATE_UNAVAILABLE = 0, + CAM_ISP_RESOURCE_STATE_AVAILABLE = 1, + CAM_ISP_RESOURCE_STATE_RESERVED = 2, + CAM_ISP_RESOURCE_STATE_INIT_HW = 3, + CAM_ISP_RESOURCE_STATE_STREAMING = 4, +}; + +enum cam_isp_resource_type { + CAM_ISP_RESOURCE_UNINT, + CAM_ISP_RESOURCE_SRC, + CAM_ISP_RESOURCE_CID, + CAM_ISP_RESOURCE_PIX_PATH, + CAM_ISP_RESOURCE_VFE_IN, + CAM_ISP_RESOURCE_VFE_OUT, + CAM_ISP_RESOURCE_VFE_BUS_RD, + CAM_ISP_RESOURCE_MAX, +}; + +enum cam_isp_hw_cmd_type { + CAM_ISP_HW_CMD_GET_CHANGE_BASE, + CAM_ISP_HW_CMD_GET_BUF_UPDATE, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, + CAM_ISP_HW_CMD_GET_REG_UPDATE, + CAM_ISP_HW_CMD_GET_HFR_UPDATE, + CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + CAM_ISP_HW_CMD_STRIPE_UPDATE, + CAM_ISP_HW_CMD_CLOCK_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE_V2, + CAM_ISP_HW_CMD_BW_CONTROL, + CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, + CAM_ISP_HW_CMD_UBWC_UPDATE, + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, + CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, + CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + CAM_ISP_HW_CMD_UBWC_UPDATE_V2, + CAM_ISP_HW_CMD_CORE_CONFIG, + CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, + CAM_ISP_HW_CMD_MAX, +}; + +/* + * struct cam_isp_resource_node: + * + * @Brief: Structure representing HW resource object + * + * @res_type: Resource Type + * @res_id: Unique resource ID within res_type objects + * for a particular HW + * @res_state: State of the resource + * @hw_intf: HW Interface of HW to which this resource + * belongs + * @res_priv: Private data of the resource + * @list: list_head node for this resource + * @cdm_ops: CDM operation functions + * @tasklet_info: Tasklet structure that will be used to + * schedule IRQ events related to this resource + * @irq_handle: handle returned on subscribing for IRQ event + * @rdi_only_ctx: resource belong to rdi only context or not + * @init: function pointer to init the HW resource + * @deinit: function pointer to deinit the HW resource + * @start: function pointer to start the HW resource + * @stop: function pointer to stop the HW resource + * @process_cmd: function pointer for processing commands + * specific to the resource + * @top_half_handler: Top Half handler function + * @bottom_half_handler: Bottom Half handler function + */ +struct cam_isp_resource_node { + enum cam_isp_resource_type res_type; + uint32_t res_id; + enum cam_isp_resource_state res_state; + struct cam_hw_intf *hw_intf; + void *res_priv; + struct list_head list; + void *cdm_ops; + void *tasklet_info; + int irq_handle; + int rdi_only_ctx; + + int (*init)(struct cam_isp_resource_node *rsrc_node, + void *init_args, uint32_t arg_size); + int (*deinit)(struct cam_isp_resource_node *rsrc_node, + void *deinit_args, uint32_t arg_size); + int (*start)(struct cam_isp_resource_node *rsrc_node); + int (*stop)(struct cam_isp_resource_node *rsrc_node); + int (*process_cmd)(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + CAM_IRQ_HANDLER_TOP_HALF top_half_handler; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/* + * struct cam_isp_hw_event_info: + * + * @Brief: Structure to pass event details to hw mgr + * + * @res_type: Type of IFE resource + * @res_id: Unique resource ID + * @hw_idx: IFE hw index + * @err_type: Error type if any + * + */ +struct cam_isp_hw_event_info { + enum cam_isp_resource_type res_type; + uint32_t res_id; + uint32_t hw_idx; + uint32_t err_type; +}; + +/* + * struct cam_isp_hw_cmd_buf_update: + * + * @Brief: Contain the new created command buffer information + * + * @cmd_buf_addr: Command buffer to store the change base command + * @size: Size of the buffer in bytes + * @used_bytes: Consumed bytes in the command buffer + * + */ +struct cam_isp_hw_cmd_buf_update { + uint32_t *cmd_buf_addr; + uint32_t size; + uint32_t used_bytes; +}; + +/* + * struct cam_isp_hw_get_wm_update: + * + * @Brief: Get cmd buffer for WM updates. + * + * @ image_buf: image buffer address array + * @ num_buf: Number of buffers in the image_buf array + * @ io_cfg: IO buffer config information sent from UMD + * + */ +struct cam_isp_hw_get_wm_update { + uint64_t *image_buf; + uint32_t num_buf; + struct cam_buf_io_cfg *io_cfg; +}; + +/* + * struct cam_isp_hw_get_cmd_update: + * + * @Brief: Get cmd buffer update for different CMD types + * + * @res: Resource node + * @cmd_type: Command type for which to get update + * @cmd: Command buffer information + * + */ +struct cam_isp_hw_get_cmd_update { + struct cam_isp_resource_node *res; + enum cam_isp_hw_cmd_type cmd_type; + struct cam_isp_hw_cmd_buf_update cmd; + union { + void *data; + struct cam_isp_hw_get_wm_update *wm_update; + struct cam_isp_hw_get_wm_update *rm_update; + struct cam_isp_port_hfr_config *hfr_update; + struct cam_isp_clock_config *clock_update; + struct cam_isp_bw_config *bw_update; + struct cam_ubwc_plane_cfg_v1 *ubwc_update; + struct cam_fe_config *fe_update; + struct cam_vfe_generic_ubwc_config *ubwc_config; + struct cam_isp_vfe_wm_config *wm_config; + }; +}; + +/* + * struct cam_isp_hw_dual_isp_update_args: + * + * @Brief: update the dual isp striping configuration. + * + * @ split_id: spilt id to inform left or rifht + * @ res: resource node + * @ dual_cfg: dual isp configuration + * + */ +struct cam_isp_hw_dual_isp_update_args { + enum cam_isp_hw_split_id split_id; + struct cam_isp_resource_node *res; + struct cam_isp_dual_config *dual_cfg; +}; +#endif /* _CAM_ISP_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h new file mode 100644 index 000000000000..7944cbc8933f --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -0,0 +1,370 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_HW_INTF_H_ +#define _CAM_VFE_HW_INTF_H_ + +#include "cam_isp_hw.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_HW_NUM_MAX 7 + +#define VFE_CORE_BASE_IDX 0 +/* + * VBIF and BUS do not exist on same HW. + * Hence both can be 1 below. + */ +#define VFE_VBIF_BASE_IDX 1 +#define VFE_BUS_BASE_IDX 1 + +#define CAM_VFE_MAX_UBWC_PORTS 4 + +enum cam_isp_hw_vfe_in_mux { + CAM_ISP_HW_VFE_IN_CAMIF = 0, + CAM_ISP_HW_VFE_IN_TESTGEN = 1, + CAM_ISP_HW_VFE_IN_RD = 2, + CAM_ISP_HW_VFE_IN_RDI0 = 3, + CAM_ISP_HW_VFE_IN_RDI1 = 4, + CAM_ISP_HW_VFE_IN_RDI2 = 5, + CAM_ISP_HW_VFE_IN_RDI3 = 6, + CAM_ISP_HW_VFE_IN_PDLIB = 7, + CAM_ISP_HW_VFE_IN_LCR = 8, + CAM_ISP_HW_VFE_IN_MAX, +}; + +enum cam_isp_hw_vfe_core { + CAM_ISP_HW_VFE_CORE_0, + CAM_ISP_HW_VFE_CORE_1, + CAM_ISP_HW_VFE_CORE_2, + CAM_ISP_HW_VFE_CORE_3, + CAM_ISP_HW_VFE_CORE_MAX, +}; + +enum cam_vfe_hw_irq_status { + CAM_VFE_IRQ_STATUS_ERR_COMP = -3, + CAM_VFE_IRQ_STATUS_COMP_OWRT = -2, + CAM_VFE_IRQ_STATUS_ERR = -1, + CAM_VFE_IRQ_STATUS_SUCCESS = 0, + CAM_VFE_IRQ_STATUS_OVERFLOW = 1, + CAM_VFE_IRQ_STATUS_P2I_ERROR = 2, + CAM_VFE_IRQ_STATUS_VIOLATION = 3, + CAM_VFE_IRQ_STATUS_MAX, +}; + +enum cam_vfe_hw_irq_regs { + CAM_IFE_IRQ_CAMIF_REG_STATUS0 = 0, + CAM_IFE_IRQ_CAMIF_REG_STATUS1 = 1, + CAM_IFE_IRQ_CAMIF_REG_STATUS2 = 2, + CAM_IFE_IRQ_VIOLATION_STATUS = 3, + CAM_IFE_IRQ_REGISTERS_MAX, +}; + +enum cam_vfe_bus_irq_regs { + CAM_IFE_IRQ_BUS_REG_STATUS0 = 0, + CAM_IFE_IRQ_BUS_REG_STATUS1 = 1, + CAM_IFE_IRQ_BUS_REG_STATUS2 = 2, + CAM_IFE_IRQ_BUS_REG_COMP_ERR = 3, + CAM_IFE_IRQ_BUS_REG_COMP_OWRT = 4, + CAM_IFE_IRQ_BUS_DUAL_COMP_ERR = 5, + CAM_IFE_IRQ_BUS_DUAL_COMP_OWRT = 6, + CAM_IFE_BUS_IRQ_REGISTERS_MAX, +}; + +enum cam_vfe_bus_ver3_irq_regs { + CAM_IFE_IRQ_BUS_VER3_REG_STATUS0 = 0, + CAM_IFE_IRQ_BUS_VER3_REG_STATUS1 = 1, + CAM_IFE_IRQ_BUS_VER3_REG_MAX, +}; + +enum cam_vfe_reset_type { + CAM_VFE_HW_RESET_HW_AND_REG, + CAM_VFE_HW_RESET_HW, + CAM_VFE_HW_RESET_MAX, +}; + +/* + * struct cam_vfe_hw_get_hw_cap: + * + * @max_width: Max width supported by HW + * @max_height: Max height supported by HW + * @max_pixel_num: Max Pixel channels available + * @max_rdi_num: Max Raw channels available + */ +struct cam_vfe_hw_get_hw_cap { + uint32_t max_width; + uint32_t max_height; + uint32_t max_pixel_num; + uint32_t max_rdi_num; +}; + +/* + * struct cam_vfe_hw_vfe_out_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @out_port_info: Output Port details to acquire + * @unique_id: Unique Identity of Context to associate with this + * resource. Used for composite grouping of multiple + * resources in the same context + * @is_dual: Dual VFE or not + * @split_id: In case of Dual VFE, this is Left or Right. + * (Default is Left if Single VFE) + * @is_master: In case of Dual VFE, this is Master or Slave. + * (Default is Master in case of Single VFE) + * @dual_slave_core: If Master and Slave exists, HW Index of Slave + * @cdm_ops: CDM operations + */ +struct cam_vfe_hw_vfe_out_acquire_args { + struct cam_isp_resource_node *rsrc_node; + struct cam_isp_out_port_generic_info *out_port_info; + uint32_t unique_id; + uint32_t is_dual; + enum cam_isp_hw_split_id split_id; + uint32_t is_master; + uint32_t dual_slave_core; + struct cam_cdm_utils_ops *cdm_ops; +}; + +/* + * struct cam_vfe_hw_vfe_in_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @res_id: Resource ID of resource to acquire if specific, + * else CAM_ISP_HW_VFE_IN_MAX + * @cdm_ops: CDM operations + * @sync_mode: In case of Dual VFE, this is Master or Slave. + * (Default is Master in case of Single VFE) + * @in_port: Input port details to acquire + */ +struct cam_vfe_hw_vfe_in_acquire_args { + struct cam_isp_resource_node *rsrc_node; + uint32_t res_id; + void *cdm_ops; + enum cam_isp_hw_sync_mode sync_mode; + struct cam_isp_in_port_generic_info *in_port; +}; + +/* + * struct cam_vfe_acquire_args: + * + * @rsrc_type: Type of Resource (OUT/IN) to acquire + * @tasklet: Tasklet to associate with this resource. This is + * used to schedule bottom of IRQ events associated + * with this resource. + * @priv: Context data + * @event_cb: Callback function to hw mgr in case of hw events + * @vfe_out: Acquire args for VFE_OUT + * @vfe_bus_rd Acquire args for VFE_BUS_READ + * @vfe_in: Acquire args for VFE_IN + */ +struct cam_vfe_acquire_args { + enum cam_isp_resource_type rsrc_type; + void *tasklet; + void *priv; + cam_hw_mgr_event_cb_func event_cb; + union { + struct cam_vfe_hw_vfe_out_acquire_args vfe_out; + struct cam_vfe_hw_vfe_out_acquire_args vfe_bus_rd; + struct cam_vfe_hw_vfe_in_acquire_args vfe_in; + }; +}; + +/* + * struct cam_vfe_clock_update_args: + * + * @node_res: Resource to get the time stamp + * @clk_rate: Clock rate requested + */ +struct cam_vfe_clock_update_args { + struct cam_isp_resource_node *node_res; + uint64_t clk_rate; +}; + +/* + * struct cam_vfe_core_config_args: + * + * @node_res: Resource to get the time stamp + * @core_config: Core config for IFE + */ +struct cam_vfe_core_config_args { + struct cam_isp_resource_node *node_res; + struct cam_isp_core_config core_config; +}; + +/* + * struct cam_vfe_bw_update_args_v2: + * + * @node_res: Resource to get the BW + * @isp_vote: Vote info according to usage data (left/right/rdi) + */ +struct cam_vfe_bw_update_args_v2 { + struct cam_isp_resource_node *node_res; + struct cam_axi_vote isp_vote; +}; + +/* + * struct cam_vfe_bw_update_args: + * + * @node_res: Resource to get the BW + * @camnoc_bw_bytes: Bandwidth vote request for CAMNOC + * @external_bw_bytes: Bandwidth vote request from CAMNOC + * out to the rest of the path-to-DDR + */ +struct cam_vfe_bw_update_args { + struct cam_isp_resource_node *node_res; + uint64_t camnoc_bw_bytes; + uint64_t external_bw_bytes; +}; + +/* + * struct cam_vfe_fe_update_args: + * + * @node_res: Resource to get fetch configuration + * @fe_config: fetch engine configuration + * + */ +struct cam_vfe_fe_update_args { + struct cam_isp_resource_node *node_res; + struct cam_fe_config fe_config; +}; + +enum cam_vfe_bw_control_action { + CAM_VFE_BW_CONTROL_EXCLUDE = 0, + CAM_VFE_BW_CONTROL_INCLUDE = 1 +}; + +/* + * struct cam_vfe_bw_control_args: + * + * @node_res: Resource to get the time stamp + * @action: Bandwidth control action + */ +struct cam_vfe_bw_control_args { + struct cam_isp_resource_node *node_res; + enum cam_vfe_bw_control_action action; +}; + +/* + * struct cam_vfe_top_irq_evt_payload: + * + * @Brief: This structure is used to save payload for IRQ + * related to VFE_TOP resources + * + * @list: list_head node for the payload + * @irq_reg_val: IRQ and Error register values, read when IRQ was + * handled + * @ts: Timestamp + */ +struct cam_vfe_top_irq_evt_payload { + struct list_head list; + uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; + struct cam_isp_timestamp ts; +}; + +/* + * struct cam_vfe_bus_irq_evt_payload: + * + * @Brief: This structure is used to save payload for IRQ + * related to VFE_BUS resources + * + * @list: list_head node for the payload + * @core_index: Index of VFE HW that generated this IRQ event + * @debug_status_0: Value of debug status_0 register at time of IRQ + * @evt_id: IRQ event + * @irq_reg_val: IRQ and Error register values, read when IRQ was + * handled + * @error_type: Identify different errors + * @ts: Timestamp + */ +struct cam_vfe_bus_irq_evt_payload { + struct list_head list; + uint32_t core_index; + uint32_t debug_status_0; + uint32_t ccif_violation_status; + uint32_t overflow_status; + uint32_t image_size_violation_status; + uint32_t evt_id; + uint32_t irq_reg_val[CAM_IFE_BUS_IRQ_REGISTERS_MAX]; + struct cam_isp_timestamp ts; +}; + +/** + * struct cam_ubwc_generic_plane_config - UBWC Plane configuration info + * + * @port_type: Port Type + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config: UBWC mode config + * @static ctrl: UBWC static ctrl + * @ctrl_2: UBWC ctrl 2 + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * @stats_ctrl_2: UBWC stats control + * @lossy_threshold0 UBWC lossy threshold 0 + * @lossy_threshold1 UBWC lossy threshold 1 + * @lossy_var_offset UBWC offset variance threshold + * @bandwidth limit UBWC bandwidth limit + */ +struct cam_vfe_generic_ubwc_plane_config { + uint32_t port_type; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config_0; + uint32_t mode_config_1; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; + uint32_t static_ctrl; + uint32_t ctrl_2; + uint32_t stats_ctrl_2; + uint32_t lossy_threshold_0; + uint32_t lossy_threshold_1; + uint32_t lossy_var_offset; + uint32_t bandwidth_limit; +}; + +/** + * struct cam_ubwc_generic_config - UBWC Configuration Payload + * + * @api_version: UBWC config api version + * @ubwc_plane_config: Array of UBWC configurations per plane + */ +struct cam_vfe_generic_ubwc_config { + uint32_t api_version; + struct cam_vfe_generic_ubwc_plane_config + ubwc_plane_cfg[CAM_PACKET_MAX_PLANES - 1]; +}; + +/* + * cam_vfe_hw_init() + * + * @Brief: Initialize VFE HW device + * + * @vfe_hw: vfe_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of VFE HW + */ +int cam_vfe_hw_init(struct cam_hw_intf **vfe_hw, uint32_t hw_idx); + +/* + * cam_vfe_put_evt_payload() + * + * @Brief: Put the evt payload back to free list + * + * @core_info: VFE HW core_info + * @evt_payload: Event payload data + */ +int cam_vfe_put_evt_payload(void *core_info, + struct cam_vfe_top_irq_evt_payload **evt_payload); + +#endif /* _CAM_VFE_HW_INTF_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile new file mode 100644 index 000000000000..1609a7a04808 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_soc.o cam_vfe_dev.o cam_vfe_core.o +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_bus/ vfe_top/ vfe17x/ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c new file mode 100644 index 000000000000..0fe3e9c79f35 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -0,0 +1,748 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "cam_tasklet_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_core.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_top.h" +#include "cam_ife_hw_mgr.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe"; + +#define CAM_VFE_17X_CLEAR_0_REG_OFFSET 0x00000064 +#define CAM_VFE_17X_CLEAR_1_REG_OFFSET 0x00000068 +#define CAM_VFE_17X_IRQ_CMD_REG_OFFSET 0x00000058 +#define CAM_VFE_17X_TOP_RESET_MASK 0x80000000 + +#define CAM_VFE_48X_CLEAR_0_REG_OFFSET 0x00000048 +#define CAM_VFE_48X_CLEAR_1_REG_OFFSET 0x0000004C +#define CAM_VFE_48X_CLEAR_2_REG_OFFSET 0x00000050 +#define CAM_VFE_48X_IRQ_CMD_REG_OFFSET 0x00000038 +#define CAM_VFE_48X_TOP_RESET_MASK 0x00000001 + +#define CAM_VFE_LITE_48X_CLEAR_0_REG_OFFSET 0x00000034 +#define CAM_VFE_LITE_48X_CLEAR_1_REG_OFFSET 0x00000038 +#define CAM_VFE_LITE_48X_CLEAR_2_REG_OFFSET 0x0000003C +#define CAM_VFE_LITE_48X_IRQ_CMD_REG_OFFSET 0x00000024 +#define CAM_VFE_LITE_48X_TOP_RESET_MASK 0x00020000 + +int cam_vfe_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_dev = hw_priv; + struct cam_vfe_hw_core_info *core_info = NULL; + int rc = 0; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_dev->core_info; + + if (core_info->vfe_top->hw_ops.get_hw_caps) + core_info->vfe_top->hw_ops.get_hw_caps( + core_info->vfe_top->top_priv, + get_hw_cap_args, arg_size); + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_vfe_reset_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc = -EINVAL; + struct cam_hw_info *vfe_hw; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + void __iomem *mem_base; + + vfe_hw = th_payload->handler_priv; + soc_info = &vfe_hw->soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + CAM_DBG(CAM_ISP, "Enter"); + + /* + * Clear All IRQs to avoid spurious IRQs immediately + * after Reset Done. + */ + CAM_DBG(CAM_ISP, "TOP_IRQ_STATUS_0 = 0x%x", + th_payload->evt_status_arr[0]); + + mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_480_V100: + if (!soc_private->is_ife_lite) { + if (th_payload->evt_status_arr[0] & 0x1) { + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_48X_CLEAR_0_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_48X_CLEAR_1_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_48X_CLEAR_2_REG_OFFSET); + cam_io_w(0x00000001, mem_base + + CAM_VFE_48X_IRQ_CMD_REG_OFFSET); + CAM_DBG(CAM_ISP, + "Calling Complete for RESET CMD"); + complete(&vfe_hw->hw_complete); + rc = 0; + } + } else { + if (th_payload->evt_status_arr[0] & (1<<17)) { + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_LITE_48X_CLEAR_0_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_LITE_48X_CLEAR_1_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_LITE_48X_CLEAR_2_REG_OFFSET); + cam_io_w(0x00000001, mem_base + + CAM_VFE_LITE_48X_IRQ_CMD_REG_OFFSET); + CAM_DBG(CAM_ISP, + "Calling Complete for RESET CMD"); + complete(&vfe_hw->hw_complete); + rc = 0; + } + } + break; + default: + if (th_payload->evt_status_arr[0] & (1<<31)) { + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_17X_CLEAR_0_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_17X_CLEAR_1_REG_OFFSET); + cam_io_w(0x00000001, mem_base + + CAM_VFE_17X_IRQ_CMD_REG_OFFSET); + CAM_DBG(CAM_ISP, "Calling Complete for RESET CMD"); + complete(&vfe_hw->hw_complete); + rc = 0; + } + break; + } + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_isp_resource_node *isp_res = NULL; + int rc = 0; + uint32_t reset_core_args = + CAM_VFE_HW_RESET_HW_AND_REG; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&vfe_hw->hw_mutex); + vfe_hw->open_count++; + if (vfe_hw->open_count > 1) { + mutex_unlock(&vfe_hw->hw_mutex); + CAM_DBG(CAM_ISP, "VFE has already been initialized cnt %d", + vfe_hw->open_count); + return 0; + } + mutex_unlock(&vfe_hw->hw_mutex); + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + /* Turn ON Regulators, Clocks and other SOC resources */ + rc = cam_vfe_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "Enable SOC failed"); + rc = -EFAULT; + goto decrement_open_cnt; + } + + isp_res = (struct cam_isp_resource_node *)init_hw_args; + if (isp_res && isp_res->init) { + rc = isp_res->init(isp_res, NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "init Failed rc=%d", rc); + goto disable_soc; + } + } + + CAM_DBG(CAM_ISP, "Enable soc done"); + + /* Do HW Reset */ + rc = cam_vfe_reset(hw_priv, &reset_core_args, sizeof(uint32_t)); + if (rc) { + CAM_ERR(CAM_ISP, "Reset Failed rc=%d", rc); + goto deinint_vfe_res; + } + + rc = core_info->vfe_bus->hw_ops.init(core_info->vfe_bus->bus_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Bus HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + + rc = core_info->vfe_top->hw_ops.init(core_info->vfe_top->top_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Top HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.init( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Bus RD HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + } + + vfe_hw->hw_state = CAM_HW_STATE_POWER_UP; + return rc; + +deinint_vfe_res: + if (isp_res && isp_res->deinit) + isp_res->deinit(isp_res, NULL, 0); +disable_soc: + cam_vfe_disable_soc_resources(soc_info); +decrement_open_cnt: + mutex_lock(&vfe_hw->hw_mutex); + vfe_hw->open_count--; + mutex_unlock(&vfe_hw->hw_mutex); + return rc; +} + +int cam_vfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_isp_resource_node *isp_res = NULL; + int rc = 0; + uint32_t reset_core_args = + CAM_VFE_HW_RESET_HW_AND_REG; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&vfe_hw->hw_mutex); + if (!vfe_hw->open_count) { + mutex_unlock(&vfe_hw->hw_mutex); + CAM_ERR(CAM_ISP, "Error. Unbalanced deinit"); + return -EFAULT; + } + vfe_hw->open_count--; + if (vfe_hw->open_count) { + mutex_unlock(&vfe_hw->hw_mutex); + CAM_DBG(CAM_ISP, "open_cnt non-zero =%d", vfe_hw->open_count); + return 0; + } + mutex_unlock(&vfe_hw->hw_mutex); + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + rc = core_info->vfe_bus->hw_ops.deinit(core_info->vfe_bus->bus_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.deinit( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + } + + isp_res = (struct cam_isp_resource_node *)deinit_hw_args; + if (isp_res && isp_res->deinit) { + rc = isp_res->deinit(isp_res, NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "deinit failed"); + } + + rc = cam_vfe_reset(hw_priv, &reset_core_args, sizeof(uint32_t)); + + /* Turn OFF Regulators, Clocks and other SOC resources */ + CAM_DBG(CAM_ISP, "Disable SOC resource"); + rc = cam_vfe_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ISP, "Disable SOC failed"); + + vfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_vfe_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + uint32_t top_reset_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + int rc; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &vfe_hw->soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + memset(top_reset_irq_reg_mask, 0, sizeof(top_reset_irq_reg_mask)); + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_480_V100: + if (!soc_private->is_ife_lite) + top_reset_irq_reg_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + = CAM_VFE_48X_TOP_RESET_MASK; + else + top_reset_irq_reg_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + = CAM_VFE_LITE_48X_TOP_RESET_MASK; + break; + default: + top_reset_irq_reg_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + = CAM_VFE_17X_TOP_RESET_MASK; + break; + } + + core_info->reset_irq_handle = cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_0, + top_reset_irq_reg_mask, vfe_hw, + cam_vfe_reset_irq_top_half, NULL, NULL, NULL); + if (core_info->reset_irq_handle < 1) { + CAM_ERR(CAM_ISP, "subscribe irq controller failed"); + core_info->reset_irq_handle = 0; + return -EFAULT; + } + + reinit_completion(&vfe_hw->hw_complete); + + CAM_DBG(CAM_ISP, "calling RESET on VFE:%d", soc_info->index); + + core_info->vfe_top->hw_ops.reset(core_info->vfe_top->top_priv, + reset_core_args, arg_size); + + /* Wait for Completion or Timeout of 500ms */ + rc = wait_for_completion_timeout(&vfe_hw->hw_complete, 500); + + if (!rc) + CAM_ERR(CAM_ISP, "Reset Timeout"); + else + CAM_DBG(CAM_ISP, "reset complete done (%d)", rc); + + rc = cam_irq_controller_unsubscribe_irq( + core_info->vfe_irq_controller, core_info->reset_irq_handle); + if (rc) + CAM_ERR(CAM_ISP, "Error. Unsubscribe failed"); + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + time_stamp->mono_time.tv_sec = ts.tv_sec; + time_stamp->mono_time.tv_usec = ts.tv_nsec/1000; +} + +int cam_vfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_vfe_acquire_args *acquire; + int rc = -ENODEV; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_vfe_acquire_args))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + acquire = (struct cam_vfe_acquire_args *)reserve_args; + + CAM_DBG(CAM_ISP, "acq res type: %d", acquire->rsrc_type); + mutex_lock(&vfe_hw->hw_mutex); + if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_IN) { + rc = core_info->vfe_top->hw_ops.reserve( + core_info->vfe_top->top_priv, + acquire, sizeof(*acquire)); + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_OUT) { + rc = core_info->vfe_bus->hw_ops.reserve( + core_info->vfe_bus->bus_priv, acquire, + sizeof(*acquire)); + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.reserve( + core_info->vfe_rd_bus->bus_priv, acquire, + sizeof(*acquire)); + } else + CAM_ERR(CAM_ISP, "Invalid res type:%d", acquire->rsrc_type); + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + +int cam_vfe_release(void *hw_priv, void *release_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + int rc = -ENODEV; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *) release_args; + + mutex_lock(&vfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) + rc = core_info->vfe_top->hw_ops.release( + core_info->vfe_top->top_priv, isp_res, + sizeof(*isp_res)); + else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) + rc = core_info->vfe_bus->hw_ops.release( + core_info->vfe_bus->bus_priv, isp_res, + sizeof(*isp_res)); + else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.release( + core_info->vfe_rd_bus->bus_priv, isp_res, + sizeof(*isp_res)); + } else { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + } + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + + +int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + struct cam_hw_soc_info *soc_info = NULL; + int rc = 0; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *)start_args; + core_info->tasklet_info = isp_res->tasklet_info; + + mutex_lock(&vfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { + rc = core_info->vfe_top->hw_ops.start( + core_info->vfe_top->top_priv, isp_res, + sizeof(struct cam_isp_resource_node)); + + if (rc) + CAM_ERR(CAM_ISP, "Failed to start VFE IN"); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { + rc = core_info->vfe_bus->hw_ops.start(isp_res, NULL, 0); + + if (rc) + CAM_ERR(CAM_ISP, "Failed to start VFE OUT"); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.start(isp_res, + NULL, 0); + + if (rc) + CAM_ERR(CAM_ISP, "Failed to start BUS RD"); + } + } else { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + rc = -EFAULT; + } + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + +int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + int rc = -EINVAL; + + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *)stop_args; + + mutex_lock(&vfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { + rc = core_info->vfe_top->hw_ops.stop( + core_info->vfe_top->top_priv, isp_res, + sizeof(struct cam_isp_resource_node)); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { + rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.stop(isp_res, + NULL, 0); + } else { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + } + + if (core_info->reset_irq_handle > 0) { + cam_irq_controller_unsubscribe_irq( + core_info->vfe_irq_controller, + core_info->reset_irq_handle); + core_info->reset_irq_handle = 0; + } + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + +int cam_vfe_read(void *hw_priv, void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_write(void *hw_priv, void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_vfe_hw_info *hw_info = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + hw_info = core_info->vfe_hw_info; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + case CAM_ISP_HW_CMD_BW_UPDATE: + case CAM_ISP_HW_CMD_BW_CONTROL: + case CAM_ISP_HW_CMD_CORE_CONFIG: + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + rc = core_info->vfe_top->hw_ops.process_cmd( + core_info->vfe_top->top_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + case CAM_ISP_HW_CMD_UBWC_UPDATE: + case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: + case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + rc = core_info->vfe_bus->hw_ops.process_cmd( + core_info->vfe_bus->bus_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + break; + + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = core_info->vfe_top->hw_ops.process_cmd( + core_info->vfe_top->top_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid cmd type:%d", cmd_type); + rc = -EINVAL; + break; + } + return rc; +} + +irqreturn_t cam_vfe_irq(int irq_num, void *data) +{ + struct cam_hw_info *vfe_hw; + struct cam_vfe_hw_core_info *core_info; + + if (!data) + return IRQ_NONE; + + vfe_hw = (struct cam_hw_info *)data; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + return cam_irq_controller_handle_irq(irq_num, + core_info->vfe_irq_controller); +} + +int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_vfe_hw_info *vfe_hw_info) +{ + int rc = -EINVAL; + struct cam_vfe_soc_private *soc_private = NULL; + + CAM_DBG(CAM_ISP, "Enter"); + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + rc = cam_irq_controller_init(drv_name, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX), + vfe_hw_info->irq_reg_info, &core_info->vfe_irq_controller); + if (rc) { + CAM_ERR(CAM_ISP, + "Error, cam_irq_controller_init failed rc = %d", rc); + return rc; + } + + rc = cam_vfe_top_init(vfe_hw_info->top_version, soc_info, hw_intf, + vfe_hw_info->top_hw_info, core_info->vfe_irq_controller, + &core_info->vfe_top); + if (rc) { + CAM_ERR(CAM_ISP, "Error, cam_vfe_top_init failed rc = %d", rc); + goto deinit_controller; + } + + rc = cam_vfe_bus_init(vfe_hw_info->bus_version, BUS_TYPE_WR, + soc_info, hw_intf, vfe_hw_info->bus_hw_info, + core_info->vfe_irq_controller, &core_info->vfe_bus); + if (rc) { + CAM_ERR(CAM_ISP, "Error, cam_vfe_bus_init failed rc = %d", rc); + goto deinit_top; + } + + /* Read Bus is not valid for vfe-lite */ + if (!soc_private->is_ife_lite) { + rc = cam_vfe_bus_init(vfe_hw_info->bus_rd_version, BUS_TYPE_RD, + soc_info, hw_intf, vfe_hw_info->bus_rd_hw_info, + core_info->vfe_irq_controller, &core_info->vfe_rd_bus); + if (rc) { + CAM_WARN(CAM_ISP, "Error, RD cam_vfe_bus_init failed"); + rc = 0; + } + CAM_DBG(CAM_ISP, "vfe_bus_rd %pK hw_idx %d", + core_info->vfe_rd_bus, hw_intf->hw_idx); + } + + spin_lock_init(&core_info->spin_lock); + + return rc; + +deinit_top: + cam_vfe_top_deinit(vfe_hw_info->top_version, + &core_info->vfe_top); + +deinit_controller: + cam_irq_controller_deinit(&core_info->vfe_irq_controller); + + return rc; +} + +int cam_vfe_core_deinit(struct cam_vfe_hw_core_info *core_info, + struct cam_vfe_hw_info *vfe_hw_info) +{ + int rc = -EINVAL; + unsigned long flags; + + spin_lock_irqsave(&core_info->spin_lock, flags); + + rc = cam_vfe_bus_deinit(vfe_hw_info->bus_version, + &core_info->vfe_bus); + if (rc) + CAM_ERR(CAM_ISP, "Error cam_vfe_bus_deinit failed rc=%d", rc); + + rc = cam_vfe_top_deinit(vfe_hw_info->top_version, + &core_info->vfe_top); + if (rc) + CAM_ERR(CAM_ISP, "Error cam_vfe_top_deinit failed rc=%d", rc); + + rc = cam_irq_controller_deinit(&core_info->vfe_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Error cam_irq_controller_deinit failed rc=%d", rc); + + spin_unlock_irqrestore(&core_info->spin_lock, flags); + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h new file mode 100644 index 000000000000..43afd0377057 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CORE_H_ +#define _CAM_VFE_CORE_H_ + +#include +#include "cam_hw_intf.h" +#include "cam_vfe_top.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_hw_intf.h" + +struct cam_vfe_hw_info { + struct cam_irq_controller_reg_info *irq_reg_info; + + uint32_t bus_version; + void *bus_hw_info; + + uint32_t bus_rd_version; + void *bus_rd_hw_info; + + uint32_t top_version; + void *top_hw_info; + uint32_t camif_version; + void *camif_reg; + + uint32_t camif_lite_version; + void *camif_lite_reg; + + uint32_t testgen_version; + void *testgen_reg; + + uint32_t num_qos_settings; + struct cam_isp_reg_val_pair *qos_settings; + + uint32_t num_ds_settings; + struct cam_isp_reg_val_pair *ds_settings; + + uint32_t num_vbif_settings; + struct cam_isp_reg_val_pair *vbif_settings; +}; + +#define CAM_VFE_EVT_MAX 256 + +struct cam_vfe_hw_core_info { + struct cam_vfe_hw_info *vfe_hw_info; + void *vfe_irq_controller; + struct cam_vfe_top *vfe_top; + struct cam_vfe_bus *vfe_bus; + struct cam_vfe_bus *vfe_rd_bus; + void *tasklet_info; + spinlock_t spin_lock; + int reset_irq_handle; +}; + +int cam_vfe_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size); +int cam_vfe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_vfe_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_vfe_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size); +int cam_vfe_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_vfe_release(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_vfe_start(void *device_priv, + void *start_args, uint32_t arg_size); +int cam_vfe_stop(void *device_priv, + void *stop_args, uint32_t arg_size); +int cam_vfe_read(void *device_priv, + void *read_args, uint32_t arg_size); +int cam_vfe_write(void *device_priv, + void *write_args, uint32_t arg_size); +int cam_vfe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_vfe_irq(int irq_num, void *data); + +int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_vfe_hw_info *vfe_hw_info); + +int cam_vfe_core_deinit(struct cam_vfe_hw_core_info *core_info, + struct cam_vfe_hw_info *vfe_hw_info); + +#endif /* _CAM_VFE_CORE_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c new file mode 100644 index 000000000000..362d513c6a8f --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + + +#include +#include +#include +#include "cam_vfe_dev.h" +#include "cam_vfe_core.h" +#include "cam_vfe_soc.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_vfe_hw_list[CAM_VFE_HW_NUM_MAX] = {0, 0, 0, 0}; + +static char vfe_dev_name[8]; + +int cam_vfe_probe(struct platform_device *pdev) +{ + struct cam_hw_info *vfe_hw = NULL; + struct cam_hw_intf *vfe_hw_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_vfe_hw_info *hw_info = NULL; + int rc = 0; + + vfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!vfe_hw_intf) { + rc = -ENOMEM; + goto end; + } + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &vfe_hw_intf->hw_idx); + + vfe_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!vfe_hw) { + rc = -ENOMEM; + goto free_vfe_hw_intf; + } + + memset(vfe_dev_name, 0, sizeof(vfe_dev_name)); + snprintf(vfe_dev_name, sizeof(vfe_dev_name), + "vfe%1u", vfe_hw_intf->hw_idx); + + vfe_hw->soc_info.pdev = pdev; + vfe_hw->soc_info.dev = &pdev->dev; + vfe_hw->soc_info.dev_name = vfe_dev_name; + vfe_hw_intf->hw_priv = vfe_hw; + vfe_hw_intf->hw_ops.get_hw_caps = cam_vfe_get_hw_caps; + vfe_hw_intf->hw_ops.init = cam_vfe_init_hw; + vfe_hw_intf->hw_ops.deinit = cam_vfe_deinit_hw; + vfe_hw_intf->hw_ops.reset = cam_vfe_reset; + vfe_hw_intf->hw_ops.reserve = cam_vfe_reserve; + vfe_hw_intf->hw_ops.release = cam_vfe_release; + vfe_hw_intf->hw_ops.start = cam_vfe_start; + vfe_hw_intf->hw_ops.stop = cam_vfe_stop; + vfe_hw_intf->hw_ops.read = cam_vfe_read; + vfe_hw_intf->hw_ops.write = cam_vfe_write; + vfe_hw_intf->hw_ops.process_cmd = cam_vfe_process_cmd; + vfe_hw_intf->hw_type = CAM_ISP_HW_TYPE_VFE; + + CAM_DBG(CAM_ISP, "type %d index %d", + vfe_hw_intf->hw_type, vfe_hw_intf->hw_idx); + + platform_set_drvdata(pdev, vfe_hw_intf); + + vfe_hw->core_info = kzalloc(sizeof(struct cam_vfe_hw_core_info), + GFP_KERNEL); + if (!vfe_hw->core_info) { + CAM_DBG(CAM_ISP, "Failed to alloc for core"); + rc = -ENOMEM; + goto free_vfe_hw; + } + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "Of_match Failed"); + rc = -EINVAL; + goto free_core_info; + } + hw_info = (struct cam_vfe_hw_info *)match_dev->data; + core_info->vfe_hw_info = hw_info; + + rc = cam_vfe_init_soc_resources(&vfe_hw->soc_info, cam_vfe_irq, + vfe_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed to init soc rc=%d", rc); + goto free_core_info; + } + + rc = cam_vfe_core_init(core_info, &vfe_hw->soc_info, + vfe_hw_intf, hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed to init core rc=%d", rc); + goto deinit_soc; + } + + vfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&vfe_hw->hw_mutex); + spin_lock_init(&vfe_hw->hw_lock); + init_completion(&vfe_hw->hw_complete); + + if (vfe_hw_intf->hw_idx < CAM_VFE_HW_NUM_MAX) + cam_vfe_hw_list[vfe_hw_intf->hw_idx] = vfe_hw_intf; + + cam_vfe_init_hw(vfe_hw, NULL, 0); + cam_vfe_deinit_hw(vfe_hw, NULL, 0); + + CAM_DBG(CAM_ISP, "VFE%d probe successful", vfe_hw_intf->hw_idx); + + return rc; + +deinit_soc: + if (cam_vfe_deinit_soc_resources(&vfe_hw->soc_info)) + CAM_ERR(CAM_ISP, "Failed to deinit soc"); +free_core_info: + kfree(vfe_hw->core_info); +free_vfe_hw: + kfree(vfe_hw); +free_vfe_hw_intf: + kfree(vfe_hw_intf); +end: + return rc; +} + +int cam_vfe_remove(struct platform_device *pdev) +{ + struct cam_hw_info *vfe_hw = NULL; + struct cam_hw_intf *vfe_hw_intf = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + int rc = 0; + + vfe_hw_intf = platform_get_drvdata(pdev); + if (!vfe_hw_intf) { + CAM_ERR(CAM_ISP, "Error! No data in pdev"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "type %d index %d", + vfe_hw_intf->hw_type, vfe_hw_intf->hw_idx); + + if (vfe_hw_intf->hw_idx < CAM_VFE_HW_NUM_MAX) + cam_vfe_hw_list[vfe_hw_intf->hw_idx] = NULL; + + vfe_hw = vfe_hw_intf->hw_priv; + if (!vfe_hw) { + CAM_ERR(CAM_ISP, "Error! HW data is NULL"); + rc = -ENODEV; + goto free_vfe_hw_intf; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + if (!core_info) { + CAM_ERR(CAM_ISP, "Error! core data NULL"); + rc = -EINVAL; + goto deinit_soc; + } + + rc = cam_vfe_core_deinit(core_info, core_info->vfe_hw_info); + if (rc < 0) + CAM_ERR(CAM_ISP, "Failed to deinit core rc=%d", rc); + + kfree(vfe_hw->core_info); + +deinit_soc: + rc = cam_vfe_deinit_soc_resources(&vfe_hw->soc_info); + if (rc < 0) + CAM_ERR(CAM_ISP, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&vfe_hw->hw_mutex); + kfree(vfe_hw); + + CAM_DBG(CAM_ISP, "VFE%d remove successful", vfe_hw_intf->hw_idx); + +free_vfe_hw_intf: + kfree(vfe_hw_intf); + + return rc; +} + +int cam_vfe_hw_init(struct cam_hw_intf **vfe_hw, uint32_t hw_idx) +{ + int rc = 0; + + if (cam_vfe_hw_list[hw_idx]) { + *vfe_hw = cam_vfe_hw_list[hw_idx]; + rc = 0; + } else { + *vfe_hw = NULL; + rc = -ENODEV; + } + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h new file mode 100644 index 000000000000..c2d78b69c684 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_DEV_H_ +#define _CAM_VFE_DEV_H_ + +#include + +/* + * cam_vfe_probe() + * + * @brief: Driver probe function called on Boot + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_probe(struct platform_device *pdev); + +/* + * cam_vfe_remove() + * + * @brief: Driver remove function + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_remove(struct platform_device *pdev); + +#endif /* _CAM_VFE_DEV_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c new file mode 100644 index 000000000000..cf899e97f326 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_cpas_api.h" +#include "cam_vfe_soc.h" +#include "cam_debug_util.h" + +static bool cam_vfe_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + bool error_handled = false; + + if (!irq_data) + return error_handled; + + switch (irq_data->irq_type) { + case CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ISP, + "IFE UBWC Encode error type=%d status=%x", + irq_data->irq_type, + irq_data->u.enc_err.encerr_status.value); + error_handled = true; + break; + default: + break; + } + + return error_handled; +} + +static int cam_vfe_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0, num_ubwc_cfg = 0, i = 0; + struct device_node *of_node = NULL; + struct platform_device *pdev = NULL; + struct cam_vfe_soc_private *vfe_soc_private; + + pdev = soc_info->pdev; + of_node = pdev->dev.of_node; + vfe_soc_private = soc_info->soc_private; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "Error! get DT properties failed rc=%d", rc); + return rc; + } + + vfe_soc_private->is_ife_lite = false; + if (strnstr(soc_info->compatible, "lite", + strlen(soc_info->compatible)) != NULL) { + vfe_soc_private->is_ife_lite = true; + goto end; + } + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_480_V100: + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-static-cfg"); + + if (num_ubwc_cfg < 0 || num_ubwc_cfg > UBWC_STATIC_CONFIG_MAX) { + CAM_ERR(CAM_ISP, "wrong num_ubwc_cfg: %d", + num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, + "ubwc-static-cfg", i, + &vfe_soc_private->ubwc_static_ctrl[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "unable to read ubwc static config"); + break; + } + } + break; + default: + break; + } + +end: + return rc; +} + +static int cam_vfe_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, vfe_irq_handler, + irq_data); + if (rc) + CAM_ERR(CAM_ISP, + "Error! Request platform resource failed rc=%d", rc); + + return rc; +} + +static int cam_vfe_release_platform_resource(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_ISP, + "Error! Release platform resource failed rc=%d", rc); + + return rc; +} + +int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + + soc_private = kzalloc(sizeof(struct cam_vfe_soc_private), + GFP_KERNEL); + if (!soc_private) { + CAM_DBG(CAM_ISP, "Error! soc_private Alloc Failed"); + return -ENOMEM; + } + soc_info->soc_private = soc_private; + + rc = cam_cpas_get_cpas_hw_version(&soc_private->cpas_version); + if (rc) { + CAM_ERR(CAM_ISP, "Error! Invalid cpas version rc=%d", rc); + goto free_soc_private; + } + soc_info->hw_version = soc_private->cpas_version; + + rc = cam_vfe_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Error! Get DT properties failed rc=%d", rc); + goto free_soc_private; + } + + rc = cam_soc_util_get_option_clk_by_name(soc_info, + CAM_VFE_DSP_CLK_NAME, &soc_private->dsp_clk, + &soc_private->dsp_clk_index, &soc_private->dsp_clk_rate); + if (rc) + CAM_WARN(CAM_ISP, "Option clk get failed with rc %d", rc); + + rc = cam_vfe_request_platform_resource(soc_info, vfe_irq_handler, + irq_data); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Error! Request platform resources failed rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "ife", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + cpas_register_param.cam_cpas_client_cb = cam_vfe_cpas_cb; + cpas_register_param.userdata = soc_info; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } else { + soc_private->cpas_handle = cpas_register_param.client_handle; + } + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); +free_soc_private: + kfree(soc_private); + + return rc; +} + +int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! soc_info NULL"); + return -ENODEV; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + return -ENODEV; + } + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + + rc = cam_vfe_release_platform_resource(soc_info); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Error! Release platform resources failed rc=%d", rc); + + rc = cam_soc_util_clk_put(&soc_private->dsp_clk); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Error Put dsp clk failed rc=%d", rc); + + kfree(soc_private); + + return rc; +} + +int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid params"); + rc = -EINVAL; + goto end; + } + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + if (strnstr(soc_info->compatible, "lite", + strlen(soc_info->compatible))) { + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_RDI1; + } else { + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; + } + + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = 10640000000L; + axi_vote.axi_path[0].mnoc_ab_bw = 10640000000L; + axi_vote.axi_path[0].mnoc_ib_bw = 10640000000L; + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS start failed rc=%d", rc); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_TURBO_VOTE, true); + if (rc) { + CAM_ERR(CAM_ISP, "Error! enable platform failed rc=%d", rc); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + if (strcmp(clk_name, CAM_VFE_DSP_CLK_NAME) == 0) { + rc = cam_soc_util_clk_enable(soc_private->dsp_clk, + CAM_VFE_DSP_CLK_NAME, soc_private->dsp_clk_rate); + if (rc) + CAM_ERR(CAM_ISP, + "Error enable dsp clk failed rc=%d", rc); + } + + return rc; +} + +int cam_vfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + if (strcmp(clk_name, CAM_VFE_DSP_CLK_NAME) == 0) { + rc = cam_soc_util_clk_disable(soc_private->dsp_clk, + CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, + "Error enable dsp clk failed rc=%d", rc); + } + + return rc; +} + + +int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_ISP, "Disable platform failed rc=%d", rc); + return rc; + } + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h new file mode 100644 index 000000000000..64d9de084ec1 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_SOC_H_ +#define _CAM_VFE_SOC_H_ + +#include "cam_soc_util.h" +#include "cam_isp_hw.h" + +#define CAM_VFE_DSP_CLK_NAME "ife_dsp_clk" + +#define UBWC_STATIC_CONFIG_MAX 2 + +/* + * struct cam_vfe_soc_private: + * + * @Brief: Private SOC data specific to VFE HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + * @cpas_version: Has cpas version read from Hardware + * @ubwc_static_ctrl: UBWC static control configuration + * @is_ife_lite: Flag to indicate full vs lite IFE + */ +struct cam_vfe_soc_private { + uint32_t cpas_handle; + uint32_t cpas_version; + struct clk *dsp_clk; + int32_t dsp_clk_index; + int32_t dsp_clk_rate; + uint32_t ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX]; + bool is_ife_lite; +}; + +/* + * cam_vfe_init_soc_resources() + * + * @Brief: Initialize SOC resources including private data + * + * @soc_info: Device soc information + * @handler: Irq handler function pointer + * @irq_data: Irq handler function Callback data + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data); + +/* + * cam_vfe_deinit_soc_resources() + * + * @Brief: Deinitialize SOC resources including private data + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_vfe_enable_soc_resources() + * + * @brief: Enable regulator, irq resources, start CPAS + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_vfe_disable_soc_resources() + * + * @brief: Disable regulator, irq resources, stop CPAS + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_vfe_soc_enable_clk() + * + * @brief: Enable clock with given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +/* + * cam_vfe_soc_disable_dsp_clk() + * + * @brief: Disable clock with given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +#endif /* _CAM_VFE_SOC_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile new file mode 100644 index 000000000000..e129ea6999b0 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c new file mode 100644 index 000000000000..5336352a4797 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_vfe170.h" +#include "cam_vfe175.h" +#include "cam_vfe175_130.h" +#include "cam_vfe480.h" +#include "cam_vfe_lite17x.h" +#include "cam_vfe_lite48x.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_core.h" +#include "cam_vfe_dev.h" + +static const struct of_device_id cam_vfe_dt_match[] = { + { + .compatible = "qcom,vfe170", + .data = &cam_vfe170_hw_info, + }, + { + .compatible = "qcom,vfe175", + .data = &cam_vfe175_hw_info, + }, + { + .compatible = "qcom,vfe175_130", + .data = &cam_vfe175_130_hw_info, + }, + { + .compatible = "qcom,vfe480", + .data = &cam_vfe480_hw_info, + }, + { + .compatible = "qcom,vfe-lite170", + .data = &cam_vfe_lite17x_hw_info, + }, + { + .compatible = "qcom,vfe-lite175", + .data = &cam_vfe_lite17x_hw_info, + }, + { + .compatible = "qcom,vfe-lite480", + .data = &cam_vfe_lite48x_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_vfe_dt_match); + +static struct platform_driver cam_vfe_driver = { + .probe = cam_vfe_probe, + .remove = cam_vfe_remove, + .driver = { + .name = "cam_vfe", + .owner = THIS_MODULE, + .of_match_table = cam_vfe_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_vfe_init_module(void) +{ + return platform_driver_register(&cam_vfe_driver); +} + +static void __exit cam_vfe_exit_module(void) +{ + platform_driver_unregister(&cam_vfe_driver); +} + +module_init(cam_vfe_init_module); +module_exit(cam_vfe_exit_module); +MODULE_DESCRIPTION("CAM VFE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h new file mode 100644 index 000000000000..748c324f5496 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -0,0 +1,843 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE170_H_ +#define _CAM_VFE170_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe170_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe170_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe170_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_170_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0x0FFF7E80, + .enable_diagnostic_hw = 0x1, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_170_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_170_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_170_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_170_reg, + &stats_170_reg, + &color_170_reg, + &zoom_170_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe170_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { + .common_reg = &vfe170_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe170_top_common_reg, + .camif_reg = &vfe170_camif_reg, + .reg_data = &vfe_170_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = NULL, + .camif_lite_reg = NULL, + .reg_data = NULL, + }, + .rdi_hw_info = { + .common_reg = &vfe170_top_common_reg, + .rdi_reg = &vfe170_rdi_reg, + .reg_data = { + &vfe_170_rdi_0_data, + &vfe_170_rdi_1_data, + &vfe_170_rdi_2_data, + NULL, + }, + }, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe170_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + .debug_status_cfg = 0x0000226C, + .debug_status_0 = 0x00002270, + }, + .num_client = 20, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = &ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = &ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 18, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe170_hw_info = { + .irq_reg_info = &vfe170_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe170_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe170_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe170_camif_reg, + + .camif_lite_version = 0, + .camif_reg = NULL, + +}; + +#endif /* _CAM_VFE170_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h new file mode 100644 index 000000000000..db61bfbdc84b --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -0,0 +1,1013 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE175_H_ +#define _CAM_VFE175_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe175_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe175_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe175_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe175_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_175_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .subscribe_irq_mask0 = 0x00000017, + .subscribe_irq_mask1 = 0x00000000, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_camif_lite_ver2_reg vfe175_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data vfe175_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_err_irq_mask0 = 0x00400000, + .lite_err_irq_mask1 = 0x00004100, + .lite_subscribe_irq_mask0 = 0x001C0000, + .lite_subscribe_irq_mask1 = 0x0, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe175_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_175_reg, + &stats_175_reg, + &color_175_reg, + &zoom_175_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe175_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_common_reg_data vfe175_rdi_reg_data = { + .subscribe_irq_mask0 = 0x780001E0, + .subscribe_irq_mask1 = 0x0, + .error_irq_mask0 = 0x0, + .error_irq_mask1 = 0x3C, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_reg = &vfe175_camif_reg, + .reg_data = &vfe_175_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_lite_reg = &vfe175_camif_lite_reg, + .reg_data = &vfe175_camif_lite_reg_data, + }, + .rdi_hw_info = { + .common_reg = &vfe175_top_common_reg, + .rdi_reg = &vfe175_rdi_reg, + .common_reg_data = &vfe175_rdi_reg_data, + .reg_data = { + &vfe_175_rdi_0_data, + &vfe_175_rdi_1_data, + &vfe_175_rdi_2_data, + NULL, + }, + }, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, + }, +}; + +static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe175_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + .debug_status_cfg = 0x0000226C, + .debug_status_0 = 0x00002270, + }, + .num_client = 24, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = &vfe175_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = &vfe175_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = &vfe175_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = &vfe175_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 22, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe175_hw_info = { + .irq_reg_info = &vfe175_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe175_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe175_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe175_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_camif_lite_reg, + +}; + +#endif /* _CAM_VFE175_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h new file mode 100644 index 000000000000..03a6409324d8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -0,0 +1,1121 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE175_130_H_ +#define _CAM_VFE175_130_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe175_130_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe175_130_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe175_130_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe175_130_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_175_130_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .subscribe_irq_mask0 = 0x00000017, + .subscribe_irq_mask1 = 0x00000000, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_fe_ver1_reg vfe175_130_fe_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, + .fe_cfg = 0x00000084, +}; + +static struct cam_vfe_fe_reg_data vfe_175_130_fe_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .enable_diagnostic_hw = 0x1, + .fe_mux_data = 0x2, + .hbi_cnt_shift = 0x8, +}; + +static struct cam_vfe_camif_lite_ver2_reg vfe175_130_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data + vfe175_130_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_err_irq_mask0 = 0x00400000, + .lite_err_irq_mask1 = 0x00004100, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_130_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_130_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_130_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_130_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe175_130_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_175_130_reg, + &stats_175_130_reg, + &color_175_130_reg, + &zoom_175_130_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe175_130_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_common_reg_data vfe175_130_rdi_reg_data = { + .subscribe_irq_mask0 = 0x780001E0, + .subscribe_irq_mask1 = 0x0, + .error_irq_mask0 = 0x0, + .error_irq_mask1 = 0x3C, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_reg = &vfe175_130_camif_reg, + .reg_data = &vfe_175_130_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + .reg_data = &vfe175_130_camif_lite_reg_data, + }, + .rdi_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .rdi_reg = &vfe175_130_rdi_reg, + .common_reg_data = &vfe175_130_rdi_reg_data, + .reg_data = { + &vfe_175_130_rdi_0_data, + &vfe_175_130_rdi_1_data, + &vfe_175_130_rdi_2_data, + NULL, + }, + }, + .fe_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .fe_reg = &vfe175_130_fe_reg, + .reg_data = &vfe_175_130_fe_reg_data, + }, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, + CAM_VFE_IN_RD_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_rd_irq_reg[1] = { + { + .mask_reg_offset = 0x00005010, + .clear_reg_offset = 0x00005014, + .status_reg_offset = 0x0000501C, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, +}; + +static struct cam_vfe_bus_rd_ver1_hw_info vfe175_130_bus_rd_hw_info = { + .common_reg = { + .hw_version = 0x00005000, + .hw_capability = 0x00005004, + .sw_reset = 0x00005008, + .cgc_ovd = 0x0000500C, + .pwr_iso_cfg = 0x000050CC, + .input_if_cmd = 0x00005020, + .test_bus_ctrl = 0x00005048, + .irq_reg_info = { + .num_registers = 1, + .irq_reg_set = vfe175_130_bus_rd_irq_reg, + .global_clear_offset = 0x00005018, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 1, + .bus_client_reg = { + /* BUS Client 0 */ + { + .cfg = 0x00005050, + .image_addr = 0x00005058, + .buf_size = 0x0000505C, + .stride = 0x00005060, + .unpacker_cfg = 0x00005064, + .latency_buf_allocation = 0x00005078, + .burst_limit = 0x00005080, + }, + }, + .num_bus_rd_resc = 1, + .vfe_bus_rd_hw_info = { + { + .vfe_bus_rd_type = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe175_130_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + .debug_status_cfg = 0x0000226C, + .debug_status_0 = 0x00002270, + }, + .num_client = 24, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 22, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe175_130_hw_info = { + .irq_reg_info = &vfe175_130_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe175_130_bus_hw_info, + + .bus_rd_version = CAM_VFE_BUS_RD_VER_1_0, + .bus_rd_hw_info = &vfe175_130_bus_rd_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe175_130_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe175_130_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + +}; + +#endif /* _CAM_VFE175_130_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h new file mode 100644 index 000000000000..e855a54dc723 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -0,0 +1,1360 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_VFE480_H_ +#define _CAM_VFE480_H_ +#include "cam_vfe_camif_ver3.h" +#include "cam_vfe_top_ver3.h" +#include "cam_vfe_core.h" +#include "cam_vfe_bus_ver3.h" +#include "cam_irq_controller.h" + +static struct cam_irq_register_set vfe480_top_irq_reg_set[3] = { + { + .mask_reg_offset = 0x0000003C, + .clear_reg_offset = 0x00000048, + .status_reg_offset = 0x00000054, + }, + { + .mask_reg_offset = 0x00000040, + .clear_reg_offset = 0x0000004C, + .status_reg_offset = 0x00000058, + }, + { + .mask_reg_offset = 0x00000044, + .clear_reg_offset = 0x00000050, + .status_reg_offset = 0x0000005C, + }, +}; + +static struct cam_irq_controller_reg_info vfe480_top_irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe480_top_irq_reg_set, + .global_clear_offset = 0x00000038, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver3_pp_clc_reg vfe480_camif_reg = { + .hw_version = 0x00002600, + .hw_status = 0x00002604, + .module_cfg = 0x00002660, + .pdaf_raw_crop_width_cfg = 0x00002668, + .pdaf_raw_crop_height_cfg = 0x0000266C, + .line_skip_pattern = 0x00002670, + .pixel_skip_pattern = 0x00002674, + .period_cfg = 0x00002678, + .irq_subsample_pattern = 0x0000267C, + .epoch_irq_cfg = 0x00002680, + .debug_1 = 0x000027F0, + .debug_0 = 0x000027F4, + .test_bus_ctrl = 0x000027F8, + .spare = 0x000027FC, + .reg_update_cmd = 0x00000034, +}; + +static struct cam_vfe_camif_ver3_reg_data vfe_480_camif_reg_data = { + .pp_extern_reg_update_shift = 4, + .dual_pd_extern_reg_update_shift = 17, + .extern_reg_update_mask = 1, + .dual_ife_pix_en_shift = 3, + .operating_mode_shift = 11, + .input_mux_sel_shift = 5, + .pixel_pattern_shift = 24, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 24, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 23, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x41, + .epoch_line_cfg = 0x00000014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .epoch1_irq_mask = 0x00000008, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x82000200, + .error_irq_mask2 = 0x30301F80, + .subscribe_irq_mask1 = 0x00000007, + .enable_diagnostic_hw = 0x1, + .pp_camif_cfg_en_shift = 0, + .pp_camif_cfg_ife_out_en_shift = 8, +}; + +static struct cam_vfe_top_ver3_reg_offset_common vfe480_top_common_reg = { + .hw_version = 0x00000000, + .titan_version = 0x00000004, + .hw_capability = 0x00000008, + .lens_feature = 0x0000000C, + .stats_feature = 0x00000010, + .color_feature = 0x00000014, + .zoom_feature = 0x00000018, + .global_reset_cmd = 0x0000001C, + .core_cfg_0 = 0x0000002C, + .core_cfg_1 = 0x00000030, + .reg_update_cmd = 0x00000034, + .violation_status = 0x00000074, + .core_cgc_ovd_0 = 0x00000020, + .core_cgc_ovd_1 = 0x00000094, + .ahb_cgc_ovd = 0x00000024, + .noc_cgc_ovd = 0x00000028, + .trigger_cdm_events = 0x00000090, + .sbi_frame_idx = 0x00000110, + .dsp_status = 0x0000007C, + .diag_config = 0x00000064, + .diag_sensor_status_0 = 0x00000068, + .diag_sensor_status_1 = 0x00000098, + .bus_overflow_status = 0x0000AA68, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe480_camif_rdi[3] = { + { + .lite_hw_version = 0x9A00, + .lite_hw_status = 0x9A04, + .lite_module_config = 0x9A60, + .lite_skip_period = 0x9A68, + .lite_irq_subsample_pattern = 0x9A6C, + .lite_epoch_irq = 0x9A70, + .lite_debug_1 = 0x9BF0, + .lite_debug_0 = 0x9BF4, + .lite_test_bus_ctrl = 0x9BF8, + .camif_lite_spare = 0x9BFC, + .reg_update_cmd = 0x34, + }, + { + .lite_hw_version = 0x9C00, + .lite_hw_status = 0x9C04, + .lite_module_config = 0x9C60, + .lite_skip_period = 0x9C68, + .lite_irq_subsample_pattern = 0x9C6C, + .lite_epoch_irq = 0x9C70, + .lite_debug_1 = 0x9DF0, + .lite_debug_0 = 0x9DF4, + .lite_test_bus_ctrl = 0x9DF8, + .camif_lite_spare = 0x9DFC, + .reg_update_cmd = 0x34, + }, + { + .lite_hw_version = 0x9E00, + .lite_hw_status = 0x9E04, + .lite_module_config = 0x9E60, + .lite_skip_period = 0x9E68, + .lite_irq_subsample_pattern = 0x9E6C, + .lite_epoch_irq = 0x9E70, + .lite_debug_1 = 0x9FF0, + .lite_debug_0 = 0x9FF4, + .lite_test_bus_ctrl = 0x9FF8, + .camif_lite_spare = 0x9FFC, + .reg_update_cmd = 0x34, + }, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe480_camif_rdi_reg_data[3] = { + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x2, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x10, + .epoch0_irq_mask = 0x40, + .epoch1_irq_mask = 0x80, + .eof_irq_mask = 0x20, + .error_irq_mask0 = 0x20000000, + .error_irq_mask2 = 0x20000, + .subscribe_irq_mask1 = 0x30, + .enable_diagnostic_hw = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x4, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x100, + .epoch0_irq_mask = 0x400, + .epoch1_irq_mask = 0x800, + .eof_irq_mask = 0x200, + .error_irq_mask0 = 0x10000000, + .error_irq_mask2 = 0x40000, + .subscribe_irq_mask1 = 0x300, + .enable_diagnostic_hw = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x8, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x1000, + .epoch0_irq_mask = 0x4000, + .epoch1_irq_mask = 0x8000, + .eof_irq_mask = 0x2000, + .error_irq_mask0 = 0x8000000, + .error_irq_mask2 = 0x80000, + .subscribe_irq_mask1 = 0x3000, + .enable_diagnostic_hw = 0x1, + }, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe480_camif_lcr = { + .lite_hw_version = 0xA000, + .lite_hw_status = 0xA004, + .lite_module_config = 0xA060, + .lite_skip_period = 0xA068, + .lite_irq_subsample_pattern = 0xA06C, + .lite_epoch_irq = 0xA070, + .lite_debug_1 = 0xA1F0, + .lite_debug_0 = 0xA1F4, + .lite_test_bus_ctrl = 0xA1F8, + .camif_lite_spare = 0xA1FC, + .reg_update_cmd = 0x0034, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe480_camif_lcr_reg_data = { + .extern_reg_update_shift = 16, + .reg_update_cmd_data = 0x40, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x100000, + .epoch0_irq_mask = 0x400000, + .epoch1_irq_mask = 0x800000, + .eof_irq_mask = 0x200000, + .error_irq_mask0 = 0x0, + .error_irq_mask2 = 0x18000, + .subscribe_irq_mask1 = 0x300000, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe480_camif_pd = { + .lite_hw_version = 0xA400, + .lite_hw_status = 0xA404, + .lite_module_config = 0xA460, + .lite_skip_period = 0xA468, + .lite_irq_subsample_pattern = 0xA46C, + .lite_epoch_irq = 0xA470, + .lite_debug_1 = 0xA5F0, + .lite_debug_0 = 0xA5F4, + .lite_test_bus_ctrl = 0xA5F8, + .camif_lite_spare = 0xA5FC, + .reg_update_cmd = 0x0034, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe480_camif_pd_reg_data = { + .extern_reg_update_shift = 17, + .operating_mode_shift = 13, + .input_mux_sel_shift = 31, + .reg_update_cmd_data = 0x20, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x10000, + .epoch0_irq_mask = 0x40000, + .epoch1_irq_mask = 0x80000, + .eof_irq_mask = 0x20000, + .error_irq_mask0 = 0x40000000, + .error_irq_mask2 = 0x6000, + .subscribe_irq_mask1 = 0x30000, + .enable_diagnostic_hw = 0x1, +}; + +struct cam_vfe_camif_lite_ver3_hw_info rdi_hw_info_arr[CAM_VFE_RDI_VER2_MAX] = { + { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_rdi[0], + .reg_data = &vfe480_camif_rdi_reg_data[0], + }, + { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_rdi[1], + .reg_data = &vfe480_camif_rdi_reg_data[1], + }, + { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_rdi[2], + .reg_data = &vfe480_camif_rdi_reg_data[2], + }, +}; + +static struct cam_vfe_top_ver3_hw_info vfe480_top_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_reg = &vfe480_camif_reg, + .reg_data = &vfe_480_camif_reg_data, + }, + .pdlib_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_pd, + .reg_data = &vfe480_camif_pd_reg_data, + }, + .rdi_hw_info[0] = &rdi_hw_info_arr[0], + .rdi_hw_info[1] = &rdi_hw_info_arr[1], + .rdi_hw_info[2] = &rdi_hw_info_arr[2], + .lcr_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_lcr, + .reg_data = &vfe480_camif_lcr_reg_data, + }, + .mux_type = { + CAM_VFE_CAMIF_VER_3_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_PDLIB_VER_1_0, + CAM_VFE_LCR_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe480_bus_irq_reg[2] = { + { + .mask_reg_offset = 0x0000AA18, + .clear_reg_offset = 0x0000AA20, + .status_reg_offset = 0x0000AA28, + }, + { + .mask_reg_offset = 0x0000AA1C, + .clear_reg_offset = 0x0000AA24, + .status_reg_offset = 0x0000AA2C, + }, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_0 = { + .meta_addr = 0x0000AC40, + .meta_cfg = 0x0000AC44, + .mode_cfg = 0x0000AC48, + .stats_ctrl = 0x0000AC4C, + .ctrl_2 = 0x0000AC50, + .lossy_thresh0 = 0x0000AC54, + .lossy_thresh1 = 0x0000AC58, + .off_lossy_var = 0x0000AC5C, + .bw_limit = 0x0000AC1C, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_1 = { + .meta_addr = 0x0000AD40, + .meta_cfg = 0x0000AD44, + .mode_cfg = 0x0000AD48, + .stats_ctrl = 0x0000AD4C, + .ctrl_2 = 0x0000AD50, + .lossy_thresh0 = 0x0000AD54, + .lossy_thresh1 = 0x0000AD58, + .off_lossy_var = 0x0000AD5C, + .bw_limit = 0x0000AD1C, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_4 = { + .meta_addr = 0x0000B040, + .meta_cfg = 0x0000B044, + .mode_cfg = 0x0000B048, + .stats_ctrl = 0x0000B04C, + .ctrl_2 = 0x0000B050, + .lossy_thresh0 = 0x0000B054, + .lossy_thresh1 = 0x0000B058, + .off_lossy_var = 0x0000B05C, + .bw_limit = 0x0000B01C, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_5 = { + .meta_addr = 0x0000B140, + .meta_cfg = 0x0000B144, + .mode_cfg = 0x0000B148, + .stats_ctrl = 0x0000B14C, + .ctrl_2 = 0x0000B150, + .lossy_thresh0 = 0x0000B154, + .lossy_thresh1 = 0x0000B158, + .off_lossy_var = 0x0000B15C, + .bw_limit = 0x0000B11C, +}; + +static struct cam_vfe_bus_ver3_hw_info vfe480_bus_hw_info = { + .common_reg = { + .hw_version = 0x0000AA00, + .cgc_ovd = 0x0000AA08, + .comp_cfg_0 = 0x0000AA0C, + .comp_cfg_1 = 0x0000AA10, + .if_frameheader_cfg = { + 0x0000AA34, + 0x0000AA38, + 0x0000AA3C, + 0x0000AA40, + 0x0000AA44, + 0x0000AA48, + }, + .ubwc_static_ctrl = 0x0000AA58, + .pwr_iso_cfg = 0x0000AA5C, + .overflow_status_clear = 0x0000AA60, + .ccif_violation_status = 0x0000AA64, + .overflow_status = 0x0000AA68, + .image_size_violation_status = 0x0000AA70, + .debug_status_top_cfg = 0x0000AAD4, + .debug_status_top = 0x0000AAD8, + .test_bus_ctrl = 0x0000AADC, + .irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe480_bus_irq_reg, + .global_clear_offset = 0x0000AA30, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = CAM_VFE_BUS_VER3_MAX_CLIENTS, + .bus_client_reg = { + /* BUS Client 0 FULL Y */ + { + .cfg = 0x0000AC00, + .image_addr = 0x0000AC04, + .frame_incr = 0x0000AC08, + .image_cfg_0 = 0x0000AC0C, + .image_cfg_1 = 0x0000AC10, + .image_cfg_2 = 0x0000AC14, + .packer_cfg = 0x0000AC18, + .frame_header_addr = 0x0000AC20, + .frame_header_incr = 0x0000AC24, + .frame_header_cfg = 0x0000AC28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AC30, + .irq_subsample_pattern = 0x0000AC34, + .framedrop_period = 0x0000AC38, + .framedrop_pattern = 0x0000AC3C, + .system_cache_cfg = 0x0000AC60, + .burst_limit = 0x0000AC64, + .addr_status_0 = 0x0000AC68, + .addr_status_1 = 0x0000AC6C, + .addr_status_2 = 0x0000AC70, + .addr_status_3 = 0x0000AC74, + .debug_status_cfg = 0x0000AC78, + .debug_status_0 = 0x0000AC7C, + .debug_status_1 = 0x0000AC80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = &vfe480_ubwc_regs_client_0, + }, + /* BUS Client 1 FULL C */ + { + .cfg = 0x0000AD00, + .image_addr = 0x0000AD04, + .frame_incr = 0x0000AD08, + .image_cfg_0 = 0x0000AD0C, + .image_cfg_1 = 0x0000AD10, + .image_cfg_2 = 0x0000AD14, + .packer_cfg = 0x0000AD18, + .frame_header_addr = 0x0000AD20, + .frame_header_incr = 0x0000AD24, + .frame_header_cfg = 0x0000AD28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AD30, + .irq_subsample_pattern = 0x0000AD34, + .framedrop_period = 0x0000AD38, + .framedrop_pattern = 0x0000AD3C, + .system_cache_cfg = 0x0000AD60, + .burst_limit = 0x0000AD64, + .addr_status_0 = 0x0000AD68, + .addr_status_1 = 0x0000AD6C, + .addr_status_2 = 0x0000AD70, + .addr_status_3 = 0x0000AD74, + .debug_status_cfg = 0x0000AD78, + .debug_status_0 = 0x0000AD7C, + .debug_status_1 = 0x0000AD80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = &vfe480_ubwc_regs_client_1, + }, + /* BUS Client 2 DS4 */ + { + .cfg = 0x0000AE00, + .image_addr = 0x0000AE04, + .frame_incr = 0x0000AE08, + .image_cfg_0 = 0x0000AE0C, + .image_cfg_1 = 0x0000AE10, + .image_cfg_2 = 0x0000AE14, + .packer_cfg = 0x0000AE18, + .frame_header_addr = 0x0000AE20, + .frame_header_incr = 0x0000AE24, + .frame_header_cfg = 0x0000AE28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AE30, + .irq_subsample_pattern = 0x0000AE34, + .framedrop_period = 0x0000AE38, + .framedrop_pattern = 0x0000AE3C, + .system_cache_cfg = 0x0000AE60, + .burst_limit = 0x0000AE64, + .addr_status_0 = 0x0000AE68, + .addr_status_1 = 0x0000AE6C, + .addr_status_2 = 0x0000AE70, + .addr_status_3 = 0x0000AE74, + .debug_status_cfg = 0x0000AE78, + .debug_status_0 = 0x0000AE7C, + .debug_status_1 = 0x0000AE80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = NULL, + }, + /* BUS Client 3 DS16 */ + { + .cfg = 0x0000AF00, + .image_addr = 0x0000AF04, + .frame_incr = 0x0000AF08, + .image_cfg_0 = 0x0000AF0C, + .image_cfg_1 = 0x0000AF10, + .image_cfg_2 = 0x0000AF14, + .packer_cfg = 0x0000AF18, + .frame_header_addr = 0x0000AF20, + .frame_header_incr = 0x0000AF24, + .frame_header_cfg = 0x0000AF28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AF30, + .irq_subsample_pattern = 0x0000AF34, + .framedrop_period = 0x0000AF38, + .framedrop_pattern = 0x0000AF3C, + .system_cache_cfg = 0x0000AF60, + .burst_limit = 0x0000AF64, + .addr_status_0 = 0x0000AF68, + .addr_status_1 = 0x0000AF6C, + .addr_status_2 = 0x0000AF70, + .addr_status_3 = 0x0000AF74, + .debug_status_cfg = 0x0000AF78, + .debug_status_0 = 0x0000AF7C, + .debug_status_1 = 0x0000AF80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = NULL, + }, + /* BUS Client 4 DISP Y */ + { + .cfg = 0x0000B000, + .image_addr = 0x0000B004, + .frame_incr = 0x0000B008, + .image_cfg_0 = 0x0000B00C, + .image_cfg_1 = 0x0000B010, + .image_cfg_2 = 0x0000B014, + .packer_cfg = 0x0000B018, + .frame_header_addr = 0x0000B020, + .frame_header_incr = 0x0000B024, + .frame_header_cfg = 0x0000B028, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B030, + .irq_subsample_pattern = 0x0000B034, + .framedrop_period = 0x0000B038, + .framedrop_pattern = 0x0000B03C, + .system_cache_cfg = 0x0000B060, + .burst_limit = 0x0000B064, + .addr_status_0 = 0x0000B068, + .addr_status_1 = 0x0000B06C, + .addr_status_2 = 0x0000B070, + .addr_status_3 = 0x0000B074, + .debug_status_cfg = 0x0000B078, + .debug_status_0 = 0x0000B07C, + .debug_status_1 = 0x0000B080, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = &vfe480_ubwc_regs_client_4, + }, + /* BUS Client 5 DISP C */ + { + .cfg = 0x0000B100, + .image_addr = 0x0000B104, + .frame_incr = 0x0000B108, + .image_cfg_0 = 0x0000B10C, + .image_cfg_1 = 0x0000B110, + .image_cfg_2 = 0x0000B114, + .packer_cfg = 0x0000B118, + .frame_header_addr = 0x0000B120, + .frame_header_incr = 0x0000B124, + .frame_header_cfg = 0x0000B128, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B130, + .irq_subsample_pattern = 0x0000B134, + .framedrop_period = 0x0000B138, + .framedrop_pattern = 0x0000B13C, + .system_cache_cfg = 0x0000B160, + .burst_limit = 0x0000B164, + .addr_status_0 = 0x0000B168, + .addr_status_1 = 0x0000B16C, + .addr_status_2 = 0x0000B170, + .addr_status_3 = 0x0000B174, + .debug_status_cfg = 0x0000B178, + .debug_status_0 = 0x0000B17C, + .debug_status_1 = 0x0000B180, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = &vfe480_ubwc_regs_client_5, + }, + /* BUS Client 6 DISP DS4 */ + { + .cfg = 0x0000B200, + .image_addr = 0x0000B204, + .frame_incr = 0x0000B208, + .image_cfg_0 = 0x0000B20C, + .image_cfg_1 = 0x0000B210, + .image_cfg_2 = 0x0000B214, + .packer_cfg = 0x0000B218, + .frame_header_addr = 0x0000B220, + .frame_header_incr = 0x0000B224, + .frame_header_cfg = 0x0000B228, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B230, + .irq_subsample_pattern = 0x0000B234, + .framedrop_period = 0x0000B238, + .framedrop_pattern = 0x0000B23C, + .system_cache_cfg = 0x0000B260, + .burst_limit = 0x0000B264, + .addr_status_0 = 0x0000B268, + .addr_status_1 = 0x0000B26C, + .addr_status_2 = 0x0000B270, + .addr_status_3 = 0x0000B274, + .debug_status_cfg = 0x0000B278, + .debug_status_0 = 0x0000B27C, + .debug_status_1 = 0x0000B280, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = NULL, + }, + /* BUS Client 7 DISP DS16 */ + { + .cfg = 0x0000B300, + .image_addr = 0x0000B304, + .frame_incr = 0x0000B308, + .image_cfg_0 = 0x0000B30C, + .image_cfg_1 = 0x0000B310, + .image_cfg_2 = 0x0000B314, + .packer_cfg = 0x0000B318, + .frame_header_addr = 0x0000B320, + .frame_header_incr = 0x0000B324, + .frame_header_cfg = 0x0000B328, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B330, + .irq_subsample_pattern = 0x0000B334, + .framedrop_period = 0x0000B338, + .framedrop_pattern = 0x0000B33C, + .system_cache_cfg = 0x0000B360, + .burst_limit = 0x0000B364, + .addr_status_0 = 0x0000B368, + .addr_status_1 = 0x0000B36C, + .addr_status_2 = 0x0000B370, + .addr_status_3 = 0x0000B374, + .debug_status_cfg = 0x0000B378, + .debug_status_0 = 0x0000B37C, + .debug_status_1 = 0x0000B380, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = NULL, + }, + /* BUS Client 8 FD Y */ + { + .cfg = 0x0000B400, + .image_addr = 0x0000B404, + .frame_incr = 0x0000B408, + .image_cfg_0 = 0x0000B40C, + .image_cfg_1 = 0x0000B410, + .image_cfg_2 = 0x0000B414, + .packer_cfg = 0x0000B418, + .frame_header_addr = 0x0000B420, + .frame_header_incr = 0x0000B424, + .frame_header_cfg = 0x0000B428, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B430, + .irq_subsample_pattern = 0x0000B434, + .framedrop_period = 0x0000B438, + .framedrop_pattern = 0x0000B43C, + .system_cache_cfg = 0x0000B460, + .burst_limit = 0x0000B464, + .addr_status_0 = 0x0000B468, + .addr_status_1 = 0x0000B46C, + .addr_status_2 = 0x0000B470, + .addr_status_3 = 0x0000B474, + .debug_status_cfg = 0x0000B478, + .debug_status_0 = 0x0000B47C, + .debug_status_1 = 0x0000B480, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_2, + .ubwc_regs = NULL, + }, + /* BUS Client 9 FD C */ + { + .cfg = 0x0000B500, + .image_addr = 0x0000B504, + .frame_incr = 0x0000B508, + .image_cfg_0 = 0x0000B50C, + .image_cfg_1 = 0x0000B510, + .image_cfg_2 = 0x0000B514, + .packer_cfg = 0x0000B518, + .frame_header_addr = 0x0000B520, + .frame_header_incr = 0x0000B524, + .frame_header_cfg = 0x0000B528, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B530, + .irq_subsample_pattern = 0x0000B534, + .framedrop_period = 0x0000B538, + .framedrop_pattern = 0x0000B53C, + .system_cache_cfg = 0x0000B560, + .burst_limit = 0x0000B564, + .addr_status_0 = 0x0000B568, + .addr_status_1 = 0x0000B56C, + .addr_status_2 = 0x0000B570, + .addr_status_3 = 0x0000B574, + .debug_status_cfg = 0x0000B578, + .debug_status_0 = 0x0000B57C, + .debug_status_1 = 0x0000B580, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_2, + .ubwc_regs = NULL, + }, + /* BUS Client 10 PIXEL RAW */ + { + .cfg = 0x0000B600, + .image_addr = 0x0000B604, + .frame_incr = 0x0000B608, + .image_cfg_0 = 0x0000B60C, + .image_cfg_1 = 0x0000B610, + .image_cfg_2 = 0x0000B614, + .packer_cfg = 0x0000B618, + .frame_header_addr = 0x0000B620, + .frame_header_incr = 0x0000B624, + .frame_header_cfg = 0x0000B628, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B630, + .irq_subsample_pattern = 0x0000B634, + .framedrop_period = 0x0000B638, + .framedrop_pattern = 0x0000B63C, + .system_cache_cfg = 0x0000B660, + .burst_limit = 0x0000B664, + .addr_status_0 = 0x0000B668, + .addr_status_1 = 0x0000B66C, + .addr_status_2 = 0x0000B670, + .addr_status_3 = 0x0000B674, + .debug_status_cfg = 0x0000B678, + .debug_status_0 = 0x0000B67C, + .debug_status_1 = 0x0000B680, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_3, + .ubwc_regs = NULL, + }, + /* BUS Client 11 CAMIF PD */ + { + .cfg = 0x0000B700, + .image_addr = 0x0000B704, + .frame_incr = 0x0000B708, + .image_cfg_0 = 0x0000B70C, + .image_cfg_1 = 0x0000B710, + .image_cfg_2 = 0x0000B714, + .packer_cfg = 0x0000B718, + .frame_header_addr = 0x0000B720, + .frame_header_incr = 0x0000B724, + .frame_header_cfg = 0x0000B728, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B730, + .irq_subsample_pattern = 0x0000B734, + .framedrop_period = 0x0000B738, + .framedrop_pattern = 0x0000B73C, + .system_cache_cfg = 0x0000B760, + .burst_limit = 0x0000B764, + .addr_status_0 = 0x0000B768, + .addr_status_1 = 0x0000B76C, + .addr_status_2 = 0x0000B770, + .addr_status_3 = 0x0000B774, + .debug_status_cfg = 0x0000B778, + .debug_status_0 = 0x0000B77C, + .debug_status_1 = 0x0000B780, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_4, + .ubwc_regs = NULL, + }, + /* BUS Client 12 STATS HDR BE */ + { + .cfg = 0x0000B800, + .image_addr = 0x0000B804, + .frame_incr = 0x0000B808, + .image_cfg_0 = 0x0000B80C, + .image_cfg_1 = 0x0000B810, + .image_cfg_2 = 0x0000B814, + .packer_cfg = 0x0000B818, + .frame_header_addr = 0x0000B820, + .frame_header_incr = 0x0000B824, + .frame_header_cfg = 0x0000B828, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B830, + .irq_subsample_pattern = 0x0000B834, + .framedrop_period = 0x0000B838, + .framedrop_pattern = 0x0000B83C, + .system_cache_cfg = 0x0000B860, + .burst_limit = 0x0000B864, + .addr_status_0 = 0x0000B868, + .addr_status_1 = 0x0000B86C, + .addr_status_2 = 0x0000B870, + .addr_status_3 = 0x0000B874, + .debug_status_cfg = 0x0000B878, + .debug_status_0 = 0x0000B87C, + .debug_status_1 = 0x0000B880, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_5, + .ubwc_regs = NULL, + }, + /* BUS Client 13 STATS HDR BHIST */ + { + .cfg = 0x0000B900, + .image_addr = 0x0000B904, + .frame_incr = 0x0000B908, + .image_cfg_0 = 0x0000B90C, + .image_cfg_1 = 0x0000B910, + .image_cfg_2 = 0x0000B914, + .packer_cfg = 0x0000B918, + .frame_header_addr = 0x0000B920, + .frame_header_incr = 0x0000B924, + .frame_header_cfg = 0x0000B928, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B930, + .irq_subsample_pattern = 0x0000B934, + .framedrop_period = 0x0000B938, + .framedrop_pattern = 0x0000B93C, + .system_cache_cfg = 0x0000B960, + .burst_limit = 0x0000B964, + .addr_status_0 = 0x0000B968, + .addr_status_1 = 0x0000B96C, + .addr_status_2 = 0x0000B970, + .addr_status_3 = 0x0000B974, + .debug_status_cfg = 0x0000B978, + .debug_status_0 = 0x0000B97C, + .debug_status_1 = 0x0000B980, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_5, + .ubwc_regs = NULL, + }, + /* BUS Client 14 STATS TINTLESS BG */ + { + .cfg = 0x0000BA00, + .image_addr = 0x0000BA04, + .frame_incr = 0x0000BA08, + .image_cfg_0 = 0x0000BA0C, + .image_cfg_1 = 0x0000BA10, + .image_cfg_2 = 0x0000BA14, + .packer_cfg = 0x0000BA18, + .frame_header_addr = 0x0000BA20, + .frame_header_incr = 0x0000BA24, + .frame_header_cfg = 0x0000BA28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BA30, + .irq_subsample_pattern = 0x0000BA34, + .framedrop_period = 0x0000BA38, + .framedrop_pattern = 0x0000BA3C, + .system_cache_cfg = 0x0000BA60, + .burst_limit = 0x0000BA64, + .addr_status_0 = 0x0000BA68, + .addr_status_1 = 0x0000BA6C, + .addr_status_2 = 0x0000BA70, + .addr_status_3 = 0x0000BA74, + .debug_status_cfg = 0x0000BA78, + .debug_status_0 = 0x0000BA7C, + .debug_status_1 = 0x0000BA80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_6, + .ubwc_regs = NULL, + }, + /* BUS Client 15 STATS AWB BG */ + { + .cfg = 0x0000BB00, + .image_addr = 0x0000BB04, + .frame_incr = 0x0000BB08, + .image_cfg_0 = 0x0000BB0C, + .image_cfg_1 = 0x0000BB10, + .image_cfg_2 = 0x0000BB14, + .packer_cfg = 0x0000BB18, + .frame_header_addr = 0x0000BB20, + .frame_header_incr = 0x0000BB24, + .frame_header_cfg = 0x0000BB28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BB30, + .irq_subsample_pattern = 0x0000BB34, + .framedrop_period = 0x0000BB38, + .framedrop_pattern = 0x0000BB3C, + .system_cache_cfg = 0x0000BB60, + .burst_limit = 0x0000BB64, + .addr_status_0 = 0x0000BB68, + .addr_status_1 = 0x0000BB6C, + .addr_status_2 = 0x0000BB70, + .addr_status_3 = 0x0000BB74, + .debug_status_cfg = 0x0000BB78, + .debug_status_0 = 0x0000BB7C, + .debug_status_1 = 0x0000BB80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_6, + .ubwc_regs = NULL, + }, + /* BUS Client 16 STATS BHIST */ + { + .cfg = 0x0000BC00, + .image_addr = 0x0000BC04, + .frame_incr = 0x0000BC08, + .image_cfg_0 = 0x0000BC0C, + .image_cfg_1 = 0x0000BC10, + .image_cfg_2 = 0x0000BC14, + .packer_cfg = 0x0000BC18, + .frame_header_addr = 0x0000BC20, + .frame_header_incr = 0x0000BC24, + .frame_header_cfg = 0x0000BC28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BC30, + .irq_subsample_pattern = 0x0000BC34, + .framedrop_period = 0x0000BC38, + .framedrop_pattern = 0x0000BC3C, + .system_cache_cfg = 0x0000BC60, + .burst_limit = 0x0000BC64, + .addr_status_0 = 0x0000BC68, + .addr_status_1 = 0x0000BC6C, + .addr_status_2 = 0x0000BC70, + .addr_status_3 = 0x0000BC74, + .debug_status_cfg = 0x0000BC78, + .debug_status_0 = 0x0000BC7C, + .debug_status_1 = 0x0000BC80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 17 STATS RS */ + { + .cfg = 0x0000BD00, + .image_addr = 0x0000BD04, + .frame_incr = 0x0000BD08, + .image_cfg_0 = 0x0000BD0C, + .image_cfg_1 = 0x0000BD10, + .image_cfg_2 = 0x0000BD14, + .packer_cfg = 0x0000BD18, + .frame_header_addr = 0x0000BD20, + .frame_header_incr = 0x0000BD24, + .frame_header_cfg = 0x0000BD28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BD30, + .irq_subsample_pattern = 0x0000BD34, + .framedrop_period = 0x0000BD38, + .framedrop_pattern = 0x0000BD3C, + .system_cache_cfg = 0x0000BD60, + .burst_limit = 0x0000BD64, + .addr_status_0 = 0x0000BD68, + .addr_status_1 = 0x0000BD6C, + .addr_status_2 = 0x0000BD70, + .addr_status_3 = 0x0000BD74, + .debug_status_cfg = 0x0000BD78, + .debug_status_0 = 0x0000BD7C, + .debug_status_1 = 0x0000BD80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 18 STATS CS */ + { + .cfg = 0x0000BE00, + .image_addr = 0x0000BE04, + .frame_incr = 0x0000BE08, + .image_cfg_0 = 0x0000BE0C, + .image_cfg_1 = 0x0000BE10, + .image_cfg_2 = 0x0000BE14, + .packer_cfg = 0x0000BE18, + .frame_header_addr = 0x0000BE20, + .frame_header_incr = 0x0000BE24, + .frame_header_cfg = 0x0000BE28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BE30, + .irq_subsample_pattern = 0x0000BE34, + .framedrop_period = 0x0000BE38, + .framedrop_pattern = 0x0000BE3C, + .system_cache_cfg = 0x0000BE60, + .burst_limit = 0x0000BE64, + .addr_status_0 = 0x0000BE68, + .addr_status_1 = 0x0000BE6C, + .addr_status_2 = 0x0000BE70, + .addr_status_3 = 0x0000BE74, + .debug_status_cfg = 0x0000BE78, + .debug_status_0 = 0x0000BE7C, + .debug_status_1 = 0x0000BE80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 19 STATS IHIST */ + { + .cfg = 0x0000BF00, + .image_addr = 0x0000BF04, + .frame_incr = 0x0000BF08, + .image_cfg_0 = 0x0000BF0C, + .image_cfg_1 = 0x0000BF10, + .image_cfg_2 = 0x0000BF14, + .packer_cfg = 0x0000BF18, + .frame_header_addr = 0x0000BF20, + .frame_header_incr = 0x0000BF24, + .frame_header_cfg = 0x0000BF28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BF30, + .irq_subsample_pattern = 0x0000BF34, + .framedrop_period = 0x0000BF38, + .framedrop_pattern = 0x0000BF3C, + .system_cache_cfg = 0x0000BF60, + .burst_limit = 0x0000BF64, + .addr_status_0 = 0x0000BF68, + .addr_status_1 = 0x0000BF6C, + .addr_status_2 = 0x0000BF70, + .addr_status_3 = 0x0000BF74, + .debug_status_cfg = 0x0000BF78, + .debug_status_0 = 0x0000BF7C, + .debug_status_1 = 0x0000BF80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 20 STATS BF */ + { + .cfg = 0x0000C000, + .image_addr = 0x0000C004, + .frame_incr = 0x0000C008, + .image_cfg_0 = 0x0000C00C, + .image_cfg_1 = 0x0000C010, + .image_cfg_2 = 0x0000C014, + .packer_cfg = 0x0000C018, + .frame_header_addr = 0x0000C020, + .frame_header_incr = 0x0000C024, + .frame_header_cfg = 0x0000C028, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000C030, + .irq_subsample_pattern = 0x0000C034, + .framedrop_period = 0x0000C038, + .framedrop_pattern = 0x0000C03C, + .system_cache_cfg = 0x0000C060, + .burst_limit = 0x0000C064, + .addr_status_0 = 0x0000C068, + .addr_status_1 = 0x0000C06C, + .addr_status_2 = 0x0000C070, + .addr_status_3 = 0x0000C074, + .debug_status_cfg = 0x0000C078, + .debug_status_0 = 0x0000C07C, + .debug_status_1 = 0x0000C080, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_8, + .ubwc_regs = NULL, + }, + /* BUS Client 21 PDAF V2.0 */ + { + .cfg = 0x0000C100, + .image_addr = 0x0000C104, + .frame_incr = 0x0000C108, + .image_cfg_0 = 0x0000C10C, + .image_cfg_1 = 0x0000C110, + .image_cfg_2 = 0x0000C114, + .packer_cfg = 0x0000C118, + .frame_header_addr = 0x0000C120, + .frame_header_incr = 0x0000C124, + .frame_header_cfg = 0x0000C128, + .line_done_cfg = 0x0000C12C, + .irq_subsample_period = 0x0000C130, + .irq_subsample_pattern = 0x0000C134, + .framedrop_period = 0x0000C138, + .framedrop_pattern = 0x0000C13C, + .system_cache_cfg = 0x0000C160, + .burst_limit = 0x0000C164, + .addr_status_0 = 0x0000C168, + .addr_status_1 = 0x0000C16C, + .addr_status_2 = 0x0000C170, + .addr_status_3 = 0x0000C174, + .debug_status_cfg = 0x0000C178, + .debug_status_0 = 0x0000C17C, + .debug_status_1 = 0x0000C180, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_9, + .ubwc_regs = NULL, + }, + /* BUS Client 22 LCR */ + { + .cfg = 0x0000C200, + .image_addr = 0x0000C204, + .frame_incr = 0x0000C208, + .image_cfg_0 = 0x0000C20C, + .image_cfg_1 = 0x0000C210, + .image_cfg_2 = 0x0000C214, + .packer_cfg = 0x0000C218, + .frame_header_addr = 0x0000C220, + .frame_header_incr = 0x0000C224, + .frame_header_cfg = 0x0000C228, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000C230, + .irq_subsample_pattern = 0x0000C234, + .framedrop_period = 0x0000C238, + .framedrop_pattern = 0x0000C23C, + .system_cache_cfg = 0x0000C260, + .burst_limit = 0x0000C264, + .addr_status_0 = 0x0000C268, + .addr_status_1 = 0x0000C26C, + .addr_status_2 = 0x0000C270, + .addr_status_3 = 0x0000C274, + .debug_status_cfg = 0x0000C278, + .debug_status_0 = 0x0000C27C, + .debug_status_1 = 0x0000C280, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_10, + .ubwc_regs = NULL, + }, + /* BUS Client 23 RDI0 */ + { + .cfg = 0x0000C300, + .image_addr = 0x0000C304, + .frame_incr = 0x0000C308, + .image_cfg_0 = 0x0000C30C, + .image_cfg_1 = 0x0000C310, + .image_cfg_2 = 0x0000C314, + .packer_cfg = 0x0000C318, + .frame_header_addr = 0x0000C320, + .frame_header_incr = 0x0000C324, + .frame_header_cfg = 0x0000C328, + .line_done_cfg = 0x0000C32C, + .irq_subsample_period = 0x0000C330, + .irq_subsample_pattern = 0x0000C334, + .framedrop_period = 0x0000C338, + .framedrop_pattern = 0x0000C33C, + .system_cache_cfg = 0x0000C360, + .burst_limit = 0x0000C364, + .addr_status_0 = 0x0000C368, + .addr_status_1 = 0x0000C36C, + .addr_status_2 = 0x0000C370, + .addr_status_3 = 0x0000C374, + .debug_status_cfg = 0x0000C378, + .debug_status_0 = 0x0000C37C, + .debug_status_1 = 0x0000C380, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_11, + .ubwc_regs = NULL, + }, + /* BUS Client 24 RDI1 */ + { + .cfg = 0x0000C400, + .image_addr = 0x0000C404, + .frame_incr = 0x0000C408, + .image_cfg_0 = 0x0000C40C, + .image_cfg_1 = 0x0000C410, + .image_cfg_2 = 0x0000C414, + .packer_cfg = 0x0000C418, + .frame_header_addr = 0x0000C420, + .frame_header_incr = 0x0000C424, + .frame_header_cfg = 0x0000C428, + .line_done_cfg = 0x0000C42C, + .irq_subsample_period = 0x0000C430, + .irq_subsample_pattern = 0x0000C434, + .framedrop_period = 0x0000C438, + .framedrop_pattern = 0x0000C43C, + .system_cache_cfg = 0x0000C460, + .burst_limit = 0x0000C464, + .addr_status_0 = 0x0000C468, + .addr_status_1 = 0x0000C46C, + .addr_status_2 = 0x0000C470, + .addr_status_3 = 0x0000C474, + .debug_status_cfg = 0x0000C478, + .debug_status_0 = 0x0000C47C, + .debug_status_1 = 0x0000C480, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_12, + .ubwc_regs = NULL, + }, + /* BUS Client 25 RDI2 */ + { + .cfg = 0x0000C500, + .image_addr = 0x0000C504, + .frame_incr = 0x0000C508, + .image_cfg_0 = 0x0000C50C, + .image_cfg_1 = 0x0000C510, + .image_cfg_2 = 0x0000C514, + .packer_cfg = 0x0000C518, + .frame_header_addr = 0x0000C520, + .frame_header_incr = 0x0000C524, + .frame_header_cfg = 0x0000C528, + .line_done_cfg = 0x0000C52C, + .irq_subsample_period = 0x0000C530, + .irq_subsample_pattern = 0x0000C534, + .framedrop_period = 0x0000C538, + .framedrop_pattern = 0x0000C53C, + .system_cache_cfg = 0x0000C560, + .burst_limit = 0x0000C564, + .addr_status_0 = 0x0000C568, + .addr_status_1 = 0x0000C56C, + .addr_status_2 = 0x0000C570, + .addr_status_3 = 0x0000C574, + .debug_status_cfg = 0x0000C578, + .debug_status_0 = 0x0000C57C, + .debug_status_1 = 0x0000C580, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_13, + .ubwc_regs = NULL, + }, + }, + .num_out = 23, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_3, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_4, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_5, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_LCR, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_2, + }, + }, + .comp_done_shift = 6, + .top_irq_shift = 7, +}; + +static struct cam_irq_register_set vfe480_bus_rd_irq_reg[1] = { + { + .mask_reg_offset = 0x0000A810, + .clear_reg_offset = 0x0000A814, + .status_reg_offset = 0x0000A81C, + }, +}; + +static struct cam_vfe_bus_rd_ver1_hw_info vfe480_bus_rd_hw_info = { + .common_reg = { + .hw_version = 0x0000A800, + .hw_capability = 0x0000A804, + .sw_reset = 0x0000A808, + .cgc_ovd = 0x0000A80C, + .pwr_iso_cfg = 0x0000A834, + .input_if_cmd = 0x0000A820, + .test_bus_ctrl = 0x0000A848, + .irq_reg_info = { + .num_registers = 1, + .irq_reg_set = vfe480_bus_rd_irq_reg, + .global_clear_offset = 0x0000A818, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 1, + .bus_client_reg = { + /* BUS Client 0 */ + { + .cfg = 0x0000A850, + .image_addr = 0x0000A858, + .buf_size = 0x0000A85C, + .stride = 0x0000A860, + .unpacker_cfg = 0x0000A864, + .latency_buf_allocation = 0x0000A878, + .burst_limit = 0x0000A880, + }, + }, + .num_bus_rd_resc = 1, + .vfe_bus_rd_hw_info = { + { + .vfe_bus_rd_type = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe480_hw_info = { + .irq_reg_info = &vfe480_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_3_0, + .bus_hw_info = &vfe480_bus_hw_info, + + .bus_rd_version = CAM_VFE_BUS_RD_VER_1_0, + .bus_rd_hw_info = &vfe480_bus_rd_hw_info, + + .top_version = CAM_VFE_TOP_VER_3_0, + .top_hw_info = &vfe480_top_hw_info, +}; + +#endif /* _CAM_VFE480_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h new file mode 100644 index 000000000000..0c94b63be2e0 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h @@ -0,0 +1,329 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_LITE17X_H_ +#define _CAM_VFE_LITE17X_H_ + +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe17x_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe17x_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe17x_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe17x_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + NULL, + NULL, + NULL, + NULL, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000000, + .three_D_cfg = 0x00000000, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe17x_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_3_data = { + .reg_update_cmd_data = 0x10, + .sof_irq_mask = 0x40000000, + .reg_update_irq_mask = 0x100, +}; + +static struct cam_vfe_top_ver2_hw_info vfe17x_top_hw_info = { + .common_reg = &vfe17x_top_common_reg, + .camif_hw_info = { + .common_reg = NULL, + .camif_reg = NULL, + .reg_data = NULL, + }, + .rdi_hw_info = { + .common_reg = &vfe17x_top_common_reg, + .rdi_reg = &vfe17x_rdi_reg, + .reg_data = { + &vfe17x_rdi_0_data, + &vfe17x_rdi_1_data, + &vfe17x_rdi_2_data, + &vfe17x_rdi_3_data, + }, + }, + .mux_type = { + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe17x_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe17x_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe17x_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + }, + .num_client = 4, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 4, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI3, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +static struct cam_vfe_hw_info cam_vfe_lite17x_hw_info = { + .irq_reg_info = &vfe17x_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe17x_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe17x_top_hw_info, + +}; + +#endif /* _CAM_VFE_LITE17X_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h new file mode 100644 index 000000000000..c9d66ed94e97 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h @@ -0,0 +1,400 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_LITE48x_H_ +#define _CAM_VFE_LITE48x_H_ + +#include "cam_vfe_bus_ver3.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver3.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe48x_top_irq_reg_set[3] = { + { + .mask_reg_offset = 0x00000028, + .clear_reg_offset = 0x00000034, + .status_reg_offset = 0x00000040, + }, + { + .mask_reg_offset = 0x0000002C, + .clear_reg_offset = 0x00000038, + .status_reg_offset = 0x00000044, + }, + { + .mask_reg_offset = 0x00000030, + .clear_reg_offset = 0x0000003C, + .status_reg_offset = 0x00000048, + }, +}; + +static struct cam_irq_controller_reg_info vfe48x_top_irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe48x_top_irq_reg_set, + .global_clear_offset = 0x00000024, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_top_ver3_reg_offset_common vfe48x_top_common_reg = { + .hw_version = 0x00000000, + .titan_version = 0x00000004, + .hw_capability = 0x00000008, + .global_reset_cmd = 0x0000000C, + .core_cgc_ovd_0 = 0x00000010, + .ahb_cgc_ovd = 0x00000014, + .noc_cgc_ovd = 0x00000018, + .reg_update_cmd = 0x00000020, + .diag_config = 0x00000050, + .diag_sensor_status_0 = 0x00000054, + .bus_overflow_status = 0x00001A68, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe48x_camif_rdi[4] = { + { + .lite_hw_version = 0x1200, + .lite_hw_status = 0x1204, + .lite_module_config = 0x1260, + .lite_skip_period = 0x1268, + .lite_irq_subsample_pattern = 0x126C, + .lite_epoch_irq = 0x1270, + .lite_debug_1 = 0x13F0, + .lite_debug_0 = 0x13F4, + .lite_test_bus_ctrl = 0x13F8, + .camif_lite_spare = 0x13FC, + .reg_update_cmd = 0x0020, + }, + { + .lite_hw_version = 0x1400, + .lite_hw_status = 0x1404, + .lite_module_config = 0x1460, + .lite_skip_period = 0x1468, + .lite_irq_subsample_pattern = 0x146C, + .lite_epoch_irq = 0x1470, + .lite_debug_1 = 0x15F0, + .lite_debug_0 = 0x15F4, + .lite_test_bus_ctrl = 0x15F8, + .camif_lite_spare = 0x15FC, + .reg_update_cmd = 0x0020, + }, + { + .lite_hw_version = 0x1600, + .lite_hw_status = 0x1604, + .lite_module_config = 0x1660, + .lite_skip_period = 0x1668, + .lite_irq_subsample_pattern = 0x166C, + .lite_epoch_irq = 0x1670, + .lite_debug_1 = 0x17F0, + .lite_debug_0 = 0x17F4, + .lite_test_bus_ctrl = 0x17F8, + .camif_lite_spare = 0x17FC, + .reg_update_cmd = 0x0020, + }, + { + .lite_hw_version = 0x1800, + .lite_hw_status = 0x1804, + .lite_module_config = 0x1860, + .lite_skip_period = 0x1868, + .lite_irq_subsample_pattern = 0x186C, + .lite_epoch_irq = 0x1870, + .lite_debug_1 = 0x19F0, + .lite_debug_0 = 0x19F4, + .lite_test_bus_ctrl = 0x19F8, + .camif_lite_spare = 0x19FC, + .reg_update_cmd = 0x0020, + }, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe48x_camif_rdi_reg_data[4] = { + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x1, + .epoch0_irq_mask = 0x4, + .epoch1_irq_mask = 0x8, + .eof_irq_mask = 0x02, + .error_irq_mask0 = 0x1, + .error_irq_mask2 = 0x100, + .subscribe_irq_mask1 = 0x3, + .enable_diagnostic_hw = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x2, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x10, + .epoch0_irq_mask = 0x40, + .epoch1_irq_mask = 0x80, + .eof_irq_mask = 0x20, + .error_irq_mask0 = 0x2, + .error_irq_mask2 = 0x200, + .subscribe_irq_mask1 = 0x30, + .enable_diagnostic_hw = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x4, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x100, + .epoch0_irq_mask = 0x400, + .epoch1_irq_mask = 0x800, + .eof_irq_mask = 0x200, + .error_irq_mask0 = 0x4, + .error_irq_mask2 = 0x400, + .subscribe_irq_mask1 = 0x300, + .enable_diagnostic_hw = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x8, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x1000, + .epoch0_irq_mask = 0x4000, + .epoch1_irq_mask = 0x8000, + .eof_irq_mask = 0x2000, + .error_irq_mask0 = 0x8, + .error_irq_mask2 = 0x800, + .subscribe_irq_mask1 = 0x3000, + .enable_diagnostic_hw = 0x1, + }, +}; + +static struct cam_vfe_camif_lite_ver3_hw_info + vfe48x_rdi_hw_info[CAM_VFE_RDI_VER2_MAX] = { + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[0], + .reg_data = &vfe48x_camif_rdi_reg_data[0], + }, + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[1], + .reg_data = &vfe48x_camif_rdi_reg_data[1], + }, + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[2], + .reg_data = &vfe48x_camif_rdi_reg_data[2], + }, + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[3], + .reg_data = &vfe48x_camif_rdi_reg_data[3], + }, +}; + +static struct cam_vfe_top_ver3_hw_info vfe48x_top_hw_info = { + .common_reg = &vfe48x_top_common_reg, + .rdi_hw_info[0] = &vfe48x_rdi_hw_info[0], + .rdi_hw_info[1] = &vfe48x_rdi_hw_info[1], + .rdi_hw_info[2] = &vfe48x_rdi_hw_info[2], + .rdi_hw_info[3] = &vfe48x_rdi_hw_info[3], + .mux_type = { + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe48x_bus_irq_reg[2] = { + { + .mask_reg_offset = 0x00001A18, + .clear_reg_offset = 0x00001A20, + .status_reg_offset = 0x00001A28, + }, + { + .mask_reg_offset = 0x00001A1C, + .clear_reg_offset = 0x00001A24, + .status_reg_offset = 0x00001A2C, + }, +}; + +static struct cam_vfe_bus_ver3_hw_info vfe48x_bus_hw_info = { + .common_reg = { + .hw_version = 0x00001A00, + .cgc_ovd = 0x00001A08, + .if_frameheader_cfg = { + 0x00001A34, + 0x00001A38, + 0x00001A3C, + 0x00001A40, + }, + .pwr_iso_cfg = 0x00001A5C, + .overflow_status_clear = 0x00001A60, + .ccif_violation_status = 0x00001A64, + .overflow_status = 0x00001A68, + .image_size_violation_status = 0x00001A70, + .debug_status_top_cfg = 0x00001AD4, + .debug_status_top = 0x00001AD8, + .test_bus_ctrl = 0x00001ADC, + .irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe48x_bus_irq_reg, + .global_clear_offset = 0x00001A30, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 4, + .bus_client_reg = { + /* RDI 0 */ + { + .cfg = 0x00001C00, + .image_addr = 0x00001C04, + .frame_incr = 0x00001C08, + .image_cfg_0 = 0x00001C0C, + .image_cfg_1 = 0x00001C10, + .image_cfg_2 = 0x00001C14, + .packer_cfg = 0x00001C18, + .frame_header_addr = 0x00001C20, + .frame_header_incr = 0x00001C24, + .frame_header_cfg = 0x00001C28, + .line_done_cfg = 0x00001C2C, + .irq_subsample_period = 0x00001C30, + .irq_subsample_pattern = 0x00001C34, + .framedrop_period = 0x00001C38, + .framedrop_pattern = 0x00001C3C, + .system_cache_cfg = 0x00001C60, + .burst_limit = 0x00001C64, + .addr_status_0 = 0x00001C68, + .addr_status_1 = 0x00001C6C, + .addr_status_2 = 0x00001C70, + .addr_status_3 = 0x00001C74, + .debug_status_cfg = 0x00001C78, + .debug_status_0 = 0x00001C7C, + .debug_status_1 = 0x00001C80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = NULL, + }, + /* RDI 1 */ + { + .cfg = 0x00001D00, + .image_addr = 0x00001D04, + .frame_incr = 0x00001D08, + .image_cfg_0 = 0x00001D0C, + .image_cfg_1 = 0x00001D10, + .image_cfg_2 = 0x00001D14, + .packer_cfg = 0x00001D18, + .frame_header_addr = 0x00001D20, + .frame_header_incr = 0x00001D24, + .frame_header_cfg = 0x00001D28, + .line_done_cfg = 0x00001D2C, + .irq_subsample_period = 0x00001D30, + .irq_subsample_pattern = 0x00001D34, + .framedrop_period = 0x00001D38, + .framedrop_pattern = 0x00001D3C, + .system_cache_cfg = 0x00001D60, + .burst_limit = 0x00001D64, + .addr_status_0 = 0x00001D68, + .addr_status_1 = 0x00001D6C, + .addr_status_2 = 0x00001D70, + .addr_status_3 = 0x00001D74, + .debug_status_cfg = 0x00001D78, + .debug_status_0 = 0x00001D7C, + .debug_status_1 = 0x00001D80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = NULL, + }, + /* RDI 2 */ + { + .cfg = 0x00001E00, + .image_addr = 0x00001E04, + .frame_incr = 0x00001E08, + .image_cfg_0 = 0x00001E0C, + .image_cfg_1 = 0x00001E10, + .image_cfg_2 = 0x00001E14, + .packer_cfg = 0x00001E18, + .frame_header_addr = 0x00001E20, + .frame_header_incr = 0x00001E24, + .frame_header_cfg = 0x00001E28, + .line_done_cfg = 0x00001E2C, + .irq_subsample_period = 0x00001E30, + .irq_subsample_pattern = 0x00001E34, + .framedrop_period = 0x00001E38, + .framedrop_pattern = 0x00001E3C, + .system_cache_cfg = 0x00001E60, + .burst_limit = 0x00001E64, + .addr_status_0 = 0x00001E68, + .addr_status_1 = 0x00001E6C, + .addr_status_2 = 0x00001E70, + .addr_status_3 = 0x00001E74, + .debug_status_cfg = 0x00001E78, + .debug_status_0 = 0x00001E7C, + .debug_status_1 = 0x00001E80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_2, + .ubwc_regs = NULL, + }, + /* RDI 3 */ + { + .cfg = 0x00001F00, + .image_addr = 0x00001F04, + .frame_incr = 0x00001F08, + .image_cfg_0 = 0x00001F0C, + .image_cfg_1 = 0x00001F10, + .image_cfg_2 = 0x00001F14, + .packer_cfg = 0x00001F18, + .frame_header_addr = 0x00001F20, + .frame_header_incr = 0x00001F24, + .frame_header_cfg = 0x00001F28, + .line_done_cfg = 0x00001F2C, + .irq_subsample_period = 0x00001F30, + .irq_subsample_pattern = 0x00001F34, + .framedrop_period = 0x00001F38, + .framedrop_pattern = 0x00001F3C, + .system_cache_cfg = 0x00001F60, + .burst_limit = 0x00001F64, + .addr_status_0 = 0x00001F68, + .addr_status_1 = 0x00001F6C, + .addr_status_2 = 0x00001F70, + .addr_status_3 = 0x00001F74, + .debug_status_cfg = 0x00001F78, + .debug_status_0 = 0x00001F7C, + .debug_status_1 = 0x00001F80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_3, + .ubwc_regs = NULL, + }, + }, + .num_out = 4, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_2, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI3, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_3, + }, + }, + .comp_done_shift = 4, + .top_irq_shift = 4, +}; + +static struct cam_vfe_hw_info cam_vfe_lite48x_hw_info = { + .irq_reg_info = &vfe48x_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_3_0, + .bus_hw_info = &vfe48x_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_3_0, + .top_hw_info = &vfe48x_top_hw_info, + +}; + +#endif /* _CAM_VFE_LITE48x_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile new file mode 100644 index 000000000000..bdf6d3ee981b --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o cam_vfe_bus_rd_ver1.o cam_vfe_bus_ver3.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c new file mode 100644 index 000000000000..2b902d753ad2 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_ver1.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_vfe_bus_ver3.h" +#include "cam_debug_util.h" + +int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int rc = -ENODEV; + + switch (bus_type) { + case BUS_TYPE_WR: + switch (bus_version) { + case CAM_VFE_BUS_VER_2_0: + rc = cam_vfe_bus_ver2_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + case CAM_VFE_BUS_VER_3_0: + rc = cam_vfe_bus_ver3_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus WR Version 0x%x", + bus_version); + break; + } + break; + case BUS_TYPE_RD: + switch (bus_version) { + case CAM_VFE_BUS_RD_VER_1_0: + /* Call vfe bus rd init function */ + rc = cam_vfe_bus_rd_ver1_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus RD Version 0x%x", + bus_version); + break; + } + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus type %d", bus_type); + break; + } + + return rc; +} + +int cam_vfe_bus_deinit(uint32_t bus_version, + struct cam_vfe_bus **vfe_bus) +{ + int rc = -ENODEV; + + switch (bus_version) { + case CAM_VFE_BUS_VER_2_0: + rc = cam_vfe_bus_ver2_deinit(vfe_bus); + break; + case CAM_VFE_BUS_VER_3_0: + rc = cam_vfe_bus_ver3_deinit(vfe_bus); + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus Version %x", bus_version); + break; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c new file mode 100644 index 000000000000..ca2d443747f7 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c @@ -0,0 +1,1221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "../../cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_vfe_core.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus_rd"; + +#define ALIGNUP(value, alignment) \ + ((value + alignment - 1) / alignment * alignment) + +#define MAX_BUF_UPDATE_REG_NUM \ + (sizeof(struct cam_vfe_bus_rd_ver1_reg_offset_bus_client)/4) + +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ + } while (0) + +enum cam_vfe_bus_rd_ver1_unpacker_format { + BUS_RD_VER1_PACKER_FMT_PLAIN_128 = 0x0, + BUS_RD_VER1_PACKER_FMT_PLAIN_8 = 0x1, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_10BPP = 0x2, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_12BPP = 0x3, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_14BPP = 0x4, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_16BPP = 0x5, + BUS_RD_VER1_PACKER_FMT_ARGB_10 = 0x6, + BUS_RD_VER1_PACKER_FMT_ARGB_12 = 0x7, + BUS_RD_VER1_PACKER_FMT_ARGB_14 = 0x8, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_20BPP = 0x9, + BUS_RD_VER1_PACKER_FMT_PLAIN_64 = 0xA, + BUS_RD_VER1_PACKER_FMT_TP_10 = 0xB, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_32BPP = 0xC, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN = 0xD, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0xE, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF, + BUS_RD_VER1_PACKER_FMT_MAX = 0xF, +}; + +struct cam_vfe_bus_rd_ver1_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t fs_sync_enable; + uint32_t go_cmd_sel; +}; + +struct cam_vfe_bus_rd_ver1_rm_resource_data { + uint32_t index; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client *hw_regs; + void *ctx; + + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t hbi_count; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t latency_buf_allocation; + uint32_t unpacker_cfg; + uint32_t burst_len; + + uint32_t go_cmd_sel; + uint32_t fs_sync_enable; + uint32_t fs_line_sync_en; + + uint32_t en_cfg; + uint32_t is_dual; + uint32_t img_addr; + uint32_t input_if_cmd; +}; + +struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data { + uint32_t bus_rd_type; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + + uint32_t num_rm; + struct cam_isp_resource_node *rm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_bus_rd_list; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; +}; + +struct cam_vfe_bus_rd_ver1_priv { + struct cam_vfe_bus_rd_ver1_common_data common_data; + uint32_t num_client; + uint32_t num_bus_rd_resc; + + struct cam_isp_resource_node bus_client[ + CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + struct cam_isp_resource_node vfe_bus_rd[ + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; + + int irq_handle; + int error_irq_handle; +}; + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + +static enum cam_vfe_bus_rd_ver1_unpacker_format + cam_vfe_bus_get_unpacker_fmt(uint32_t unpack_fmt) +{ + switch (unpack_fmt) { + case CAM_FORMAT_MIPI_RAW_10: + return BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN; + default: + return BUS_RD_VER1_PACKER_FMT_MAX; + } +} + +static bool cam_vfe_bus_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return false; + + default: + return false; + } +} + +static enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type + cam_vfe_bus_get_bus_rd_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_RESOURCE_VFE_BUS_RD: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0; + default: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + } +} + +static int cam_vfe_bus_get_num_rm( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type res_type) +{ + switch (res_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return 1; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported resource_type %u", + res_type); + return -EINVAL; +} + +static int cam_vfe_bus_get_rm_idx( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane) +{ + int rm_idx = -1; + + switch (vfe_bus_rd_res_id) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + switch (plane) { + case PLANE_Y: + rm_idx = 0; + break; + default: + break; + } + break; + default: + break; + } + + return rm_idx; +} + +static int cam_vfe_bus_acquire_rm( + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + void *ctx, + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane, + uint32_t subscribe_irq, + struct cam_isp_resource_node **rm_res, + uint32_t *client_done_mask, + uint32_t is_dual) +{ + uint32_t rm_idx = 0; + struct cam_isp_resource_node *rm_res_local = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = NULL; + + *rm_res = NULL; + *client_done_mask = 0; + + /* No need to allocate for BUS VER2. VFE OUT to RM is fixed. */ + rm_idx = cam_vfe_bus_get_rm_idx(vfe_bus_rd_res_id, plane); + if (rm_idx < 0 || rm_idx >= ver1_bus_rd_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d plane %d", + vfe_bus_rd_res_id, plane); + return -EINVAL; + } + + rm_res_local = &ver1_bus_rd_priv->bus_client[rm_idx]; + if (rm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "RM res not available state:%d", + rm_res_local->res_state); + return -EALREADY; + } + rm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rm_res_local->tasklet_info = tasklet; + + rsrc_data = rm_res_local->res_priv; + rsrc_data->ctx = ctx; + rsrc_data->is_dual = is_dual; + /* Set RM offset value to default */ + rsrc_data->offset = 0; + + *client_done_mask = (1 << rm_idx); + *rm_res = rm_res_local; + + CAM_DBG(CAM_ISP, "RM %d: Acquired"); + return 0; +} + +static int cam_vfe_bus_release_rm(void *bus_priv, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->unpacker_cfg = 0; + rsrc_data->burst_len = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rm_res->tasklet_info = NULL; + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rm_data->common_data; + uint32_t buf_size; + uint32_t val; + uint32_t offset; + + CAM_DBG(CAM_ISP, "w: 0x%x", rm_data->width); + CAM_DBG(CAM_ISP, "h: 0x%x", rm_data->height); + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", rm_data->fs_sync_enable); + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", rm_data->fs_line_sync_en); + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + + /* Write All the values*/ + offset = rm_data->hw_regs->buf_size; + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + cam_io_w_mb(buf_size, common_data->mem_base + offset); + CAM_DBG(CAM_ISP, "buf_size: 0x%x", buf_size); + + val = rm_data->width; + offset = rm_data->hw_regs->stride; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + CAM_DBG(CAM_ISP, "rm_data->unpacker_cfg:0x%x", rm_data->unpacker_cfg); + val = cam_vfe_bus_get_unpacker_fmt(rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, " value:0x%x", val); + offset = rm_data->hw_regs->unpacker_cfg; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + val = rm_data->latency_buf_allocation; + offset = rm_data->hw_regs->latency_buf_allocation; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + cam_io_w_mb(0x1, common_data->mem_base + + rm_data->hw_regs->cfg); + return rc; +} + +static int cam_vfe_bus_stop_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rsrc_data->common_data; + + /* Disable RM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + + return rc; +} + +static int cam_vfe_bus_init_rm_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_rm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for RM res priv"); + return -ENOMEM; + } + rm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &bus_rd_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver1_bus_rd_priv->common_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = cam_vfe_bus_start_rm; + rm_res->stop = cam_vfe_bus_stop_rm; + rm_res->hw_intf = ver1_bus_rd_priv->common_data.hw_intf; + + + return 0; +} + +static int cam_vfe_bus_deinit_rm_resource( + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = NULL; + rm_res->stop = NULL; + rm_res->top_half_handler = NULL; + rm_res->bottom_half_handler = NULL; + rm_res->hw_intf = NULL; + + rsrc_data = rm_res->res_priv; + rm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type bus_rd_res_id; + int num_rm; + uint32_t subscribe_irq; + uint32_t client_done_mask; + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv = + bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *bus_rd_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + bus_rd_acquire_args = &acq_args->vfe_bus_rd; + + CAM_DBG(CAM_ISP, "Acquiring resource type 0x%x", + acq_args->rsrc_type); + + bus_rd_res_id = cam_vfe_bus_get_bus_rd_res_id( + acq_args->rsrc_type); + if (bus_rd_res_id == CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX) + return -ENODEV; + + num_rm = cam_vfe_bus_get_num_rm(bus_rd_res_id); + if (num_rm < 1) + return -EINVAL; + + rsrc_node = &ver1_bus_rd_priv->vfe_bus_rd[bus_rd_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", + bus_rd_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + secure_caps = cam_vfe_bus_can_be_secure( + rsrc_data->bus_rd_type); + + mode = bus_rd_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + rsrc_data->num_rm = num_rm; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = bus_rd_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = bus_rd_acquire_args->cdm_ops; + + subscribe_irq = 1; + + for (i = 0; i < num_rm; i++) { + rc = cam_vfe_bus_acquire_rm(ver1_bus_rd_priv, + bus_rd_acquire_args->out_port_info, + acq_args->tasklet, + acq_args->priv, + bus_rd_res_id, + i, + subscribe_irq, + &rsrc_data->rm_res[i], + &client_done_mask, + bus_rd_acquire_args->is_dual); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d RM acquire failed for Out %d rc=%d", + rsrc_data->common_data->core_index, + bus_rd_res_id, rc); + goto release_rm; + } + } + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + bus_rd_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_rm: + for (i--; i >= 0; i--) + cam_vfe_bus_release_rm(ver1_bus_rd_priv, rsrc_data->rm_res[i]); + return rc; +} + +static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_bus_rd = release_args; + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_bus_rd->res_state); + } + + for (i = 0; i < rsrc_data->num_rm; i++) + cam_vfe_bus_release_rm(bus_priv, rsrc_data->rm_res[i]); + rsrc_data->num_rm = 0; + + vfe_bus_rd->tasklet_info = NULL; + vfe_bus_rd->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->bus_rd_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_vfe_bus_rd( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + struct cam_vfe_bus_rd_ver1_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "Start resource type: %x", rsrc_data->bus_rd_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + return -EACCES; + } + + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_start_rm(rsrc_data->rm_res[i]); + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_stop_vfe_bus_rd( + struct cam_isp_resource_node *vfe_bus_rd) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + + CAM_DBG(CAM_ISP, "E:Stop rd Res"); + if (!vfe_bus_rd) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "vfe_out res_state is %d", + vfe_bus_rd->res_state); + return rc; + } + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_stop_rm(rsrc_data->rm_res[i]); + + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_init_vfe_bus_read_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info) +{ + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_bus_rd_resc_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + + if (vfe_bus_rd_resc_type < 0 || + vfe_bus_rd_resc_type > CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_bus_rd_resc_type); + return -EINVAL; + } + + vfe_bus_rd = &bus_rd_priv->vfe_bus_rd[vfe_bus_rd_resc_type]; + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_bus_rd->res_priv) { + CAM_ERR(CAM_ISP, + "Error. Looks like same resource is init again"); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_bus_rd->res_priv = rsrc_data; + + vfe_bus_rd->res_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd->list); + + rsrc_data->bus_rd_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + rsrc_data->common_data = &bus_rd_priv->common_data; + rsrc_data->max_width = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_width; + rsrc_data->max_height = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_bus_rd->start = cam_vfe_bus_start_vfe_bus_rd; + vfe_bus_rd->stop = cam_vfe_bus_stop_vfe_bus_rd; + vfe_bus_rd->process_cmd = cam_vfe_bus_process_cmd; + vfe_bus_rd->hw_intf = bus_rd_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_vfe_bus_rd_resource( + struct cam_isp_resource_node *vfe_bus_rd_res) +{ + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = + vfe_bus_rd_res->res_priv; + + if (vfe_bus_rd_res->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "HW%d Res %d already deinitialized"); + return 0; + } + + vfe_bus_rd_res->start = NULL; + vfe_bus_rd_res->stop = NULL; + vfe_bus_rd_res->top_half_handler = NULL; + vfe_bus_rd_res->bottom_half_handler = NULL; + vfe_bus_rd_res->hw_intf = NULL; + + vfe_bus_rd_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd_res->list); + vfe_bus_rd_res->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_ver1_handle_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "BUS READ IRQ Received"); + return 0; +} + +static int cam_vfe_bus_rd_update_rm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + uint32_t val; + uint32_t buf_size = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + update_buf->res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "#of RM: %d", vfe_bus_rd_data->num_rm); + if (update_buf->rm_update->num_buf != vfe_bus_rd_data->num_rm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->rm_update->num_buf, + vfe_bus_rd_data->num_rm); + return -EINVAL; + } + + reg_val_pair = &vfe_bus_rd_data->common_data->io_buf_update[0]; + io_cfg = update_buf->rm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_bus_rd_data->num_rm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %lu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + + /* update size register */ + rm_data->width = io_cfg->planes[i].width; + rm_data->height = io_cfg->planes[i].height; + CAM_DBG(CAM_ISP, "RM %d image w 0x%x h 0x%x image size 0x%x", + rm_data->index, rm_data->width, rm_data->height, + buf_size); + + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + + CAM_DBG(CAM_ISP, "size offset 0x%x buf_size 0x%x", + rm_data->hw_regs->buf_size, buf_size); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->buf_size, buf_size); + CAM_DBG(CAM_ISP, "RM %d image size 0x%x", + rm_data->index, reg_val_pair[j-1]); + + val = rm_data->width; + CAM_DBG(CAM_ISP, "io_cfg stride 0x%x", val); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->stride, + val); + rm_data->stride = val; + CAM_DBG(CAM_ISP, "RM %d image stride 0x%x", + rm_data->index, reg_val_pair[j-1]); + + /* RM Image address */ + CAM_DBG(CAM_ISP, "image_addr offset %x", + rm_data->hw_regs->image_addr); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->image_addr, + update_buf->rm_update->image_buf[i] + + rm_data->offset); + CAM_DBG(CAM_ISP, "RM %d image address 0x%x", + rm_data->index, reg_val_pair[j-1]); + rm_data->img_addr = reg_val_pair[j-1]; + + } + + size = vfe_bus_rd_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_bus_rd_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_rd_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_rd_update_fs_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + struct cam_vfe_fe_update_args *fe_upd_args; + struct cam_fe_config *fe_cfg; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + int i = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + fe_upd_args = (struct cam_vfe_fe_update_args *)cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + fe_upd_args->node_res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + fe_cfg = &fe_upd_args->fe_config; + + for (i = 0; i < vfe_bus_rd_data->num_rm; i++) { + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + common_data = rm_data->common_data; + + rm_data->format = fe_cfg->format; + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + + rm_data->unpacker_cfg = fe_cfg->unpacker_cfg; + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + + rm_data->latency_buf_allocation = fe_cfg->latency_buf_size; + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + + rm_data->stride = fe_cfg->stride; + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + + rm_data->go_cmd_sel = fe_cfg->go_cmd_sel; + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + + rm_data->fs_sync_enable = fe_cfg->fs_sync_enable; + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", + rm_data->fs_sync_enable); + + rm_data->hbi_count = fe_cfg->hbi_count; + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + + rm_data->fs_line_sync_en = fe_cfg->fs_line_sync_en; + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", + rm_data->fs_line_sync_en); + + rm_data->fs_mode = fe_cfg->fs_mode; + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + + rm_data->min_vbi = fe_cfg->min_vbi; + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + } + bus_priv->common_data.fs_sync_enable = fe_cfg->fs_sync_enable; + bus_priv->common_data.go_cmd_sel = fe_cfg->go_cmd_sel; + return 0; +} + +static int cam_vfe_bus_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_start_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_stop_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[3] = {0}; + uint32_t offset = 0, val = 0; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + common_reg = bus_priv->common_data.common_reg; + top_irq_reg_mask[0] = (1 << 23); + + bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_rd_ver1_handle_irq, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + bus_priv->irq_handle = 0; + return -EFAULT; + } + /* no clock gating at bus input */ + offset = common_reg->cgc_ovd; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* BUS_RD_TEST_BUS_CTRL */ + offset = common_reg->test_bus_ctrl; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* Read irq mask */ + offset = common_reg->irq_reg_info.irq_reg_set->mask_reg_offset; + cam_io_w_mb(0x5, bus_priv->common_data.mem_base + offset); + + /* INPUT_IF_CMD */ + val = (bus_priv->common_data.fs_sync_enable << 5) | + (bus_priv->common_data.go_cmd_sel << 4); + offset = common_reg->input_if_cmd; + cam_io_w_mb(val, bus_priv->common_data.mem_base + offset); + return 0; +} + +static int cam_vfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + int rc = 0; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + + if (bus_priv->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->irq_handle); + bus_priv->irq_handle = 0; + } + + return rc; +} + +static int __cam_vfe_bus_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); +} + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + rc = cam_vfe_bus_rd_update_rm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + rc = cam_vfe_bus_rd_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_rd_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + rc = cam_vfe_bus_rd_update_fs_cfg(priv, cmd_args, arg_size); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info = bus_hw_info; + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_rd_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = bus_rd_hw_info->num_client; + bus_priv->num_bus_rd_resc = + bus_rd_hw_info->num_bus_rd_resc; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &bus_rd_hw_info->common_reg; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &bus_rd_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller); + if (rc) { + CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + goto free_bus_priv; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_init_rm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init RM failed rc=%d", rc); + goto deinit_rm; + } + } + + for (i = 0; i < bus_priv->num_bus_rd_resc; i++) { + rc = cam_vfe_bus_init_vfe_bus_read_resource(i, bus_priv, + bus_rd_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed rc=%d", rc); + goto deinit_vfe_bus_rd; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_acquire_vfe_bus_rd; + vfe_bus_local->hw_ops.release = cam_vfe_bus_release_vfe_bus_rd; + vfe_bus_local->hw_ops.start = cam_vfe_bus_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw; + vfe_bus_local->top_half_handler = cam_vfe_bus_rd_ver1_handle_irq; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd; + + *vfe_bus = vfe_bus_local; + + return rc; + +deinit_vfe_bus_rd: + if (i < 0) + i = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); +deinit_rm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_rd_bus_ver1_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit RM failed rc=%d", rc); + } + for (i = 0; i < CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; i++) { + rc = cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit VFE Out failed rc=%d", rc); + } + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h new file mode 100644 index 000000000000..19cc86496371 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_R_VER1_H_ +#define _CAM_VFE_BUS_R_VER1_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_RD_VER1_MAX_CLIENTS 1 + +enum cam_vfe_bus_rd_ver1_vfe_core_id { + CAM_VFE_BUS_RD_VER1_VFE_CORE_0, + CAM_VFE_BUS_RD_VER1_VFE_CORE_1, + CAM_VFE_BUS_RD_VER1_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_rd_ver1_comp_grp_type { + CAM_VFE_BUS_RD_VER1_COMP_GRP_0, + CAM_VFE_BUS_RD_VER1_COMP_GRP_MAX, +}; + + +enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type { + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX, +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_ovd; + uint32_t pwr_iso_cfg; + uint32_t input_if_cmd; + uint32_t test_bus_ctrl; + struct cam_irq_controller_reg_info irq_reg_info; +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_bus_client { + uint32_t cfg; + uint32_t image_addr; + uint32_t buf_size; + uint32_t stride; + uint32_t unpacker_cfg; + uint32_t latency_buf_allocation; + uint32_t burst_limit; +}; + +/* + * struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info { + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_type; + uint32_t max_width; + uint32_t max_height; +}; + +/* + * struct cam_vfe_bus_rd_ver1_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @bus_client_reg: Bus client register info + * @comp_reg_grp: Composite group register info + * @vfe_out_hw_info: VFE output capability + */ +struct cam_vfe_bus_rd_ver1_hw_info { + struct cam_vfe_bus_rd_ver1_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + uint32_t num_bus_rd_resc; + struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info + vfe_bus_rd_hw_info[CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; +}; + +/* + * cam_vfe_bus_rd_ver1_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_rd_bus_ver1_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_bus_ver1_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_R_VER1_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h new file mode 100644 index 000000000000..2783ddccf2d8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_VER1_H_ +#define _CAM_VFE_BUS_VER1_H_ + +enum cam_vfe_bus_ver1_pingpong_id { + CAM_VFE_BUS_VER1_PING, + CAM_VFE_BUS_VER1_PONG, + CAM_VFE_BUS_VER1_PINGPONG_MAX, +}; + +enum cam_vfe_bus_ver1_wm_type { + CAM_VFE_BUS_WM_TYPE_IMAGE, + CAM_VFE_BUS_WM_TYPE_STATS, + CAM_VFE_BUS_WM_TYPE_MAX, +}; + +enum cam_vfe_bus_ver1_comp_grp_type { + CAM_VFE_BUS_VER1_COMP_GRP_IMG0, + CAM_VFE_BUS_VER1_COMP_GRP_IMG1, + CAM_VFE_BUS_VER1_COMP_GRP_IMG2, + CAM_VFE_BUS_VER1_COMP_GRP_IMG3, + CAM_VFE_BUS_VER1_COMP_GRP_STATS0, + CAM_VFE_BUS_VER1_COMP_GRP_STATS1, + CAM_VFE_BUS_VER1_COMP_GRP_MAX, +}; + +struct cam_vfe_bus_ver1_common_reg { + uint32_t cmd_offset; + uint32_t cfg_offset; + uint32_t io_fmt_offset; + uint32_t argb_cfg_offset; + uint32_t xbar_cfg0_offset; + uint32_t xbar_cfg1_offset; + uint32_t xbar_cfg2_offset; + uint32_t xbar_cfg3_offset; + uint32_t ping_pong_status_reg; +}; + +struct cam_vfe_bus_ver1_wm_reg { + uint32_t wm_cfg_offset; + uint32_t ping_addr_offset; + uint32_t ping_max_addr_offset; + uint32_t pong_addr_offset; + uint32_t pong_max_addr_offset; + uint32_t addr_cfg_offset; + uint32_t ub_cfg_offset; + uint32_t image_size_offset; + uint32_t buffer_cfg_offset; + uint32_t framedrop_pattern_offset; + uint32_t irq_subsample_pattern_offset; + uint32_t ping_pong_status_bit; /* 0 - 31 */ + uint32_t composite_bit; /* 0 -31 */ +}; + +struct cam_vfe_bus_ver1_wm_resource_data { + uint32_t index; + uint32_t wm_type; + uint32_t res_type; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t scanline; + + uint32_t burst_len; + + uint32_t framedrop_period; + uint32_t framedrop_pattern; + + uint32_t buf_valid[CAM_VFE_BUS_VER1_PINGPONG_MAX]; + uint32_t ub_size; + uint32_t ub_offset; + + struct cam_vfe_bus_ver1_wm_reg hw_regs; +}; + +struct cam_vfe_bus_ver1_comp_grp_reg { + enum cam_vfe_bus_ver1_comp_grp_type comp_grp_type; + uint32_t comp_grp_offset; +}; + +struct cam_vfe_bus_ver1_comp_grp { + struct cam_vfe_bus_ver1_comp_grp_reg reg_info; + struct list_head wm_list; + uint32_t cur_bit_mask; +}; + +/* + * cam_vfe_bus_ver1_init() + * + * @Brief: Initialize Bus layer + * + * @mem_base: Mapped base address of register space + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + */ +int cam_vfe_bus_ver1_init( + void __iomem *mem_base, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_VER1_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c new file mode 100644 index 000000000000..2a452c0d874d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -0,0 +1,3781 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "../../cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_core.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus"; + +#define CAM_VFE_BUS_IRQ_REG0 0 +#define CAM_VFE_BUS_IRQ_REG1 1 +#define CAM_VFE_BUS_IRQ_REG2 2 +#define CAM_VFE_BUS_IRQ_MAX 3 + +#define CAM_VFE_BUS_VER2_PAYLOAD_MAX 256 + +#define CAM_VFE_BUS_SET_DEBUG_REG 0x82 + +#define CAM_VFE_RDI_BUS_DEFAULT_WIDTH 0xFF01 +#define CAM_VFE_RDI_BUS_DEFAULT_STRIDE 0xFF01 +#define CAM_VFE_BUS_INTRA_CLIENT_MASK 0x3 +#define CAM_VFE_BUS_ADDR_SYNC_INTRA_CLIENT_SHIFT 8 +#define CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL \ + ((1 << CAM_VFE_BUS_VER2_MAX_CLIENTS) - 1) + +#define MAX_BUF_UPDATE_REG_NUM \ + ((sizeof(struct cam_vfe_bus_ver2_reg_offset_bus_client) + \ + sizeof(struct cam_vfe_bus_ver2_reg_offset_ubwc_client))/4) +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +static uint32_t bus_error_irq_mask[3] = { + 0x7800, + 0x0000, + 0x0040, +}; + +enum cam_vfe_bus_packer_format { + PACKER_FMT_PLAIN_128 = 0x0, + PACKER_FMT_PLAIN_8 = 0x1, + PACKER_FMT_PLAIN_16_10BPP = 0x2, + PACKER_FMT_PLAIN_16_12BPP = 0x3, + PACKER_FMT_PLAIN_16_14BPP = 0x4, + PACKER_FMT_PLAIN_16_16BPP = 0x5, + PACKER_FMT_ARGB_10 = 0x6, + PACKER_FMT_ARGB_12 = 0x7, + PACKER_FMT_ARGB_14 = 0x8, + PACKER_FMT_PLAIN_32_20BPP = 0x9, + PACKER_FMT_PLAIN_64 = 0xA, + PACKER_FMT_TP_10 = 0xB, + PACKER_FMT_PLAIN_32_32BPP = 0xC, + PACKER_FMT_PLAIN_8_ODD_EVEN = 0xD, + PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0xE, + PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF, + PACKER_FMT_MAX = 0xF, +}; + +enum cam_vfe_bus_comp_grp_id { + CAM_VFE_BUS_COMP_GROUP_NONE = -EINVAL, + CAM_VFE_BUS_COMP_GROUP_ID_0 = 0x0, + CAM_VFE_BUS_COMP_GROUP_ID_1 = 0x1, + CAM_VFE_BUS_COMP_GROUP_ID_2 = 0x2, + CAM_VFE_BUS_COMP_GROUP_ID_3 = 0x3, + CAM_VFE_BUS_COMP_GROUP_ID_4 = 0x4, + CAM_VFE_BUS_COMP_GROUP_ID_5 = 0x5, +}; + +struct cam_vfe_bus_ver2_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_ver2_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct cam_vfe_bus_irq_evt_payload evt_payload[ + CAM_VFE_BUS_VER2_PAYLOAD_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t addr_no_sync; + cam_hw_mgr_event_cb_func event_cb; + bool hw_init; +}; + +struct cam_vfe_bus_ver2_wm_resource_data { + uint32_t index; + struct cam_vfe_bus_ver2_common_data *common_data; + struct cam_vfe_bus_ver2_reg_offset_bus_client *hw_regs; + + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + enum cam_vfe_bus_packer_format pack_fmt; + + uint32_t burst_len; + + uint32_t en_ubwc; + bool ubwc_updated; + uint32_t packer_cfg; + uint32_t tile_cfg; + uint32_t h_init; + uint32_t v_init; + uint32_t ubwc_meta_stride; + uint32_t ubwc_mode_cfg_0; + uint32_t ubwc_mode_cfg_1; + uint32_t ubwc_meta_offset; + + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + + uint32_t en_cfg; + uint32_t is_dual; + uint32_t ubwc_lossy_threshold_0; + uint32_t ubwc_lossy_threshold_1; + uint32_t ubwc_bandwidth_limit; +}; + +struct cam_vfe_bus_ver2_comp_grp_data { + enum cam_vfe_bus_ver2_comp_grp_type comp_grp_type; + struct cam_vfe_bus_ver2_common_data *common_data; + struct cam_vfe_bus_ver2_reg_offset_comp_grp *hw_regs; + + uint32_t comp_grp_local_idx; + uint32_t unique_id; + + uint32_t is_master; + uint32_t dual_slave_core; + uint32_t intra_client_mask; + uint32_t composite_mask; + uint32_t addr_sync_mode; + + uint32_t acquire_dev_cnt; +}; + +struct cam_vfe_bus_ver2_vfe_out_data { + uint32_t out_type; + struct cam_vfe_bus_ver2_common_data *common_data; + + uint32_t num_wm; + struct cam_isp_resource_node *wm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_out_list; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; + void *priv; +}; + +struct cam_vfe_bus_ver2_priv { + struct cam_vfe_bus_ver2_common_data common_data; + uint32_t num_client; + uint32_t num_out; + + struct cam_isp_resource_node bus_client[CAM_VFE_BUS_VER2_MAX_CLIENTS]; + struct cam_isp_resource_node comp_grp[CAM_VFE_BUS_VER2_COMP_GRP_MAX]; + struct cam_isp_resource_node vfe_out[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; + + struct list_head free_comp_grp; + struct list_head free_dual_comp_grp; + struct list_head used_comp_grp; + + int irq_handle; + int error_irq_handle; + void *tasklet_info; +}; + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + +static int cam_vfe_bus_get_evt_payload( + struct cam_vfe_bus_ver2_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + int rc; + + spin_lock(&common_data->spin_lock); + + if (!common_data->hw_init) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d Bus uninitialized", + common_data->core_index); + rc = -EPERM; + goto done; + } + + if (list_empty(&common_data->free_payload_list)) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&common_data->free_payload_list, + struct cam_vfe_bus_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&common_data->spin_lock); + return rc; +} + +static enum cam_vfe_bus_comp_grp_id + cam_vfe_bus_comp_grp_id_convert(uint32_t comp_grp) +{ + switch (comp_grp) { + case CAM_ISP_RES_COMP_GROUP_ID_0: + return CAM_VFE_BUS_COMP_GROUP_ID_0; + case CAM_ISP_RES_COMP_GROUP_ID_1: + return CAM_VFE_BUS_COMP_GROUP_ID_1; + case CAM_ISP_RES_COMP_GROUP_ID_2: + return CAM_VFE_BUS_COMP_GROUP_ID_2; + case CAM_ISP_RES_COMP_GROUP_ID_3: + return CAM_VFE_BUS_COMP_GROUP_ID_3; + case CAM_ISP_RES_COMP_GROUP_ID_4: + return CAM_VFE_BUS_COMP_GROUP_ID_4; + case CAM_ISP_RES_COMP_GROUP_ID_5: + return CAM_VFE_BUS_COMP_GROUP_ID_5; + case CAM_ISP_RES_COMP_GROUP_NONE: + default: + return CAM_VFE_BUS_COMP_GROUP_NONE; + } +} + +static int cam_vfe_bus_put_evt_payload( + struct cam_vfe_bus_ver2_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!common_data) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&common_data->spin_lock, flags); + if (common_data->hw_init) + list_add_tail(&(*evt_payload)->list, + &common_data->free_payload_list); + spin_unlock_irqrestore(&common_data->spin_lock, flags); + + *evt_payload = NULL; + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_bus_ver2_get_intra_client_mask( + enum cam_vfe_bus_ver2_vfe_core_id dual_slave_core, + enum cam_vfe_bus_ver2_vfe_core_id current_core, + uint32_t *intra_client_mask) +{ + int rc = 0; + uint32_t camera_hw_version = 0; + uint32_t version_based_intra_client_mask = 0x1; + + *intra_client_mask = 0; + + + if (dual_slave_core == current_core) { + CAM_ERR(CAM_ISP, + "Invalid params. Same core as Master and Slave"); + return -EINVAL; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + + CAM_DBG(CAM_ISP, "CPAS VERSION %d", camera_hw_version); + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + version_based_intra_client_mask = 0x3; + break; + default: + version_based_intra_client_mask = 0x1; + break; + } + + + switch (current_core) { + case CAM_VFE_BUS_VER2_VFE_CORE_0: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER2_VFE_CORE_1: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_CORE_1: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER2_VFE_CORE_0: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + default: + CAM_ERR(CAM_ISP, + "Invalid value for master core %u", current_core); + rc = -EINVAL; + break; + } + + return rc; +} + +static bool cam_vfe_bus_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_VER2_VFE_OUT_FULL: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + case CAM_VFE_BUS_VER2_VFE_OUT_FD: + case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: + return true; + + case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: + case CAM_VFE_BUS_VER2_VFE_OUT_2PD: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST: + default: + return false; + } +} + +static enum cam_vfe_bus_ver2_vfe_out_type + cam_vfe_bus_get_out_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_IFE_OUT_RES_FULL: + return CAM_VFE_BUS_VER2_VFE_OUT_FULL; + case CAM_ISP_IFE_OUT_RES_DS4: + return CAM_VFE_BUS_VER2_VFE_OUT_DS4; + case CAM_ISP_IFE_OUT_RES_DS16: + return CAM_VFE_BUS_VER2_VFE_OUT_DS16; + case CAM_ISP_IFE_OUT_RES_FD: + return CAM_VFE_BUS_VER2_VFE_OUT_FD; + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + return CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP; + case CAM_ISP_IFE_OUT_RES_PDAF: + return CAM_VFE_BUS_VER2_VFE_OUT_PDAF; + case CAM_ISP_IFE_OUT_RES_2PD: + return CAM_VFE_BUS_VER2_VFE_OUT_2PD; + case CAM_ISP_IFE_OUT_RES_RDI_0: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI0; + case CAM_ISP_IFE_OUT_RES_RDI_1: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI1; + case CAM_ISP_IFE_OUT_RES_RDI_2: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI2; + case CAM_ISP_IFE_OUT_RES_RDI_3: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI3; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BF: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF; + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_RS: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS; + case CAM_ISP_IFE_OUT_RES_STATS_CS: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS; + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST; + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP; + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP; + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP; + default: + return CAM_VFE_BUS_VER2_VFE_OUT_MAX; + } +} + +static int cam_vfe_bus_get_num_wm( + enum cam_vfe_bus_ver2_vfe_out_type res_type, + uint32_t format) +{ + switch (res_type) { + case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI3: + switch (format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_DPCM_10_6_10: + case CAM_FORMAT_DPCM_10_8_10: + case CAM_FORMAT_DPCM_12_6_12: + case CAM_FORMAT_DPCM_12_8_12: + case CAM_FORMAT_DPCM_14_8_14: + case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + case CAM_FORMAT_PLAIN128: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FULL: + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_UBWC_P010: + case CAM_FORMAT_PLAIN16_10: + return 2; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FD: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_PLAIN16_10: + return 2; + case CAM_FORMAT_Y_ONLY: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: + switch (format) { + case CAM_FORMAT_PD8: + case CAM_FORMAT_PD10: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP: + switch (format) { + case CAM_FORMAT_ARGB_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: + switch (format) { + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_2PD: + switch (format) { + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS: + switch (format) { + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST: + switch (format) { + case CAM_FORMAT_PLAIN16_16: + return 1; + default: + break; + } + break; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported format %u for resource_type %u", + format, res_type); + + return -EINVAL; +} + +static int cam_vfe_bus_get_wm_idx( + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane) +{ + int wm_idx = -1; + + switch (vfe_out_res_id) { + case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: + switch (plane) { + case PLANE_Y: + wm_idx = 0; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: + switch (plane) { + case PLANE_Y: + wm_idx = 1; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: + switch (plane) { + case PLANE_Y: + wm_idx = 2; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RDI3: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FULL: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + case PLANE_C: + wm_idx = 4; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + switch (plane) { + case PLANE_Y: + wm_idx = 5; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + switch (plane) { + case PLANE_Y: + wm_idx = 6; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FD: + switch (plane) { + case PLANE_Y: + wm_idx = 7; + break; + case PLANE_C: + wm_idx = 8; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP: + switch (plane) { + case PLANE_Y: + wm_idx = 9; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: + case CAM_VFE_BUS_VER2_VFE_OUT_2PD: + switch (plane) { + case PLANE_Y: + wm_idx = 10; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE: + switch (plane) { + case PLANE_Y: + wm_idx = 11; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 12; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 13; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF: + switch (plane) { + case PLANE_Y: + wm_idx = 14; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 15; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 16; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS: + switch (plane) { + case PLANE_Y: + wm_idx = 17; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS: + switch (plane) { + case PLANE_Y: + wm_idx = 18; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 19; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 20; + break; + case PLANE_C: + wm_idx = 21; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 22; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 23; + break; + default: + break; + } + break; + + default: + break; + } + + return wm_idx; +} + +static void cam_vfe_bus_get_comp_vfe_out_res_id_list( + uint32_t comp_mask, uint32_t *out_list, int *num_out) +{ + int count = 0; + + if (comp_mask & 0x1) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_0; + + if (comp_mask & 0x2) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (comp_mask & 0x4) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_2; + + if ((comp_mask & 0x8) && (((comp_mask >> 4) & 0x1) == 0)) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_3; + + if (comp_mask & 0x18) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL; + + if (comp_mask & 0x20) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4; + + if (comp_mask & 0x40) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16; + + if (comp_mask & 0x180) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FD; + + if (comp_mask & 0x200) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RAW_DUMP; + + if (comp_mask & 0x800) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BE; + + if (comp_mask & 0x1000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST; + + if (comp_mask & 0x2000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_TL_BG; + + if (comp_mask & 0x4000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BF; + + if (comp_mask & 0x8000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_AWB_BG; + + if (comp_mask & 0x10000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BHIST; + + if (comp_mask & 0x20000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_RS; + + if (comp_mask & 0x40000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_CS; + + if (comp_mask & 0x80000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_IHIST; + + if (comp_mask & 0x300000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL_DISP; + + if (comp_mask & 0x400000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4_DISP; + + if (comp_mask & 0x800000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16_DISP; + + *num_out = count; + +} + +static enum cam_vfe_bus_packer_format + cam_vfe_bus_get_packer_fmt(uint32_t out_fmt, int wm_index) +{ + switch (out_fmt) { + case CAM_FORMAT_NV21: + if ((wm_index == 4) || (wm_index == 6) || (wm_index == 21)) + return PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN; + case CAM_FORMAT_NV12: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_Y_ONLY: + return PACKER_FMT_PLAIN_8_LSB_MSB_10; + case CAM_FORMAT_PLAIN16_16: + return PACKER_FMT_PLAIN_16_16BPP; + case CAM_FORMAT_PLAIN64: + return PACKER_FMT_PLAIN_64; + case CAM_FORMAT_PLAIN8: + return PACKER_FMT_PLAIN_8; + case CAM_FORMAT_PLAIN16_10: + return PACKER_FMT_PLAIN_16_10BPP; + case CAM_FORMAT_PLAIN16_12: + return PACKER_FMT_PLAIN_16_12BPP; + case CAM_FORMAT_PLAIN16_14: + return PACKER_FMT_PLAIN_16_14BPP; + case CAM_FORMAT_PLAIN32_20: + return PACKER_FMT_PLAIN_32_20BPP; + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PD8: + case CAM_FORMAT_PD10: + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_TP10: + return PACKER_FMT_TP_10; + case CAM_FORMAT_ARGB_14: + return PACKER_FMT_ARGB_14; + default: + return PACKER_FMT_MAX; + } +} + +static int cam_vfe_bus_acquire_wm( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + struct cam_isp_resource_node **wm_res, + uint32_t *client_done_mask, + uint32_t is_dual) +{ + uint32_t wm_idx = 0; + struct cam_isp_resource_node *wm_res_local = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = NULL; + + *wm_res = NULL; + *client_done_mask = 0; + + /* No need to allocate for BUS VER2. VFE OUT to WM is fixed. */ + wm_idx = cam_vfe_bus_get_wm_idx(vfe_out_res_id, plane); + if (wm_idx < 0 || wm_idx >= ver2_bus_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d plane %d", + vfe_out_res_id, plane); + return -EINVAL; + } + + wm_res_local = &ver2_bus_priv->bus_client[wm_idx]; + if (wm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "WM res not available state:%d", + wm_res_local->res_state); + return -EALREADY; + } + wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + wm_res_local->tasklet_info = tasklet; + + rsrc_data = wm_res_local->res_priv; + rsrc_data->format = out_port_info->format; + rsrc_data->pack_fmt = cam_vfe_bus_get_packer_fmt(rsrc_data->format, + wm_idx); + + rsrc_data->width = out_port_info->width; + rsrc_data->height = out_port_info->height; + rsrc_data->is_dual = is_dual; + /* Set WM offset value to default */ + rsrc_data->offset = 0; + CAM_DBG(CAM_ISP, "WM %d width %d height %d", rsrc_data->index, + rsrc_data->width, rsrc_data->height); + + if (rsrc_data->index < 3) { + /* Write master 0-2 refers to RDI 0/ RDI 1/RDI 2 */ + switch (rsrc_data->format) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN128: + rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->pack_fmt = 0x0; + rsrc_data->en_cfg = 0x3; + break; + case CAM_FORMAT_PLAIN8: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0x1; + rsrc_data->width = rsrc_data->width * 2; + rsrc_data->stride = rsrc_data->width; + break; + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->pack_fmt = 0x0; + rsrc_data->en_cfg = 0x3; + break; + case CAM_FORMAT_PLAIN64: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0xA; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported RDI format %d", + rsrc_data->format); + return -EINVAL; + } + } else if ((rsrc_data->index < 5) || + (rsrc_data->index == 7) || (rsrc_data->index == 8) || + (rsrc_data->index == 20) || (rsrc_data->index == 21)) { + /* + * Write master 3, 4 - for Full OUT , 7-8 FD OUT, + * WM 20-21 = FULL_DISP + */ + switch (rsrc_data->format) { + case CAM_FORMAT_UBWC_NV12_4R: + rsrc_data->en_ubwc = 1; + rsrc_data->width = ALIGNUP(rsrc_data->width, 64); + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_NV12: + rsrc_data->en_ubwc = 1; + /* Fall through for NV12 */ + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_Y_ONLY: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_TP10: + rsrc_data->en_ubwc = 1; + rsrc_data->width = + ALIGNUP(rsrc_data->width, 48) * 4 / 3; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_TP10: + rsrc_data->width = + ALIGNUP(rsrc_data->width, 3) * 4 / 3; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_PLAIN16_10: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + rsrc_data->width *= 2; + break; + default: + CAM_ERR(CAM_ISP, "Invalid format %d", + rsrc_data->format); + return -EINVAL; + } + rsrc_data->en_cfg = 0x1; + } else if (rsrc_data->index >= 11 && rsrc_data->index < 20) { + /* Write master 11 - 19 stats */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = 0x3; + } else if (rsrc_data->index == 10) { + /* Write master 10 - PDAF/2PD */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = 0x3; + if (vfe_out_res_id == CAM_VFE_BUS_VER2_VFE_OUT_PDAF) + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + } else if (rsrc_data->index == 9) { + /* Write master 9 - Raw dump */ + rsrc_data->width = rsrc_data->width * 2; + rsrc_data->stride = rsrc_data->width; + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + } else { + /* Write master 5-6 DS ports */ + uint32_t align_width; + + rsrc_data->width = rsrc_data->width * 4; + rsrc_data->height = rsrc_data->height / 2; + rsrc_data->en_cfg = 0x1; + CAM_DBG(CAM_ISP, "before width %d", rsrc_data->width); + align_width = ALIGNUP(rsrc_data->width, 16); + if (align_width != rsrc_data->width) { + CAM_WARN(CAM_ISP, + "Override width %u with expected %u", + rsrc_data->width, align_width); + rsrc_data->width = align_width; + } + } + + *client_done_mask = (1 << wm_idx); + *wm_res = wm_res_local; + + CAM_DBG(CAM_ISP, "WM %d: processed width %d, processed height %d", + rsrc_data->index, rsrc_data->width, rsrc_data->height); + return 0; +} + +static int cam_vfe_bus_release_wm(void *bus_priv, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + wm_res->res_priv; + + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->pack_fmt = 0; + rsrc_data->burst_len = 0; + rsrc_data->irq_subsample_period = 0; + rsrc_data->irq_subsample_pattern = 0; + rsrc_data->framedrop_period = 0; + rsrc_data->framedrop_pattern = 0; + rsrc_data->packer_cfg = 0; + rsrc_data->en_ubwc = 0; + rsrc_data->tile_cfg = 0; + rsrc_data->h_init = 0; + rsrc_data->v_init = 0; + rsrc_data->ubwc_meta_stride = 0; + rsrc_data->ubwc_mode_cfg_0 = 0; + rsrc_data->ubwc_mode_cfg_1 = 0; + rsrc_data->ubwc_meta_offset = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rsrc_data->ubwc_lossy_threshold_0 = 0; + rsrc_data->ubwc_lossy_threshold_1 = 0; + rsrc_data->ubwc_bandwidth_limit = 0; + wm_res->tasklet_info = NULL; + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_wm( + struct cam_isp_resource_node *wm_res, + uint32_t *bus_irq_reg_mask) +{ + int rc = 0, val = 0; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver2_common_data *common_data = + rsrc_data->common_data; + uint32_t camera_hw_version; + + cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); + + cam_io_w_mb(rsrc_data->width, + common_data->mem_base + rsrc_data->hw_regs->buffer_width_cfg); + cam_io_w(rsrc_data->height, + common_data->mem_base + rsrc_data->hw_regs->buffer_height_cfg); + cam_io_w(rsrc_data->pack_fmt, + common_data->mem_base + rsrc_data->hw_regs->packer_cfg); + + /* Configure stride for RDIs */ + if (rsrc_data->index < 3) + cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + + rsrc_data->hw_regs->stride)); + + bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG1] = (1 << rsrc_data->index); + + /* enable ubwc if needed*/ + if (rsrc_data->en_ubwc) { + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version:%d rc:%d", + camera_hw_version, rc); + return rc; + } + if ((camera_hw_version > CAM_CPAS_TITAN_NONE) && + (camera_hw_version < CAM_CPAS_TITAN_175_V100)) { + struct cam_vfe_bus_ver2_reg_offset_ubwc_client + *ubwc_regs; + + ubwc_regs = + (struct + cam_vfe_bus_ver2_reg_offset_ubwc_client *) + rsrc_data->hw_regs->ubwc_regs; + val = cam_io_r_mb(common_data->mem_base + + ubwc_regs->mode_cfg_0); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + + ubwc_regs->mode_cfg_0); + } else if ((camera_hw_version == CAM_CPAS_TITAN_175_V100) || + (camera_hw_version == CAM_CPAS_TITAN_175_V101) || + (camera_hw_version == CAM_CPAS_TITAN_175_V120) || + (camera_hw_version == CAM_CPAS_TITAN_175_V130)) { + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + *ubwc_regs; + + ubwc_regs = + (struct + cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + rsrc_data->hw_regs->ubwc_regs; + val = cam_io_r_mb(common_data->mem_base + + ubwc_regs->mode_cfg_0); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + + ubwc_regs->mode_cfg_0); + } else { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + return -EINVAL; + } + } + + /* Enable WM */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + + rsrc_data->hw_regs->cfg); + + CAM_DBG(CAM_ISP, "WM res %d width = %d, height = %d", rsrc_data->index, + rsrc_data->width, rsrc_data->height); + CAM_DBG(CAM_ISP, "WM res %d pk_fmt = %d", rsrc_data->index, + rsrc_data->pack_fmt & PACKER_FMT_MAX); + CAM_DBG(CAM_ISP, "WM res %d stride = %d, burst len = %d", + rsrc_data->index, rsrc_data->stride, 0xf); + CAM_DBG(CAM_ISP, "enable WM res %d offset 0x%x val 0x%x", + rsrc_data->index, (uint32_t) rsrc_data->hw_regs->cfg, + rsrc_data->en_cfg); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) +{ + int rc = 0; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver2_common_data *common_data = + rsrc_data->common_data; + + /* Disable WM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + + /* Disable all register access, reply on global reset */ + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + + return rc; +} + +static int cam_vfe_bus_handle_wm_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_handle_wm_done_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int rc = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *wm_res = handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + (wm_res == NULL) ? NULL : wm_res->res_priv; + uint32_t *cam_ife_irq_regs; + uint32_t status_reg; + + if (!evt_payload || !wm_res || !rsrc_data) + return rc; + + CAM_DBG(CAM_ISP, "addr of evt_payload = %llx core index:0x%x", + (uint64_t)evt_payload, evt_payload->core_index); + CAM_DBG(CAM_ISP, "bus_irq_status_0: = %x", evt_payload->irq_reg_val[0]); + CAM_DBG(CAM_ISP, "bus_irq_status_1: = %x", evt_payload->irq_reg_val[1]); + CAM_DBG(CAM_ISP, "bus_irq_status_2: = %x", evt_payload->irq_reg_val[2]); + CAM_DBG(CAM_ISP, "bus_irq_comp_err: = %x", evt_payload->irq_reg_val[3]); + CAM_DBG(CAM_ISP, "bus_irq_comp_owrt: = %x", + evt_payload->irq_reg_val[4]); + CAM_DBG(CAM_ISP, "bus_irq_dual_comp_err: = %x", + evt_payload->irq_reg_val[5]); + CAM_DBG(CAM_ISP, "bus_irq_dual_comp_owrt: = %x", + evt_payload->irq_reg_val[6]); + + cam_ife_irq_regs = evt_payload->irq_reg_val; + status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1]; + + if (status_reg & BIT(rsrc_data->index)) { + cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1] &= + ~BIT(rsrc_data->index); + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + } + CAM_DBG(CAM_ISP, "status_reg %x rc %d wm_idx %d", + status_reg, rc, rsrc_data->index); + + return rc; +} + + +static int cam_vfe_bus_err_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver2_priv *bus_priv = handler_priv; + struct cam_vfe_bus_ver2_common_data *common_data; + struct cam_isp_hw_event_info evt_info; + uint32_t val = 0; + + if (!handler_priv || !evt_payload_priv) + return -EINVAL; + + evt_payload = evt_payload_priv; + common_data = &bus_priv->common_data; + + val = evt_payload->debug_status_0; + CAM_ERR(CAM_ISP, "Bus Violation: debug_status_0 = 0x%x", val); + + if (val & 0x01) + CAM_INFO(CAM_ISP, "RDI 0 violation"); + + if (val & 0x02) + CAM_INFO(CAM_ISP, "RDI 1 violation"); + + if (val & 0x04) + CAM_INFO(CAM_ISP, "RDI 2 violation"); + + if (val & 0x08) + CAM_INFO(CAM_ISP, "VID Y 1:1 UBWC violation"); + + if (val & 0x010) + CAM_INFO(CAM_ISP, "VID C 1:1 UBWC violation"); + + if (val & 0x020) + CAM_INFO(CAM_ISP, "VID YC 4:1 violation"); + + if (val & 0x040) + CAM_INFO(CAM_ISP, "VID YC 16:1 violation"); + + if (val & 0x080) + CAM_INFO(CAM_ISP, "FD Y violation"); + + if (val & 0x0100) + CAM_INFO(CAM_ISP, "FD C violation"); + + if (val & 0x0200) + CAM_INFO(CAM_ISP, "RAW DUMP violation"); + + if (val & 0x0400) + CAM_INFO(CAM_ISP, "PDAF violation"); + + if (val & 0x0800) + CAM_INFO(CAM_ISP, "STATs HDR BE violation"); + + if (val & 0x01000) + CAM_INFO(CAM_ISP, "STATs HDR BHIST violation"); + + if (val & 0x02000) + CAM_INFO(CAM_ISP, "STATs TINTLESS BG violation"); + + if (val & 0x04000) + CAM_INFO(CAM_ISP, "STATs BF violation"); + + if (val & 0x08000) + CAM_INFO(CAM_ISP, "STATs AWB BG UBWC violation"); + + if (val & 0x010000) + CAM_INFO(CAM_ISP, "STATs BHIST violation"); + + if (val & 0x020000) + CAM_INFO(CAM_ISP, "STATs RS violation"); + + if (val & 0x040000) + CAM_INFO(CAM_ISP, "STATs CS violation"); + + if (val & 0x080000) + CAM_INFO(CAM_ISP, "STATs IHIST violation"); + + if (val & 0x0100000) + CAM_INFO(CAM_ISP, "DISP Y 1:1 UBWC violation"); + + if (val & 0x0200000) + CAM_INFO(CAM_ISP, "DISP C 1:1 UBWC violation"); + + if (val & 0x0400000) + CAM_INFO(CAM_ISP, "DISP YC 4:1 violation"); + + if (val & 0x0800000) + CAM_INFO(CAM_ISP, "DISP YC 16:1 violation"); + + cam_vfe_bus_put_evt_payload(common_data, &evt_payload); + + evt_info.hw_idx = common_data->core_index; + evt_info.res_type = CAM_ISP_RESOURCE_VFE_OUT; + evt_info.res_id = CAM_VFE_BUS_VER2_VFE_OUT_MAX; + + if (common_data->event_cb) + common_data->event_cb(NULL, CAM_ISP_HW_EVENT_ERROR, + (void *)&evt_info); + + return 0; +} + +static int cam_vfe_bus_init_wm_resource(uint32_t index, + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_wm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for WM res priv"); + return -ENOMEM; + } + wm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &ver2_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver2_bus_priv->common_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = NULL; + wm_res->stop = NULL; + wm_res->top_half_handler = cam_vfe_bus_handle_wm_done_top_half; + wm_res->bottom_half_handler = cam_vfe_bus_handle_wm_done_bottom_half; + wm_res->hw_intf = ver2_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_wm_resource( + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = NULL; + wm_res->stop = NULL; + wm_res->top_half_handler = NULL; + wm_res->bottom_half_handler = NULL; + wm_res->hw_intf = NULL; + + rsrc_data = wm_res->res_priv; + wm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static void cam_vfe_bus_add_wm_to_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t composite_mask) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = comp_grp->res_priv; + + rsrc_data->composite_mask |= composite_mask; +} + +static void cam_vfe_bus_match_comp_grp( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_resource_node **comp_grp, + uint32_t comp_grp_local_idx, + uint32_t unique_id) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + struct cam_isp_resource_node *comp_grp_local = NULL; + + list_for_each_entry(comp_grp_local, + &ver2_bus_priv->used_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_local_idx == comp_grp_local_idx && + rsrc_data->unique_id == unique_id) { + /* Match found */ + *comp_grp = comp_grp_local; + return; + } + } + + *comp_grp = NULL; +} + +static int cam_vfe_bus_acquire_comp_grp( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + uint32_t unique_id, + uint32_t is_dual, + uint32_t is_master, + enum cam_vfe_bus_ver2_vfe_core_id dual_slave_core, + struct cam_isp_resource_node **comp_grp) +{ + int rc = 0; + uint32_t bus_comp_grp_id; + struct cam_isp_resource_node *comp_grp_local = NULL; + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + + bus_comp_grp_id = cam_vfe_bus_comp_grp_id_convert( + out_port_info->comp_grp_id); + /* Perform match only if there is valid comp grp request */ + if (out_port_info->comp_grp_id != CAM_ISP_RES_COMP_GROUP_NONE) { + /* Check if matching comp_grp already acquired */ + cam_vfe_bus_match_comp_grp(ver2_bus_priv, &comp_grp_local, + bus_comp_grp_id, unique_id); + } + + if (!comp_grp_local) { + /* First find a free group */ + if (is_dual) { + CAM_DBG(CAM_ISP, "Acquire dual comp group"); + if (list_empty(&ver2_bus_priv->free_dual_comp_grp)) { + CAM_ERR(CAM_ISP, "No Free Composite Group"); + return -ENODEV; + } + comp_grp_local = list_first_entry( + &ver2_bus_priv->free_dual_comp_grp, + struct cam_isp_resource_node, list); + rsrc_data = comp_grp_local->res_priv; + rc = cam_vfe_bus_ver2_get_intra_client_mask( + dual_slave_core, + comp_grp_local->hw_intf->hw_idx, + &rsrc_data->intra_client_mask); + if (rc) + return rc; + } else { + CAM_DBG(CAM_ISP, "Acquire comp group"); + if (list_empty(&ver2_bus_priv->free_comp_grp)) { + CAM_ERR(CAM_ISP, "No Free Composite Group"); + return -ENODEV; + } + comp_grp_local = list_first_entry( + &ver2_bus_priv->free_comp_grp, + struct cam_isp_resource_node, list); + rsrc_data = comp_grp_local->res_priv; + } + + list_del(&comp_grp_local->list); + comp_grp_local->tasklet_info = tasklet; + comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + rsrc_data->is_master = is_master; + rsrc_data->composite_mask = 0; + rsrc_data->unique_id = unique_id; + rsrc_data->comp_grp_local_idx = bus_comp_grp_id; + + if (is_master) + rsrc_data->addr_sync_mode = 0; + else + rsrc_data->addr_sync_mode = 1; + + list_add_tail(&comp_grp_local->list, + &ver2_bus_priv->used_comp_grp); + + } else { + rsrc_data = comp_grp_local->res_priv; + /* Do not support runtime change in composite mask */ + if (comp_grp_local->res_state == + CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d Comp Grp %u", + comp_grp_local->res_state, + rsrc_data->comp_grp_type); + return -EBUSY; + } + } + + CAM_DBG(CAM_ISP, "Comp Grp type %u", rsrc_data->comp_grp_type); + + rsrc_data->acquire_dev_cnt++; + *comp_grp = comp_grp_local; + + return rc; +} + +static int cam_vfe_bus_release_comp_grp( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_resource_node *in_comp_grp) +{ + struct cam_isp_resource_node *comp_grp = NULL; + struct cam_vfe_bus_ver2_comp_grp_data *in_rsrc_data = NULL; + int match_found = 0; + + if (!in_comp_grp) { + CAM_ERR(CAM_ISP, "Invalid Params Comp Grp %pK", in_comp_grp); + return -EINVAL; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Already released Comp Grp"); + return 0; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d", + in_comp_grp->res_state); + return -EBUSY; + } + + in_rsrc_data = in_comp_grp->res_priv; + CAM_DBG(CAM_ISP, "Comp Grp type %u", in_rsrc_data->comp_grp_type); + + list_for_each_entry(comp_grp, &ver2_bus_priv->used_comp_grp, list) { + if (comp_grp == in_comp_grp) { + match_found = 1; + break; + } + } + + if (!match_found) { + CAM_ERR(CAM_ISP, "Could not find matching Comp Grp type %u", + in_rsrc_data->comp_grp_type); + return -ENODEV; + } + + in_rsrc_data->acquire_dev_cnt--; + if (in_rsrc_data->acquire_dev_cnt == 0) { + list_del(&comp_grp->list); + + in_rsrc_data->unique_id = 0; + in_rsrc_data->comp_grp_local_idx = CAM_VFE_BUS_COMP_GROUP_NONE; + in_rsrc_data->composite_mask = 0; + in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX; + in_rsrc_data->addr_sync_mode = 0; + + comp_grp->tasklet_info = NULL; + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + if (in_rsrc_data->comp_grp_type >= + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 && + in_rsrc_data->comp_grp_type <= + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5) + list_add_tail(&comp_grp->list, + &ver2_bus_priv->free_dual_comp_grp); + else if (in_rsrc_data->comp_grp_type >= + CAM_VFE_BUS_VER2_COMP_GRP_0 && + in_rsrc_data->comp_grp_type <= + CAM_VFE_BUS_VER2_COMP_GRP_5) + list_add_tail(&comp_grp->list, + &ver2_bus_priv->free_comp_grp); + } + + return 0; +} + +static int cam_vfe_bus_start_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t *bus_irq_reg_mask) +{ + int rc = 0; + uint32_t addr_sync_cfg; + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = + comp_grp->res_priv; + struct cam_vfe_bus_ver2_common_data *common_data = + rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "comp group id:%d streaming state:%d", + rsrc_data->comp_grp_type, comp_grp->res_state); + + cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base + + rsrc_data->hw_regs->comp_mask); + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + return 0; + + CAM_DBG(CAM_ISP, "composite_mask is 0x%x", rsrc_data->composite_mask); + CAM_DBG(CAM_ISP, "composite_mask addr 0x%x", + rsrc_data->hw_regs->comp_mask); + + if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 && + rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5) { + int dual_comp_grp = (rsrc_data->comp_grp_type - + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0); + + if (rsrc_data->is_master) { + int intra_client_en = cam_io_r_mb( + common_data->mem_base + + common_data->common_reg->dual_master_comp_cfg); + + /* + * 2 Bits per comp_grp. Hence left shift by + * comp_grp * 2 + */ + intra_client_en |= + (rsrc_data->intra_client_mask << + (dual_comp_grp * 2)); + + cam_io_w_mb(intra_client_en, common_data->mem_base + + common_data->common_reg->dual_master_comp_cfg); + + bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG2] = + (1 << dual_comp_grp); + } + + CAM_DBG(CAM_ISP, "addr_sync_mask addr 0x%x", + rsrc_data->hw_regs->addr_sync_mask); + cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base + + rsrc_data->hw_regs->addr_sync_mask); + + addr_sync_cfg = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->addr_sync_cfg); + addr_sync_cfg |= (rsrc_data->addr_sync_mode << dual_comp_grp); + /* + * 2 Bits per dual_comp_grp. dual_comp_grp stats at bit number + * 8. Hence left shift cdual_comp_grp dual comp_grp * 2 and + * add 8 + */ + addr_sync_cfg |= + (rsrc_data->intra_client_mask << + ((dual_comp_grp * 2) + + CAM_VFE_BUS_ADDR_SYNC_INTRA_CLIENT_SHIFT)); + cam_io_w_mb(addr_sync_cfg, common_data->mem_base + + common_data->common_reg->addr_sync_cfg); + + common_data->addr_no_sync &= ~(rsrc_data->composite_mask); + cam_io_w_mb(common_data->addr_no_sync, common_data->mem_base + + common_data->common_reg->addr_sync_no_sync); + CAM_DBG(CAM_ISP, "addr_sync_cfg: 0x%x addr_no_sync_cfg: 0x%x", + addr_sync_cfg, common_data->addr_no_sync); + } else { + /* IRQ bits for COMP GRP start at 5. So add 5 to the shift */ + bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG0] = + (1 << (rsrc_data->comp_grp_type + 5)); + } + + CAM_DBG(CAM_ISP, "VFE start COMP_GRP%d", rsrc_data->comp_grp_type); + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static int cam_vfe_bus_stop_comp_grp(struct cam_isp_resource_node *comp_grp) +{ + int rc = 0; + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return rc; +} + +static int cam_vfe_bus_handle_comp_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_handle_comp_done_bottom_half(void *handler_priv, + void *evt_payload_priv, uint32_t *comp_mask) +{ + int rc = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *comp_grp = handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = comp_grp->res_priv; + uint32_t *cam_ife_irq_regs; + uint32_t status_reg; + uint32_t comp_err_reg; + uint32_t comp_grp_id; + + CAM_DBG(CAM_ISP, "comp grp type %d", rsrc_data->comp_grp_type); + + if (!evt_payload) + return rc; + + cam_ife_irq_regs = evt_payload->irq_reg_val; + + switch (rsrc_data->comp_grp_type) { + case CAM_VFE_BUS_VER2_COMP_GRP_0: + case CAM_VFE_BUS_VER2_COMP_GRP_1: + case CAM_VFE_BUS_VER2_COMP_GRP_2: + case CAM_VFE_BUS_VER2_COMP_GRP_3: + case CAM_VFE_BUS_VER2_COMP_GRP_4: + case CAM_VFE_BUS_VER2_COMP_GRP_5: + comp_grp_id = (rsrc_data->comp_grp_type - + CAM_VFE_BUS_VER2_COMP_GRP_0); + + /* Check for Regular composite error */ + status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0]; + + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_COMP_ERR]; + if ((status_reg & BIT(11)) && + (comp_err_reg & rsrc_data->composite_mask)) { + /* Check for Regular composite error */ + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_ERR_COMP; + break; + } + + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_COMP_OWRT]; + /* Check for Regular composite Overwrite */ + if ((status_reg & BIT(12)) && + (comp_err_reg & rsrc_data->composite_mask)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_COMP_OWRT; + break; + } + + /* Regular Composite SUCCESS */ + if (status_reg & BIT(comp_grp_id + 5)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + CAM_DBG(CAM_ISP, "status reg = 0x%x, bit index = %d rc %d", + status_reg, (comp_grp_id + 5), rc); + break; + + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5: + comp_grp_id = (rsrc_data->comp_grp_type - + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0); + + /* Check for DUAL composite error */ + status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2]; + + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_DUAL_COMP_ERR]; + if ((status_reg & BIT(6)) && + (comp_err_reg & rsrc_data->composite_mask)) { + /* Check for DUAL composite error */ + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_ERR_COMP; + break; + } + + /* Check for Dual composite Overwrite */ + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_DUAL_COMP_OWRT]; + if ((status_reg & BIT(7)) && + (comp_err_reg & rsrc_data->composite_mask)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_COMP_OWRT; + break; + } + + /* DUAL Composite SUCCESS */ + if (status_reg & BIT(comp_grp_id)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + break; + default: + rc = CAM_VFE_IRQ_STATUS_ERR; + CAM_ERR(CAM_ISP, "Invalid comp_grp_type %u", + rsrc_data->comp_grp_type); + break; + } + + *comp_mask = rsrc_data->composite_mask; + + return rc; +} + +static int cam_vfe_bus_init_comp_grp(uint32_t index, + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info, + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_comp_grp_data), + GFP_KERNEL); + if (!rsrc_data) + return -ENOMEM; + + comp_grp->res_priv = rsrc_data; + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&comp_grp->list); + + rsrc_data->comp_grp_type = index; + rsrc_data->common_data = &ver2_bus_priv->common_data; + rsrc_data->hw_regs = &ver2_hw_info->comp_grp_reg[index]; + rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX; + + if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 && + rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5) + list_add_tail(&comp_grp->list, + &ver2_bus_priv->free_dual_comp_grp); + else if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0 + && rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5) + list_add_tail(&comp_grp->list, &ver2_bus_priv->free_comp_grp); + + comp_grp->start = NULL; + comp_grp->stop = NULL; + comp_grp->top_half_handler = cam_vfe_bus_handle_comp_done_top_half; + comp_grp->bottom_half_handler = NULL; + comp_grp->hw_intf = ver2_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = + comp_grp->res_priv; + + comp_grp->start = NULL; + comp_grp->stop = NULL; + comp_grp->top_half_handler = NULL; + comp_grp->bottom_half_handler = NULL; + comp_grp->hw_intf = NULL; + + list_del_init(&comp_grp->list); + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + + comp_grp->res_priv = NULL; + + if (!rsrc_data) { + CAM_ERR(CAM_ISP, "comp_grp_priv is NULL"); + return -ENODEV; + } + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + bool *mode = cmd_args; + struct cam_isp_resource_node *res = + (struct cam_isp_resource_node *) priv; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = + (struct cam_vfe_bus_ver2_vfe_out_data *)res->res_priv; + + *mode = + (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? + true : false; + + return 0; +} + +static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id; + uint32_t format; + int num_wm; + uint32_t client_done_mask; + struct cam_vfe_bus_ver2_priv *ver2_bus_priv = bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *out_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + out_acquire_args = &acq_args->vfe_out; + format = out_acquire_args->out_port_info->format; + + CAM_DBG(CAM_ISP, "Acquiring resource type 0x%x", + out_acquire_args->out_port_info->res_type); + + vfe_out_res_id = cam_vfe_bus_get_out_res_id( + out_acquire_args->out_port_info->res_type); + if (vfe_out_res_id == CAM_VFE_BUS_VER2_VFE_OUT_MAX) + return -ENODEV; + + num_wm = cam_vfe_bus_get_num_wm(vfe_out_res_id, format); + if (num_wm < 1) + return -EINVAL; + + rsrc_node = &ver2_bus_priv->vfe_out[vfe_out_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", + vfe_out_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->out_type); + mode = out_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + ver2_bus_priv->tasklet_info = acq_args->tasklet; + rsrc_data->num_wm = num_wm; + rsrc_node->res_id = out_acquire_args->out_port_info->res_type; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = out_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = out_acquire_args->cdm_ops; + + /* Reserve Composite Group */ + if (num_wm > 1 || (out_acquire_args->is_dual) || + (out_acquire_args->out_port_info->comp_grp_id > + CAM_ISP_RES_COMP_GROUP_NONE && + out_acquire_args->out_port_info->comp_grp_id < + CAM_ISP_RES_COMP_GROUP_ID_MAX)) { + + rc = cam_vfe_bus_acquire_comp_grp(ver2_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + out_acquire_args->unique_id, + out_acquire_args->is_dual, + out_acquire_args->is_master, + out_acquire_args->dual_slave_core, + &rsrc_data->comp_grp); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d Comp_Grp acquire fail for Out %d rc=%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + return rc; + } + } + + /* Reserve WM */ + for (i = 0; i < num_wm; i++) { + rc = cam_vfe_bus_acquire_wm(ver2_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + vfe_out_res_id, + i, + &rsrc_data->wm_res[i], + &client_done_mask, + out_acquire_args->is_dual); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d WM acquire failed for Out %d rc=%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + goto release_wm; + } + + if (rsrc_data->comp_grp) + cam_vfe_bus_add_wm_to_comp_grp(rsrc_data->comp_grp, + client_done_mask); + } + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + out_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_wm: + for (i--; i >= 0; i--) + cam_vfe_bus_release_wm(ver2_bus_priv, rsrc_data->wm_res[i]); + + cam_vfe_bus_release_comp_grp(ver2_bus_priv, + rsrc_data->comp_grp); + + return rc; +} + +static int cam_vfe_bus_release_vfe_out(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_out = release_args; + rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + } + + for (i = 0; i < rsrc_data->num_wm; i++) + cam_vfe_bus_release_wm(bus_priv, rsrc_data->wm_res[i]); + rsrc_data->num_wm = 0; + + if (rsrc_data->comp_grp) + cam_vfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp); + rsrc_data->comp_grp = NULL; + + vfe_out->tasklet_info = NULL; + vfe_out->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->out_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver2_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX]; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "Start resource index %d", rsrc_data->out_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + return -EACCES; + } + + memset(bus_irq_reg_mask, 0, sizeof(bus_irq_reg_mask)); + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_start_wm(rsrc_data->wm_res[i], + bus_irq_reg_mask); + + if (rsrc_data->comp_grp) { + memset(bus_irq_reg_mask, 0, sizeof(bus_irq_reg_mask)); + rc = cam_vfe_bus_start_comp_grp(rsrc_data->comp_grp, + bus_irq_reg_mask); + } + + vfe_out->irq_handle = cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1, + bus_irq_reg_mask, vfe_out, vfe_out->top_half_handler, + vfe_out->bottom_half_handler, vfe_out->tasklet_info, + &tasklet_bh_api); + + if (vfe_out->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Subscribe IRQ failed for res_id %d", + vfe_out->res_id); + vfe_out->irq_handle = 0; + return -EFAULT; + } + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_stop_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver2_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "vfe_out res_state is %d", vfe_out->res_state); + return rc; + } + + if (rsrc_data->comp_grp) + rc = cam_vfe_bus_stop_comp_grp(rsrc_data->comp_grp); + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_stop_wm(rsrc_data->wm_res[i]); + + if (vfe_out->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + common_data->bus_irq_controller, + vfe_out->irq_handle); + vfe_out->irq_handle = 0; + } + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_handle_vfe_out_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + vfe_out = th_payload->handler_priv; + if (!vfe_out) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + + rsrc_data = vfe_out->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = 0x%x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = 0x%x", th_payload->evt_status_arr[1]); + CAM_DBG(CAM_ISP, "IRQ status_2 = 0x%x", th_payload->evt_status_arr[2]); + + rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "IRQ status_0 = 0x%x status_1 = 0x%x status_2 = 0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], + th_payload->evt_status_arr[2]); + + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + evt_payload->core_index = rsrc_data->common_data->core_index; + evt_payload->evt_id = evt_id; + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_bus_handle_vfe_out_done_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int rc = -EINVAL; + struct cam_isp_resource_node *vfe_out = handler_priv; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv; + struct cam_isp_hw_event_info evt_info; + void *ctx = NULL; + uint32_t evt_id = 0; + uint32_t comp_mask = 0; + int num_out = 0, i = 0; + struct cam_vfe_bus_irq_evt_payload *evt_payload = + evt_payload_priv; + uint32_t out_list[CAM_VFE_BUS_VER2_VFE_OUT_MAX] = {0}; + + /* + * If this resource has Composite Group then we only handle + * Composite done. We acquire Composite if number of WM > 1. + * So Else case is only one individual buf_done = WM[0]. + */ + if (rsrc_data->comp_grp) { + rc = cam_vfe_bus_handle_comp_done_bottom_half( + rsrc_data->comp_grp, evt_payload_priv, &comp_mask); + } else { + rc = rsrc_data->wm_res[0]->bottom_half_handler( + rsrc_data->wm_res[0], evt_payload_priv); + } + + ctx = rsrc_data->priv; + + switch (rc) { + case CAM_VFE_IRQ_STATUS_SUCCESS: + evt_id = evt_payload->evt_id; + + evt_info.res_type = vfe_out->res_type; + evt_info.hw_idx = vfe_out->hw_intf->hw_idx; + if (rsrc_data->comp_grp) { + cam_vfe_bus_get_comp_vfe_out_res_id_list( + comp_mask, out_list, &num_out); + for (i = 0; i < num_out; i++) { + evt_info.res_id = out_list[i]; + if (rsrc_data->common_data->event_cb) + rsrc_data->common_data->event_cb(ctx, + evt_id, (void *)&evt_info); + } + } else { + evt_info.res_id = vfe_out->res_id; + if (rsrc_data->common_data->event_cb) + rsrc_data->common_data->event_cb(ctx, evt_id, + (void *)&evt_info); + } + break; + default: + break; + } + + cam_vfe_bus_put_evt_payload(rsrc_data->common_data, &evt_payload); + CAM_DBG(CAM_ISP, "vfe_out %d rc %d", rsrc_data->out_type, rc); + + return rc; +} + +static int cam_vfe_bus_init_vfe_out_resource(uint32_t index, + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info) +{ + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_out_type = + ver2_hw_info->vfe_out_hw_info[index].vfe_out_type; + + if (vfe_out_type < 0 || + vfe_out_type >= CAM_VFE_BUS_VER2_VFE_OUT_MAX) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_out_type); + return -EINVAL; + } + + vfe_out = &ver2_bus_priv->vfe_out[vfe_out_type]; + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_out->res_priv) { + CAM_ERR(CAM_ISP, + "Error. Looks like same resource is init again"); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_vfe_out_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_out->res_priv = rsrc_data; + + vfe_out->res_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + + rsrc_data->out_type = + ver2_hw_info->vfe_out_hw_info[index].vfe_out_type; + rsrc_data->common_data = &ver2_bus_priv->common_data; + rsrc_data->max_width = + ver2_hw_info->vfe_out_hw_info[index].max_width; + rsrc_data->max_height = + ver2_hw_info->vfe_out_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_out->start = cam_vfe_bus_start_vfe_out; + vfe_out->stop = cam_vfe_bus_stop_vfe_out; + vfe_out->top_half_handler = cam_vfe_bus_handle_vfe_out_done_top_half; + vfe_out->bottom_half_handler = + cam_vfe_bus_handle_vfe_out_done_bottom_half; + vfe_out->process_cmd = cam_vfe_bus_process_cmd; + vfe_out->hw_intf = ver2_bus_priv->common_data.hw_intf; + vfe_out->irq_handle = 0; + + return 0; +} + +static int cam_vfe_bus_deinit_vfe_out_resource( + struct cam_isp_resource_node *vfe_out) +{ + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "HW%d Res %d already deinitialized"); + return 0; + } + + vfe_out->start = NULL; + vfe_out->stop = NULL; + vfe_out->top_half_handler = NULL; + vfe_out->bottom_half_handler = NULL; + vfe_out->hw_intf = NULL; + vfe_out->irq_handle = 0; + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + vfe_out->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_ver2_handle_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + int rc = 0; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "Enter"); + rc = cam_irq_controller_handle_irq(evt_id, + bus_priv->common_data.bus_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; +} + +static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int i = 0, rc = 0; + struct cam_vfe_bus_ver2_priv *bus_priv = + th_payload->handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + CAM_ERR_RATE_LIMIT(CAM_ISP, "Bus Err IRQ"); + for (i = 0; i < th_payload->num_registers; i++) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "vfe:%d: IRQ_Status%d: 0x%x", + bus_priv->common_data.core_index, i, + th_payload->evt_status_arr[i]); + } + cam_irq_controller_disable_irq(bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + + rc = cam_vfe_bus_get_evt_payload(&bus_priv->common_data, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Cannot get payload"); + return rc; + } + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->core_index = bus_priv->common_data.core_index; + evt_payload->evt_id = evt_id; + evt_payload->debug_status_0 = cam_io_r_mb( + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->debug_status_0); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static void cam_vfe_bus_update_ubwc_meta_addr( + uint32_t *reg_val_pair, + uint32_t *j, + void *regs, + uint64_t image_buf) +{ + uint32_t camera_hw_version; + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_3_regs; + int rc = 0; + + if (!regs || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); + goto end; + } else if ((camera_hw_version < CAM_CPAS_TITAN_170_V100) || + (camera_hw_version > CAM_CPAS_TITAN_175_V130)) { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + goto end; + } + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + ubwc_regs = + (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *)regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_addr, + image_buf); + break; + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + case CAM_CPAS_TITAN_175_V120: + case CAM_CPAS_TITAN_175_V130: + ubwc_3_regs = + (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_3_regs->meta_addr, + image_buf); + break; + default: + break; + } +end: + return; +} + +static int cam_vfe_bus_update_ubwc_3_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_regs; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->offset); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->v_init, wm_data->v_init); + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_1, wm_data->ubwc_mode_cfg_1); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_1 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->ubwc_bandwidth_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, wm_data->ubwc_bandwidth_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, wm_data->ubwc_bandwidth_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_legacy_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t camera_hw_version, uint32_t *reg_val_pair, + uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; + uint32_t ubwc_bw_limit = 0; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->offset); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->v_init, wm_data->v_init); + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (camera_hw_version == CAM_CPAS_TITAN_170_V110) { + switch (wm_data->format) { + case CAM_FORMAT_UBWC_TP10: + ubwc_bw_limit = 0x8 | BIT(0); + break; + case CAM_FORMAT_UBWC_NV12_4R: + ubwc_bw_limit = 0xB | BIT(0); + break; + default: + ubwc_bw_limit = 0; + break; + } + } + + if (ubwc_bw_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, ubwc_bw_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, ubwc_bw_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + uint32_t camera_hw_version; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); + goto end; + } else if ((camera_hw_version <= CAM_CPAS_TITAN_NONE) || + (camera_hw_version >= CAM_CPAS_TITAN_MAX)) { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + rc = -EINVAL; + goto end; + } + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + rc = cam_vfe_bus_update_ubwc_legacy_regs( + wm_data, camera_hw_version, reg_val_pair, i, j); + break; + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + case CAM_CPAS_TITAN_175_V120: + case CAM_CPAS_TITAN_175_V130: + rc = cam_vfe_bus_update_ubwc_3_regs( + wm_data, reg_val_pair, i, j); + break; + default: + break; + } + + if (rc) + CAM_ERR(CAM_ISP, "Failed to update ubwc regs rc:%d", rc); + +end: + return rc; +} + +static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_client = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, k, size = 0; + uint32_t frame_inc = 0, val; + uint32_t loop_size = 0; + + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_buf->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + if (update_buf->wm_update->num_buf != vfe_out_data->num_wm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->wm_update->num_buf, vfe_out_data->num_wm); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + io_cfg = update_buf->wm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_client = wm_data->hw_regs->ubwc_regs; + /* update width register */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->buffer_width_cfg, + wm_data->width); + CAM_DBG(CAM_ISP, "WM %d image width 0x%x", + wm_data->index, reg_val_pair[j-1]); + + /* For initial configuration program all bus registers */ + val = io_cfg->planes[i].plane_stride; + CAM_DBG(CAM_ISP, "before stride %d", val); + val = ALIGNUP(val, 16); + if (val != io_cfg->planes[i].plane_stride && + val != wm_data->stride) + CAM_WARN(CAM_ISP, + "Warning stride %u expected %u", + io_cfg->planes[i].plane_stride, + val); + + if ((wm_data->stride != val || + !wm_data->init_cfg_done) && (wm_data->index >= 3)) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->stride, + io_cfg->planes[i].plane_stride); + wm_data->stride = val; + CAM_DBG(CAM_ISP, "WM %d image stride 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->en_ubwc) { + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + return -EINVAL; + } + if (wm_data->ubwc_updated) { + wm_data->ubwc_updated = false; + cam_vfe_bus_update_ubwc_regs( + wm_data, reg_val_pair, i, &j); + } + + /* UBWC meta address */ + cam_vfe_bus_update_ubwc_meta_addr( + reg_val_pair, &j, + wm_data->hw_regs->ubwc_regs, + update_buf->wm_update->image_buf[i]); + CAM_DBG(CAM_ISP, "WM %d ubwc meta addr 0x%llx", + wm_data->index, + update_buf->wm_update->image_buf[i]); + } + + if (wm_data->en_ubwc) { + frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height, 4096); + frame_inc += io_cfg->planes[i].meta_size; + CAM_DBG(CAM_ISP, + "WM %d frm %d: ht: %d stride %d meta: %d", + wm_data->index, frame_inc, + io_cfg->planes[i].slice_height, + io_cfg->planes[i].plane_stride, + io_cfg->planes[i].meta_size); + } else { + frame_inc = io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height; + } + + if (wm_data->index < 3) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_ubwc) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size + + k * frame_inc); + else + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc); + CAM_DBG(CAM_ISP, "WM %d image address 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_inc, frame_inc); + CAM_DBG(CAM_ISP, "WM %d frame_inc %d", + wm_data->index, reg_val_pair[j-1]); + + + /* enable the WM */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, + wm_data->en_cfg); + + /* set initial configuration done */ + if (!wm_data->init_cfg_done) + wm_data->init_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_hfr; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_isp_port_hfr_config *hfr_cfg = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + update_hfr = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_hfr->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + hfr_cfg = update_hfr->hfr_update; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + + if (wm_data->index <= 2 && hfr_cfg->subsample_period > 3) { + CAM_ERR(CAM_ISP, + "RDI doesn't support irq subsample period %d", + hfr_cfg->subsample_period); + return -EINVAL; + } + + if ((wm_data->framedrop_pattern != + hfr_cfg->framedrop_pattern) || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_pattern, + hfr_cfg->framedrop_pattern); + wm_data->framedrop_pattern = hfr_cfg->framedrop_pattern; + CAM_DBG(CAM_ISP, "WM %d framedrop pattern 0x%x", + wm_data->index, wm_data->framedrop_pattern); + } + + if (wm_data->framedrop_period != hfr_cfg->framedrop_period || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_period, + hfr_cfg->framedrop_period); + wm_data->framedrop_period = hfr_cfg->framedrop_period; + CAM_DBG(CAM_ISP, "WM %d framedrop period 0x%x", + wm_data->index, wm_data->framedrop_period); + } + + if (wm_data->irq_subsample_period != hfr_cfg->subsample_period + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_period, + hfr_cfg->subsample_period); + wm_data->irq_subsample_period = + hfr_cfg->subsample_period; + CAM_DBG(CAM_ISP, "WM %d irq subsample period 0x%x", + wm_data->index, wm_data->irq_subsample_period); + } + + if (wm_data->irq_subsample_pattern != hfr_cfg->subsample_pattern + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_pattern, + hfr_cfg->subsample_pattern); + wm_data->irq_subsample_pattern = + hfr_cfg->subsample_pattern; + CAM_DBG(CAM_ISP, "WM %d irq subsample pattern 0x%x", + wm_data->index, wm_data->irq_subsample_pattern); + } + + /* set initial configuration done */ + if (!wm_data->hfr_cfg_done) + wm_data->hfr_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_hfr->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_hfr->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_hfr->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_hfr->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_update_ubwc_config(void *cmd_args) +{ + struct cam_isp_hw_get_cmd_update *update_ubwc; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg = NULL; + uint32_t i; + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_ubwc->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid data"); + rc = -EINVAL; + goto end; + } + + ubwc_plane_cfg = update_ubwc->ubwc_update; + + for (i = 0; i < vfe_out_data->num_wm; i++) { + + wm_data = vfe_out_data->wm_res[i]->res_priv; + if (i > 0) + ubwc_plane_cfg++; + + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + rc = -EINVAL; + goto end; + } + + if (!wm_data->en_ubwc) { + CAM_ERR(CAM_ISP, "UBWC Disabled"); + rc = -EINVAL; + goto end; + } + + if (wm_data->packer_cfg != + ubwc_plane_cfg->packer_config || + !wm_data->init_cfg_done) { + wm_data->packer_cfg = ubwc_plane_cfg->packer_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->tile_cfg != + ubwc_plane_cfg->tile_config) + || !wm_data->init_cfg_done)) { + wm_data->tile_cfg = ubwc_plane_cfg->tile_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->h_init != + ubwc_plane_cfg->h_init) || + !wm_data->init_cfg_done)) { + wm_data->h_init = ubwc_plane_cfg->h_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->v_init != ubwc_plane_cfg->v_init || + !wm_data->init_cfg_done) { + wm_data->v_init = ubwc_plane_cfg->v_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_stride != + ubwc_plane_cfg->meta_stride || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_stride = ubwc_plane_cfg->meta_stride; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_0 != + ubwc_plane_cfg->mode_config_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_0 = + ubwc_plane_cfg->mode_config_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_1 != + ubwc_plane_cfg->mode_config_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_1 = + ubwc_plane_cfg->mode_config_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_offset != + ubwc_plane_cfg->meta_offset || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_offset = ubwc_plane_cfg->meta_offset; + wm_data->ubwc_updated = true; + } + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_config_v2(void *cmd_args) +{ + struct cam_isp_hw_get_cmd_update *update_ubwc; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_vfe_generic_ubwc_config *ubwc_generic_cfg = NULL; + struct cam_vfe_generic_ubwc_plane_config *ubwc_generic_plane_cfg = NULL; + uint32_t i; + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_ubwc->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid data"); + rc = -EINVAL; + goto end; + } + + ubwc_generic_cfg = update_ubwc->ubwc_config; + + for (i = 0; i < vfe_out_data->num_wm; i++) { + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_generic_plane_cfg = &ubwc_generic_cfg->ubwc_plane_cfg[i]; + + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + rc = -EINVAL; + goto end; + } + + if (!wm_data->en_ubwc) { + CAM_ERR(CAM_ISP, "UBWC Disabled"); + rc = -EINVAL; + goto end; + } + + if (wm_data->packer_cfg != + ubwc_generic_plane_cfg->packer_config || + !wm_data->init_cfg_done) { + wm_data->packer_cfg = + ubwc_generic_plane_cfg->packer_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->tile_cfg != + ubwc_generic_plane_cfg->tile_config) + || !wm_data->init_cfg_done)) { + wm_data->tile_cfg = ubwc_generic_plane_cfg->tile_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->h_init != + ubwc_generic_plane_cfg->h_init) || + !wm_data->init_cfg_done)) { + wm_data->h_init = ubwc_generic_plane_cfg->h_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->v_init != ubwc_generic_plane_cfg->v_init || + !wm_data->init_cfg_done) { + wm_data->v_init = ubwc_generic_plane_cfg->v_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_stride != + ubwc_generic_plane_cfg->meta_stride || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_stride = + ubwc_generic_plane_cfg->meta_stride; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_0 != + ubwc_generic_plane_cfg->mode_config_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_0 = + ubwc_generic_plane_cfg->mode_config_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_1 != + ubwc_generic_plane_cfg->mode_config_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_1 = + ubwc_generic_plane_cfg->mode_config_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_offset != + ubwc_generic_plane_cfg->meta_offset || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_offset = + ubwc_generic_plane_cfg->meta_offset; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_0 != + ubwc_generic_plane_cfg->lossy_threshold_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_0 = + ubwc_generic_plane_cfg->lossy_threshold_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_1 != + ubwc_generic_plane_cfg->lossy_threshold_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_1 = + ubwc_generic_plane_cfg->lossy_threshold_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_bandwidth_limit != + ubwc_generic_plane_cfg->bandwidth_limit || + !wm_data->init_cfg_done) { + wm_data->ubwc_bandwidth_limit = + ubwc_generic_plane_cfg->bandwidth_limit; + wm_data->ubwc_updated = true; + } + } + +end: + return rc; +} + + +static int cam_vfe_bus_update_stripe_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + struct cam_isp_hw_dual_isp_update_args *stripe_args; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_isp_dual_stripe_config *stripe_config; + uint32_t outport_id, ports_plane_idx, i; + + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + stripe_args = (struct cam_isp_hw_dual_isp_update_args *)cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + stripe_args->res->res_priv; + + if (!vfe_out_data) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + outport_id = stripe_args->res->res_id & 0xFF; + if (stripe_args->res->res_id < CAM_ISP_IFE_OUT_RES_BASE || + stripe_args->res->res_id >= CAM_ISP_IFE_OUT_RES_MAX) + return 0; + + ports_plane_idx = (stripe_args->split_id * + (stripe_args->dual_cfg->num_ports * CAM_PACKET_MAX_PLANES)) + + (outport_id * CAM_PACKET_MAX_PLANES); + for (i = 0; i < vfe_out_data->num_wm; i++) { + wm_data = vfe_out_data->wm_res[i]->res_priv; + stripe_config = (struct cam_isp_dual_stripe_config *) + &stripe_args->dual_cfg->stripes[ports_plane_idx + i]; + wm_data->width = stripe_config->width; + wm_data->offset = stripe_config->offset; + wm_data->tile_cfg = stripe_config->tileconfig; + CAM_DBG(CAM_ISP, "id:%x wm:%d width:0x%x offset:%x tilecfg:%x", + stripe_args->res->res_id, i, wm_data->width, + wm_data->offset, wm_data->tile_cfg); + } + + return 0; +} + +static int cam_vfe_bus_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_start_vfe_out(hw_priv); +} + +static int cam_vfe_bus_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_stop_vfe_out(hw_priv); +} + +static int cam_vfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[2] = {0}; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + if (bus_priv->common_data.hw_init) + return 0; + + top_irq_reg_mask[0] = (1 << 9); + + bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_ver2_handle_irq, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + bus_priv->irq_handle = 0; + return -EFAULT; + } + + if (bus_priv->tasklet_info != NULL) { + bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.bus_irq_controller, + CAM_IRQ_PRIORITY_0, + bus_error_irq_mask, + bus_priv, + cam_vfe_bus_error_irq_top_half, + cam_vfe_bus_err_bottom_half, + bus_priv->tasklet_info, + &tasklet_bh_api); + + if (bus_priv->error_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS error IRQ %d", + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + return -EFAULT; + } + } + + /*Set Debug Registers*/ + cam_io_w_mb(CAM_VFE_BUS_SET_DEBUG_REG, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->debug_status_cfg); + + /* BUS_WR_INPUT_IF_ADDR_SYNC_FRAME_HEADER */ + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->addr_sync_frame_hdr); + + /* no clock gating at bus input */ + cam_io_w_mb(0xFFFFF, bus_priv->common_data.mem_base + 0x0000200C); + + /* BUS_WR_TEST_BUS_CTRL */ + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + 0x0000211C); + + /* if addr_no_sync has default value then config the addr no sync reg */ + cam_io_w_mb(CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL, + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->addr_sync_no_sync); + + bus_priv->common_data.hw_init = true; + + return 0; +} + +static int cam_vfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv = hw_priv; + int rc = 0, i; + unsigned long flags; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (!bus_priv->common_data.hw_init) + return 0; + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + + if (bus_priv->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->irq_handle); + bus_priv->irq_handle = 0; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + return rc; +} + +static int __cam_vfe_bus_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); +} + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_bus_ver2_priv *bus_priv; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + rc = cam_vfe_bus_update_wm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + rc = cam_vfe_bus_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + rc = cam_vfe_bus_update_stripe_cfg(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + if (bus_priv->error_irq_handle) { + CAM_DBG(CAM_ISP, "Mask off bus error irq handler"); + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + break; + case CAM_ISP_HW_CMD_UBWC_UPDATE: + rc = cam_vfe_bus_update_ubwc_config(cmd_args); + break; + case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: + rc = cam_vfe_bus_update_ubwc_config_v2(cmd_args); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_ver2_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver2_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info = bus_hw_info; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_ver2_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = ver2_hw_info->num_client; + bus_priv->num_out = ver2_hw_info->num_out; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &ver2_hw_info->common_reg; + bus_priv->common_data.addr_no_sync = + CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL; + bus_priv->common_data.hw_init = false; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &ver2_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller); + if (rc) { + CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + goto free_bus_priv; + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_init_wm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init WM failed rc=%d", rc); + goto deinit_wm; + } + } + + for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_init_comp_grp(i, bus_priv, bus_hw_info, + &bus_priv->comp_grp[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init Comp Grp failed rc=%d", rc); + goto deinit_comp_grp; + } + } + + for (i = 0; i < bus_priv->num_out; i++) { + rc = cam_vfe_bus_init_vfe_out_resource(i, bus_priv, + bus_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed rc=%d", rc); + goto deinit_vfe_out; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_acquire_vfe_out; + vfe_bus_local->hw_ops.release = cam_vfe_bus_release_vfe_out; + vfe_bus_local->hw_ops.start = cam_vfe_bus_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw; + vfe_bus_local->top_half_handler = cam_vfe_bus_ver2_handle_irq; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd; + + *vfe_bus = vfe_bus_local; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; + +deinit_vfe_out: + if (i < 0) + i = CAM_VFE_BUS_VER2_VFE_OUT_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]); + +deinit_comp_grp: + if (i < 0) + i = CAM_VFE_BUS_VER2_COMP_GRP_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + +deinit_wm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_ver2_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver2_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + unsigned long flags; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit WM failed rc=%d", rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit Comp Grp failed rc=%d", rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER2_VFE_OUT_MAX; i++) { + rc = cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit VFE Out failed rc=%d", rc); + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h new file mode 100644 index 000000000000..cac3adf65a93 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_VER2_H_ +#define _CAM_VFE_BUS_VER2_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_VER2_MAX_CLIENTS 24 + +enum cam_vfe_bus_ver2_vfe_core_id { + CAM_VFE_BUS_VER2_VFE_CORE_0, + CAM_VFE_BUS_VER2_VFE_CORE_1, + CAM_VFE_BUS_VER2_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_ver2_comp_grp_type { + CAM_VFE_BUS_VER2_COMP_GRP_0, + CAM_VFE_BUS_VER2_COMP_GRP_1, + CAM_VFE_BUS_VER2_COMP_GRP_2, + CAM_VFE_BUS_VER2_COMP_GRP_3, + CAM_VFE_BUS_VER2_COMP_GRP_4, + CAM_VFE_BUS_VER2_COMP_GRP_5, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5, + CAM_VFE_BUS_VER2_COMP_GRP_MAX, +}; + +enum cam_vfe_bus_ver2_vfe_out_type { + CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + CAM_VFE_BUS_VER2_VFE_OUT_RDI3, + CAM_VFE_BUS_VER2_VFE_OUT_FULL, + CAM_VFE_BUS_VER2_VFE_OUT_DS4, + CAM_VFE_BUS_VER2_VFE_OUT_DS16, + CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + CAM_VFE_BUS_VER2_VFE_OUT_FD, + CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_2PD, + CAM_VFE_BUS_VER2_VFE_OUT_MAX, +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_ovd; + uint32_t pwr_iso_cfg; + uint32_t dual_master_comp_cfg; + struct cam_irq_controller_reg_info irq_reg_info; + uint32_t comp_error_status; + uint32_t comp_ovrwr_status; + uint32_t dual_comp_error_status; + uint32_t dual_comp_ovrwr_status; + uint32_t addr_sync_cfg; + uint32_t addr_sync_frame_hdr; + uint32_t addr_sync_no_sync; + uint32_t debug_status_cfg; + uint32_t debug_status_0; +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_ubwc_client: + * + * @Brief: UBWC register offsets for BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_ubwc_client { + uint32_t tile_cfg; + uint32_t h_init; + uint32_t v_init; + uint32_t meta_addr; + uint32_t meta_offset; + uint32_t meta_stride; + uint32_t mode_cfg_0; + uint32_t bw_limit; +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_ubwc_client: + * + * @Brief: UBWC register offsets for BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client { + uint32_t tile_cfg; + uint32_t h_init; + uint32_t v_init; + uint32_t meta_addr; + uint32_t meta_offset; + uint32_t meta_stride; + uint32_t mode_cfg_0; + uint32_t mode_cfg_1; + uint32_t bw_limit; +}; + + +/* + * struct cam_vfe_bus_ver2_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_bus_client { + uint32_t status0; + uint32_t status1; + uint32_t cfg; + uint32_t header_addr; + uint32_t header_cfg; + uint32_t image_addr; + uint32_t image_addr_offset; + uint32_t buffer_width_cfg; + uint32_t buffer_height_cfg; + uint32_t packer_cfg; + uint32_t stride; + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t frame_inc; + uint32_t burst_limit; + void *ubwc_regs; +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_comp_grp: + * + * @Brief: Register offsets for Composite Group registers + * comp_mask: Comp group register address + * addr_sync_mask:Address sync group register address + */ +struct cam_vfe_bus_ver2_reg_offset_comp_grp { + uint32_t comp_mask; + uint32_t addr_sync_mask; +}; + +/* + * struct cam_vfe_bus_ver2_vfe_out_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_ver2_vfe_out_hw_info { + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_type; + uint32_t max_width; + uint32_t max_height; +}; + +/* + * struct cam_vfe_bus_ver2_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @bus_client_reg: Bus client register info + * @comp_reg_grp: Composite group register info + * @vfe_out_hw_info: VFE output capability + */ +struct cam_vfe_bus_ver2_hw_info { + struct cam_vfe_bus_ver2_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_ver2_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_VER2_MAX_CLIENTS]; + struct cam_vfe_bus_ver2_reg_offset_comp_grp + comp_grp_reg[CAM_VFE_BUS_VER2_COMP_GRP_MAX]; + uint32_t num_out; + struct cam_vfe_bus_ver2_vfe_out_hw_info + vfe_out_hw_info[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; +}; + +/* + * cam_vfe_bus_ver2_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver2_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_ver2_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver2_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_VER2_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c new file mode 100644 index 000000000000..f0dea326a8b0 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -0,0 +1,3924 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#include +#include +#include +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "../../cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_ver3.h" +#include "cam_vfe_core.h" +#include "cam_vfe_soc.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus"; + +#define CAM_VFE_BUS_VER3_IRQ_REG0 0 +#define CAM_VFE_BUS_VER3_IRQ_REG1 1 +#define CAM_VFE_BUS_VER3_IRQ_MAX 2 + +#define CAM_VFE_BUS_VER3_PAYLOAD_MAX 256 + +#define CAM_VFE_RDI_BUS_DEFAULT_WIDTH 0xFFFF +#define CAM_VFE_RDI_BUS_DEFAULT_STRIDE 0xFFFF +#define CAM_VFE_BUS_VER3_INTRA_CLIENT_MASK 0x3 + +#define MAX_BUF_UPDATE_REG_NUM \ + ((sizeof(struct cam_vfe_bus_ver3_reg_offset_bus_client) + \ + sizeof(struct cam_vfe_bus_ver3_reg_offset_ubwc_client))/4) +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +static uint32_t bus_error_irq_mask[2] = { + 0xC0000000, + 0x00000000, +}; + +enum cam_vfe_bus_ver3_packer_format { + PACKER_FMT_VER3_PLAIN_128, + PACKER_FMT_VER3_PLAIN_8, + PACKER_FMT_VER3_PLAIN_8_ODD_EVEN, + PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10, + PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10_ODD_EVEN, + PACKER_FMT_VER3_PLAIN_16_10BPP, + PACKER_FMT_VER3_PLAIN_16_12BPP, + PACKER_FMT_VER3_PLAIN_16_14BPP, + PACKER_FMT_VER3_PLAIN_16_16BPP, + PACKER_FMT_VER3_PLAIN_32, + PACKER_FMT_VER3_PLAIN_64, + PACKER_FMT_VER3_TP_10, + PACKER_FMT_VER3_MAX, +}; + +struct cam_vfe_bus_ver3_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_ver3_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct cam_vfe_bus_irq_evt_payload evt_payload[ + CAM_VFE_BUS_VER3_PAYLOAD_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t addr_no_sync; + uint32_t comp_done_shift; + bool is_lite; + bool hw_init; + cam_hw_mgr_event_cb_func event_cb; + int rup_irq_handle[CAM_VFE_BUS_VER3_SRC_GRP_MAX]; +}; + +struct cam_vfe_bus_ver3_wm_resource_data { + uint32_t index; + struct cam_vfe_bus_ver3_common_data *common_data; + struct cam_vfe_bus_ver3_reg_offset_bus_client *hw_regs; + + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + enum cam_vfe_bus_ver3_packer_format pack_fmt; + + uint32_t burst_len; + + uint32_t en_ubwc; + bool ubwc_updated; + uint32_t packer_cfg; + uint32_t h_init; + uint32_t ubwc_meta_addr; + uint32_t ubwc_meta_cfg; + uint32_t ubwc_mode_cfg; + uint32_t ubwc_stats_ctrl; + uint32_t ubwc_ctrl_2; + + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + + uint32_t en_cfg; + uint32_t is_dual; + + uint32_t ubwc_lossy_threshold_0; + uint32_t ubwc_lossy_threshold_1; + uint32_t ubwc_offset_lossy_variance; + uint32_t ubwc_bandwidth_limit; +}; + +struct cam_vfe_bus_ver3_comp_grp_data { + enum cam_vfe_bus_ver3_comp_grp_type comp_grp_type; + struct cam_vfe_bus_ver3_common_data *common_data; + + uint32_t is_master; + uint32_t is_dual; + uint32_t dual_slave_core; + uint32_t intra_client_mask; + uint32_t addr_sync_mode; + uint32_t composite_mask; + + uint32_t acquire_dev_cnt; + uint32_t irq_trigger_cnt; + uint32_t ubwc_static_ctrl; +}; + +struct cam_vfe_bus_ver3_vfe_out_data { + uint32_t out_type; + uint32_t source_group; + struct cam_vfe_bus_ver3_common_data *common_data; + + uint32_t num_wm; + struct cam_isp_resource_node *wm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_out_list; + + uint32_t is_master; + uint32_t is_dual; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; + void *priv; +}; + +struct cam_vfe_bus_ver3_priv { + struct cam_vfe_bus_ver3_common_data common_data; + uint32_t num_client; + uint32_t num_out; + uint32_t top_irq_shift; + + struct cam_isp_resource_node bus_client[CAM_VFE_BUS_VER3_MAX_CLIENTS]; + struct cam_isp_resource_node comp_grp[CAM_VFE_BUS_VER3_COMP_GRP_MAX]; + struct cam_isp_resource_node vfe_out[CAM_VFE_BUS_VER3_VFE_OUT_MAX]; + + struct list_head free_comp_grp; + struct list_head used_comp_grp; + + int irq_handle; + int error_irq_handle; + void *tasklet_info; +}; + +static int cam_vfe_bus_ver3_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + +static int cam_vfe_bus_ver3_get_evt_payload( + struct cam_vfe_bus_ver3_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + int rc; + + spin_lock(&common_data->spin_lock); + + if (!common_data->hw_init) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d Bus uninitialized", + common_data->core_index); + rc = -EPERM; + goto done; + } + + if (list_empty(&common_data->free_payload_list)) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free BUS event payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&common_data->free_payload_list, + struct cam_vfe_bus_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&common_data->spin_lock); + return rc; +} + +static int cam_vfe_bus_ver3_put_evt_payload( + struct cam_vfe_bus_ver3_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!common_data) { + CAM_ERR(CAM_ISP, "Invalid param common_data NULL"); + return -EINVAL; + } + + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&common_data->spin_lock, flags); + if (common_data->hw_init) + list_add_tail(&(*evt_payload)->list, + &common_data->free_payload_list); + spin_unlock_irqrestore(&common_data->spin_lock, flags); + + *evt_payload = NULL; + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_bus_ver3_get_intra_client_mask( + enum cam_vfe_bus_ver3_vfe_core_id dual_slave_core, + enum cam_vfe_bus_ver3_vfe_core_id current_core, + uint32_t *intra_client_mask) +{ + int rc = 0; + uint32_t version_based_intra_client_mask = 0x1; + + *intra_client_mask = 0; + + if (dual_slave_core == current_core) { + CAM_ERR(CAM_ISP, + "Invalid params. Same core as Master and Slave"); + return -EINVAL; + } + + switch (current_core) { + case CAM_VFE_BUS_VER3_VFE_CORE_0: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER3_VFE_CORE_1: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_CORE_1: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER3_VFE_CORE_0: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + default: + CAM_ERR(CAM_ISP, + "Invalid value for master core %u", current_core); + rc = -EINVAL; + break; + } + + return rc; +} + +static bool cam_vfe_bus_ver3_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_VER3_VFE_OUT_FULL: + case CAM_VFE_BUS_VER3_VFE_OUT_DS4: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16: + case CAM_VFE_BUS_VER3_VFE_OUT_FD: + case CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP: + case CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP: + return true; + + case CAM_VFE_BUS_VER3_VFE_OUT_2PD: + case CAM_VFE_BUS_VER3_VFE_OUT_LCR: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST: + default: + return false; + } +} + +static enum cam_vfe_bus_ver3_vfe_out_type + cam_vfe_bus_ver3_get_out_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_IFE_OUT_RES_FULL: + return CAM_VFE_BUS_VER3_VFE_OUT_FULL; + case CAM_ISP_IFE_OUT_RES_DS4: + return CAM_VFE_BUS_VER3_VFE_OUT_DS4; + case CAM_ISP_IFE_OUT_RES_DS16: + return CAM_VFE_BUS_VER3_VFE_OUT_DS16; + case CAM_ISP_IFE_OUT_RES_FD: + return CAM_VFE_BUS_VER3_VFE_OUT_FD; + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + return CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP; + case CAM_ISP_IFE_OUT_RES_2PD: + return CAM_VFE_BUS_VER3_VFE_OUT_2PD; + case CAM_ISP_IFE_OUT_RES_RDI_0: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI0; + case CAM_ISP_IFE_OUT_RES_RDI_1: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI1; + case CAM_ISP_IFE_OUT_RES_RDI_2: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI2; + case CAM_ISP_IFE_OUT_RES_RDI_3: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI3; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BF: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF; + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_RS: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS; + case CAM_ISP_IFE_OUT_RES_STATS_CS: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS; + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST; + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + return CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP; + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + return CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP; + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + return CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP; + case CAM_ISP_IFE_OUT_RES_LCR: + return CAM_VFE_BUS_VER3_VFE_OUT_LCR; + default: + return CAM_VFE_BUS_VER3_VFE_OUT_MAX; + } +} + +static int cam_vfe_bus_ver3_get_num_wm( + enum cam_vfe_bus_ver3_vfe_out_type res_type, + uint32_t format) +{ + switch (res_type) { + case CAM_VFE_BUS_VER3_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI3: + switch (format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_DPCM_10_6_10: + case CAM_FORMAT_DPCM_10_8_10: + case CAM_FORMAT_DPCM_12_6_12: + case CAM_FORMAT_DPCM_12_8_12: + case CAM_FORMAT_DPCM_14_8_14: + case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + case CAM_FORMAT_PLAIN128: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FULL: + case CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_UBWC_P010: + case CAM_FORMAT_PLAIN16_10: + return 2; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FD: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_PLAIN16_10: + return 2; + case CAM_FORMAT_Y_ONLY: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS4: + case CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP: + switch (format) { + case CAM_FORMAT_PD8: + case CAM_FORMAT_PD10: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP: + switch (format) { + case CAM_FORMAT_ARGB_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_2PD: + switch (format) { + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS: + switch (format) { + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST: + switch (format) { + case CAM_FORMAT_PLAIN16_16: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_LCR: + return 1; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported format %u for out_type:0x%X", + format, res_type); + + return -EINVAL; +} + +static int cam_vfe_bus_ver3_get_wm_idx( + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + bool is_lite) +{ + int wm_idx = -1; + + switch (vfe_out_res_id) { + case CAM_VFE_BUS_VER3_VFE_OUT_RDI0: + switch (plane) { + case PLANE_Y: + if (is_lite) + wm_idx = 0; + else + wm_idx = 23; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RDI1: + switch (plane) { + case PLANE_Y: + if (is_lite) + wm_idx = 1; + else + wm_idx = 24; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RDI2: + switch (plane) { + case PLANE_Y: + if (is_lite) + wm_idx = 2; + else + wm_idx = 25; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RDI3: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FULL: + switch (plane) { + case PLANE_Y: + wm_idx = 0; + break; + case PLANE_C: + wm_idx = 1; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS4: + switch (plane) { + case PLANE_Y: + wm_idx = 2; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS16: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FD: + switch (plane) { + case PLANE_Y: + wm_idx = 8; + break; + case PLANE_C: + wm_idx = 9; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP: + switch (plane) { + case PLANE_Y: + wm_idx = 10; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_2PD: + switch (plane) { + case PLANE_Y: + wm_idx = 21; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE: + switch (plane) { + case PLANE_Y: + wm_idx = 12; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 13; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 14; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF: + switch (plane) { + case PLANE_Y: + wm_idx = 20; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 15; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 16; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS: + switch (plane) { + case PLANE_Y: + wm_idx = 17; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS: + switch (plane) { + case PLANE_Y: + wm_idx = 18; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 19; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 4; + break; + case PLANE_C: + wm_idx = 5; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 6; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 7; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_LCR: + switch (plane) { + case PLANE_Y: + wm_idx = 22; + break; + default: + break; + } + default: + break; + } + + return wm_idx; +} + +static int cam_vfe_bus_ver3_get_comp_vfe_out_res_id_list( + uint32_t comp_mask, uint32_t *out_list, int *num_out, bool is_lite) +{ + int count = 0; + + if (is_lite) + goto vfe_lite; + + if (comp_mask & 0x3) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL; + + if (comp_mask & 0x4) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4; + + if (comp_mask & 0x8) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16; + + if (comp_mask & 0x30) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL_DISP; + + if (comp_mask & 0x40) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4_DISP; + + if (comp_mask & 0x80) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16_DISP; + + if (comp_mask & 0x300) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FD; + + if (comp_mask & 0x400) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RAW_DUMP; + + if (comp_mask & 0x1000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BE; + + if (comp_mask & 0x2000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST; + + if (comp_mask & 0x4000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_TL_BG; + + if (comp_mask & 0x8000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_AWB_BG; + + if (comp_mask & 0x10000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BHIST; + + if (comp_mask & 0x20000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_RS; + + if (comp_mask & 0x40000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_CS; + + if (comp_mask & 0x80000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_IHIST; + + if (comp_mask & 0x100000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BF; + + if (comp_mask & 0x200000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_2PD; + + if (comp_mask & 0x400000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_LCR; + + if (comp_mask & 0x800000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_0; + + if (comp_mask & 0x1000000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (comp_mask & 0x2000000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_2; + + *num_out = count; + return 0; + +vfe_lite: + if (comp_mask & 0x1) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_0; + + if (comp_mask & 0x2) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (comp_mask & 0x4) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_2; + + if (comp_mask & 0x8) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_3; + + *num_out = count; + return 0; +} + +static enum cam_vfe_bus_ver3_packer_format + cam_vfe_bus_ver3_get_packer_fmt(uint32_t out_fmt, int wm_index) +{ + switch (out_fmt) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PD8: + return PACKER_FMT_VER3_PLAIN_128; + case CAM_FORMAT_PLAIN8: + return PACKER_FMT_VER3_PLAIN_8; + case CAM_FORMAT_NV21: + if ((wm_index == 1) || (wm_index == 3) || (wm_index == 5)) + return PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10_ODD_EVEN; + case CAM_FORMAT_NV12: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_Y_ONLY: + return PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10; + case CAM_FORMAT_PLAIN16_10: + return PACKER_FMT_VER3_PLAIN_16_10BPP; + case CAM_FORMAT_PLAIN16_12: + return PACKER_FMT_VER3_PLAIN_16_12BPP; + case CAM_FORMAT_PLAIN16_14: + return PACKER_FMT_VER3_PLAIN_16_14BPP; + case CAM_FORMAT_PLAIN16_16: + return PACKER_FMT_VER3_PLAIN_16_16BPP; + case CAM_FORMAT_PLAIN32: + case CAM_FORMAT_ARGB: + return PACKER_FMT_VER3_PLAIN_32; + case CAM_FORMAT_PLAIN64: + case CAM_FORMAT_ARGB_16: + case CAM_FORMAT_PD10: + return PACKER_FMT_VER3_PLAIN_64; + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_TP10: + return PACKER_FMT_VER3_TP_10; + default: + return PACKER_FMT_VER3_MAX; + } +} + +static int cam_vfe_bus_ver3_handle_rup_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + vfe_out = th_payload->handler_priv; + if (!vfe_out) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + + rsrc_data = vfe_out->res_priv; + + CAM_DBG(CAM_ISP, "VFE:%d Bus IRQ status_0: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0]); + + rc = cam_vfe_bus_ver3_get_evt_payload(rsrc_data->common_data, + &evt_payload); + + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d Bus IRQ status_0: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0]); + return rc; + } + + evt_payload->core_index = rsrc_data->common_data->core_index; + evt_payload->evt_id = evt_id; + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_bus_ver3_handle_rup_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_vfe_bus_irq_evt_payload *payload; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + payload = evt_payload_priv; + vfe_out = handler_priv; + rsrc_data = vfe_out->res_priv; + + if (!rsrc_data->common_data->event_cb) { + CAM_ERR(CAM_ISP, "Callback to HW MGR not found"); + return ret; + } + + irq_status = payload->irq_reg_val[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + evt_info.hw_idx = rsrc_data->common_data->core_index; + evt_info.res_type = CAM_ISP_RESOURCE_VFE_IN; + + if (!rsrc_data->common_data->is_lite) { + if (irq_status & 0x1) { + CAM_DBG(CAM_ISP, "VFE:%d Received CAMIF RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_CAMIF; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x2) { + CAM_DBG(CAM_ISP, "VFE:%d Received PDLIB RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_PDLIB; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x4) + CAM_DBG(CAM_ISP, "VFE:%d Received LCR RUP", + evt_info.hw_idx); + + if (irq_status & 0x8) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI0 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI0; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x10) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI1 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI1; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x20) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI2 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI2; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + } else { + if (irq_status & 0x1) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI0 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI0; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x2) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI1 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI1; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x4) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI2 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI2; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x8) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI3 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI3; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + } + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + CAM_DBG(CAM_ISP, + "VFE:%d Bus RUP IRQ status_0:0x%X rc:%d", + evt_info.hw_idx, CAM_ISP_HW_EVENT_REG_UPDATE, irq_status, ret); + + cam_vfe_bus_ver3_put_evt_payload(rsrc_data->common_data, &payload); + + return ret; +} + +static int cam_vfe_bus_ver3_acquire_wm( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + struct cam_isp_resource_node **wm_res, + uint32_t *client_done_mask, + uint32_t is_dual, + enum cam_vfe_bus_ver3_comp_grp_type *comp_grp_id) +{ + int32_t wm_idx = 0; + struct cam_isp_resource_node *wm_res_local = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = NULL; + + *wm_res = NULL; + + /* VFE OUT to WM is fixed. */ + wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, plane, + ver3_bus_priv->common_data.is_lite); + if (wm_idx < 0 || wm_idx >= ver3_bus_priv->num_client || + plane > PLANE_C) { + CAM_ERR(CAM_ISP, + "Unsupported VFE out_type:0x%X plane:%d wm_idx:%d max_idx:%d", + vfe_out_res_id, plane, wm_idx, + ver3_bus_priv->num_client - 1); + return -EINVAL; + } + + wm_res_local = &ver3_bus_priv->bus_client[wm_idx]; + if (wm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "WM:%d not available state:%d", + wm_idx, wm_res_local->res_state); + return -EALREADY; + } + wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + wm_res_local->tasklet_info = tasklet; + + rsrc_data = wm_res_local->res_priv; + rsrc_data->format = out_port_info->format; + rsrc_data->pack_fmt = cam_vfe_bus_ver3_get_packer_fmt(rsrc_data->format, + wm_idx); + + rsrc_data->width = out_port_info->width; + rsrc_data->height = out_port_info->height; + rsrc_data->is_dual = is_dual; + /* Set WM offset value to default */ + rsrc_data->offset = 0; + CAM_DBG(CAM_ISP, "WM:%d width %d height %d", rsrc_data->index, + rsrc_data->width, rsrc_data->height); + + if (ver3_bus_priv->common_data.is_lite) + goto rdi_config; + + if (rsrc_data->index > 22) { +rdi_config: + /* WM 23-25 refers to RDI 0/ RDI 1/RDI 2 */ + switch (rsrc_data->format) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN128: + rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->pack_fmt = 0x0; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + break; + case CAM_FORMAT_PLAIN8: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0x1; + rsrc_data->stride = rsrc_data->width * 2; + break; + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->pack_fmt = 0x0; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + break; + case CAM_FORMAT_PLAIN64: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0xA; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported RDI format %d", + rsrc_data->format); + return -EINVAL; + } + } else if ((rsrc_data->index < 2) || + (rsrc_data->index == 8) || (rsrc_data->index == 9) || + (rsrc_data->index == 4) || (rsrc_data->index == 5)) { + /* + * WM 0-1 FULL_OUT, WM 8-9 FD_OUT, + * WM 4-5 FULL_DISP + */ + switch (rsrc_data->format) { + case CAM_FORMAT_UBWC_NV12_4R: + rsrc_data->en_ubwc = 1; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_NV12: + rsrc_data->en_ubwc = 1; + /* Fall through for NV12 */ + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_Y_ONLY: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_TP10: + rsrc_data->en_ubwc = 1; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_TP10: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_PLAIN16_10: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid format %d", + rsrc_data->format); + return -EINVAL; + } + rsrc_data->en_cfg = 0x1; + } else if (rsrc_data->index == 20) { + /* WM 20 stats BAF */ + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } else if (rsrc_data->index > 11 && rsrc_data->index < 20) { + /* WM 12-19 stats */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } else if (rsrc_data->index == 21) { + /* WM 21 PD */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } else if (rsrc_data->index == 10) { + /* WM 10 Raw dump */ + rsrc_data->stride = rsrc_data->width; + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + } else if (rsrc_data->index == 22) { + switch (rsrc_data->format) { + case CAM_FORMAT_PLAIN16_16: + rsrc_data->stride = ALIGNUP(rsrc_data->width * 2, 8); + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + break; + default: + CAM_ERR(CAM_ISP, "Invalid format %d", + rsrc_data->format); + return -EINVAL; + } + } else if ((rsrc_data->index == 2) || (rsrc_data->index == 3) || + (rsrc_data->index == 6) || (rsrc_data->index == 7)) { + /* Write master 2-3 and 6-7 DS ports */ + + rsrc_data->height = rsrc_data->height / 2; + rsrc_data->width = rsrc_data->width / 2; + rsrc_data->en_cfg = 0x1; + + } else { + CAM_ERR(CAM_ISP, "Invalid WM:%d requested", rsrc_data->index); + return -EINVAL; + } + + *wm_res = wm_res_local; + *comp_grp_id = rsrc_data->hw_regs->comp_group; + *client_done_mask |= (1 << wm_idx); + + CAM_DBG(CAM_ISP, + "VFE:%d WM:%d processed width:%d height:%d format:0x%X en_ubwc:%d", + rsrc_data->common_data->core_index, rsrc_data->index, + rsrc_data->width, rsrc_data->height, rsrc_data->format, + rsrc_data->en_ubwc); + return 0; +} + +static int cam_vfe_bus_ver3_release_wm(void *bus_priv, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = + wm_res->res_priv; + + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->pack_fmt = 0; + rsrc_data->burst_len = 0; + rsrc_data->irq_subsample_period = 0; + rsrc_data->irq_subsample_pattern = 0; + rsrc_data->framedrop_period = 0; + rsrc_data->framedrop_pattern = 0; + rsrc_data->packer_cfg = 0; + rsrc_data->en_ubwc = 0; + rsrc_data->h_init = 0; + rsrc_data->ubwc_meta_addr = 0; + rsrc_data->ubwc_meta_cfg = 0; + rsrc_data->ubwc_mode_cfg = 0; + rsrc_data->ubwc_stats_ctrl = 0; + rsrc_data->ubwc_ctrl_2 = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->ubwc_updated = false; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rsrc_data->ubwc_lossy_threshold_0 = 0; + rsrc_data->ubwc_lossy_threshold_1 = 0; + rsrc_data->ubwc_offset_lossy_variance = 0; + rsrc_data->ubwc_bandwidth_limit = 0; + wm_res->tasklet_info = NULL; + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + CAM_DBG(CAM_ISP, "VFE:%d Release WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + return 0; +} + +static int cam_vfe_bus_ver3_start_wm(struct cam_isp_resource_node *wm_res) +{ + int val = 0; + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver3_common_data *common_data = + rsrc_data->common_data; + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_regs; + + ubwc_regs = (struct cam_vfe_bus_ver3_reg_offset_ubwc_client *) + rsrc_data->hw_regs->ubwc_regs; + + cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); + + cam_io_w((rsrc_data->height << 16) | rsrc_data->width, + common_data->mem_base + rsrc_data->hw_regs->image_cfg_0); + cam_io_w(rsrc_data->pack_fmt, + common_data->mem_base + rsrc_data->hw_regs->packer_cfg); + + /* Configure stride for RDIs on full IFE */ + if (!common_data->is_lite && rsrc_data->index > 22) + cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + + rsrc_data->hw_regs->image_cfg_2)); + + /* Configure stride for RDIs on IFE lite */ + if (common_data->is_lite) + cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + + rsrc_data->hw_regs->image_cfg_2)); + + /* enable ubwc if needed*/ + if (rsrc_data->en_ubwc) { + val = cam_io_r_mb(common_data->mem_base + ubwc_regs->mode_cfg); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + ubwc_regs->mode_cfg); + } + + /* Enable WM */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + + rsrc_data->hw_regs->cfg); + + CAM_DBG(CAM_ISP, + "Start VFE:%d WM:%d offset:0x%X en_cfg:0x%X width:%d height:%d", + rsrc_data->common_data->core_index, rsrc_data->index, + (uint32_t) rsrc_data->hw_regs->cfg, rsrc_data->en_cfg, + rsrc_data->width, rsrc_data->height); + CAM_DBG(CAM_ISP, "WM:%d pk_fmt:%d stride:%d burst len:%d", + rsrc_data->index, rsrc_data->pack_fmt & PACKER_FMT_VER3_MAX, + rsrc_data->stride, 0xF); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_vfe_bus_ver3_stop_wm(struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver3_common_data *common_data = + rsrc_data->common_data; + + /* Disable WM */ + cam_io_w_mb(0x0, common_data->mem_base + rsrc_data->hw_regs->cfg); + CAM_DBG(CAM_ISP, "Stop VFE:%d WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->ubwc_updated = false; + + return 0; +} + +static int cam_vfe_bus_ver3_handle_wm_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_ver3_handle_wm_done_bottom_half(void *wm_node, + void *evt_payload_priv) +{ + return -EPERM; +} + +static int cam_vfe_bus_ver3_init_wm_resource(uint32_t index, + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver3_wm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for WM res priv"); + return -ENOMEM; + } + wm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &ver3_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver3_bus_priv->common_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = cam_vfe_bus_ver3_start_wm; + wm_res->stop = cam_vfe_bus_ver3_stop_wm; + wm_res->top_half_handler = cam_vfe_bus_ver3_handle_wm_done_top_half; + wm_res->bottom_half_handler = + cam_vfe_bus_ver3_handle_wm_done_bottom_half; + wm_res->hw_intf = ver3_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_wm_resource( + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = NULL; + wm_res->stop = NULL; + wm_res->top_half_handler = NULL; + wm_res->bottom_half_handler = NULL; + wm_res->hw_intf = NULL; + + rsrc_data = wm_res->res_priv; + wm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static void cam_vfe_bus_ver3_add_wm_to_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t composite_mask) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = comp_grp->res_priv; + + rsrc_data->composite_mask |= composite_mask; +} + +static bool cam_vfe_bus_ver3_match_comp_grp( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_resource_node **comp_grp, + uint32_t comp_grp_id) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + struct cam_isp_resource_node *comp_grp_local = NULL; + + list_for_each_entry(comp_grp_local, + &ver3_bus_priv->used_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_type == comp_grp_id) { + /* Match found */ + *comp_grp = comp_grp_local; + return true; + } + } + + list_for_each_entry(comp_grp_local, + &ver3_bus_priv->free_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_type == comp_grp_id) { + /* Match found */ + *comp_grp = comp_grp_local; + list_del(&comp_grp_local->list); + list_add_tail(&comp_grp_local->list, + &ver3_bus_priv->used_comp_grp); + return false; + } + } + + *comp_grp = NULL; + return false; +} + +static int cam_vfe_bus_ver3_acquire_comp_grp( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + uint32_t is_dual, + uint32_t is_master, + enum cam_vfe_bus_ver3_vfe_core_id dual_slave_core, + struct cam_isp_resource_node **comp_grp, + enum cam_vfe_bus_ver3_comp_grp_type comp_grp_id) +{ + int rc = 0; + struct cam_isp_resource_node *comp_grp_local = NULL; + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + bool previously_acquired = false; + + if (comp_grp_id >= CAM_VFE_BUS_VER3_COMP_GRP_0 && + comp_grp_id <= CAM_VFE_BUS_VER3_COMP_GRP_13) { + /* Check if matching comp_grp has already been acquired */ + previously_acquired = cam_vfe_bus_ver3_match_comp_grp( + ver3_bus_priv, &comp_grp_local, comp_grp_id); + } + + if (!comp_grp_local) { + CAM_ERR(CAM_ISP, "Invalid comp_grp:%d", comp_grp_id); + return -ENODEV; + } + + rsrc_data = comp_grp_local->res_priv; + + if (!previously_acquired) { + if (is_dual) { + rc = cam_vfe_bus_ver3_get_intra_client_mask( + dual_slave_core, + comp_grp_local->hw_intf->hw_idx, + &rsrc_data->intra_client_mask); + if (rc) + return rc; + } + + comp_grp_local->tasklet_info = tasklet; + comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + rsrc_data->is_master = is_master; + rsrc_data->is_dual = is_dual; + + if (is_master) + rsrc_data->addr_sync_mode = 0; + else + rsrc_data->addr_sync_mode = 1; + + } else { + rsrc_data = comp_grp_local->res_priv; + /* Do not support runtime change in composite mask */ + if (comp_grp_local->res_state == + CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d comp_grp:%u", + comp_grp_local->res_state, + rsrc_data->comp_grp_type); + return -EBUSY; + } + } + + CAM_DBG(CAM_ISP, "Acquire VFE:%d comp_grp:%u", + rsrc_data->common_data->core_index, rsrc_data->comp_grp_type); + + rsrc_data->acquire_dev_cnt++; + *comp_grp = comp_grp_local; + + return rc; +} + +static int cam_vfe_bus_ver3_release_comp_grp( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_resource_node *in_comp_grp) +{ + struct cam_isp_resource_node *comp_grp = NULL; + struct cam_vfe_bus_ver3_comp_grp_data *in_rsrc_data = NULL; + int match_found = 0; + + if (!in_comp_grp) { + CAM_ERR(CAM_ISP, "Invalid Params comp_grp %pK", in_comp_grp); + return -EINVAL; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Already released comp_grp"); + return 0; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d", + in_comp_grp->res_state); + return -EBUSY; + } + + in_rsrc_data = in_comp_grp->res_priv; + CAM_DBG(CAM_ISP, "Release VFE:%d comp_grp:%u", + ver3_bus_priv->common_data.core_index, + in_rsrc_data->comp_grp_type); + + list_for_each_entry(comp_grp, &ver3_bus_priv->used_comp_grp, list) { + if (comp_grp == in_comp_grp) { + match_found = 1; + break; + } + } + + if (!match_found) { + CAM_ERR(CAM_ISP, "Could not find comp_grp:%u", + in_rsrc_data->comp_grp_type); + return -ENODEV; + } + + in_rsrc_data->acquire_dev_cnt--; + if (in_rsrc_data->acquire_dev_cnt == 0) { + list_del(&comp_grp->list); + + in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER3_VFE_CORE_MAX; + in_rsrc_data->addr_sync_mode = 0; + in_rsrc_data->composite_mask = 0; + + comp_grp->tasklet_info = NULL; + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + list_add_tail(&comp_grp->list, &ver3_bus_priv->free_comp_grp); + } + + return 0; +} + +static int cam_vfe_bus_ver3_start_comp_grp( + struct cam_isp_resource_node *comp_grp, uint32_t *bus_irq_reg_mask) +{ + int rc = 0; + uint32_t val; + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_common_data *common_data = NULL; + + rsrc_data = comp_grp->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, + "Start VFE:%d comp_grp:%d streaming state:%d comp_mask:0x%X", + rsrc_data->common_data->core_index, + rsrc_data->comp_grp_type, comp_grp->res_state, + rsrc_data->composite_mask); + + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + return 0; + + if (rsrc_data->is_dual) { + if (rsrc_data->is_master) { + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val |= (0x1 << (rsrc_data->comp_grp_type + 14)); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_1); + + val |= (0x1 << rsrc_data->comp_grp_type); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_1); + } else { + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val |= (0x1 << rsrc_data->comp_grp_type); + val |= (0x1 << (rsrc_data->comp_grp_type + 14)); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_1); + + val |= (0x1 << rsrc_data->comp_grp_type); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_1); + } + } + + if (rsrc_data->ubwc_static_ctrl) { + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->ubwc_static_ctrl); + val |= rsrc_data->ubwc_static_ctrl; + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->ubwc_static_ctrl); + } + + bus_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0] = + (0x1 << (rsrc_data->comp_grp_type + + rsrc_data->common_data->comp_done_shift)); + + CAM_DBG(CAM_ISP, "Start Done VFE:%d comp_grp:%d bus_irq_mask_0: 0x%X", + rsrc_data->common_data->core_index, + rsrc_data->comp_grp_type, + bus_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0]); + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static int cam_vfe_bus_ver3_stop_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return 0; +} + +static int cam_vfe_bus_ver3_handle_comp_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_ver3_handle_comp_done_bottom_half( + void *handler_priv, + void *evt_payload_priv, + uint32_t *comp_mask) +{ + int rc = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *comp_grp = handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = comp_grp->res_priv; + uint32_t *cam_ife_irq_regs; + uint32_t status_0; + + if (!evt_payload) + return rc; + + if (rsrc_data->is_dual && (!rsrc_data->is_master)) { + CAM_ERR(CAM_ISP, "Invalid comp_grp:%u is_master:%u", + rsrc_data->comp_grp_type, rsrc_data->is_master); + return rc; + } + + cam_ife_irq_regs = evt_payload->irq_reg_val; + status_0 = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + if (status_0 & BIT(rsrc_data->comp_grp_type + + rsrc_data->common_data->comp_done_shift)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + CAM_DBG(CAM_ISP, "VFE:%d comp_grp:%d Bus IRQ status_0: 0x%X rc:%d", + rsrc_data->common_data->core_index, rsrc_data->comp_grp_type, + status_0, rc); + + *comp_mask = rsrc_data->composite_mask; + + return rc; +} + +static int cam_vfe_bus_ver3_init_comp_grp(uint32_t index, + struct cam_hw_soc_info *soc_info, + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info, + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + struct cam_vfe_soc_private *vfe_soc_private = soc_info->soc_private; + int ddr_type = 0; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver3_comp_grp_data), + GFP_KERNEL); + if (!rsrc_data) + return -ENOMEM; + + comp_grp->res_priv = rsrc_data; + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&comp_grp->list); + + rsrc_data->comp_grp_type = index; + rsrc_data->common_data = &ver3_bus_priv->common_data; + rsrc_data->dual_slave_core = CAM_VFE_BUS_VER3_VFE_CORE_MAX; + + if (rsrc_data->comp_grp_type != CAM_VFE_BUS_VER3_COMP_GRP_0 && + rsrc_data->comp_grp_type != CAM_VFE_BUS_VER3_COMP_GRP_1) + rsrc_data->ubwc_static_ctrl = 0; + else { + ddr_type = of_fdt_get_ddrtype(); + if ((ddr_type == DDR_TYPE_LPDDR5) || + (ddr_type == DDR_TYPE_LPDDR5X)) + rsrc_data->ubwc_static_ctrl = + vfe_soc_private->ubwc_static_ctrl[1]; + else + rsrc_data->ubwc_static_ctrl = + vfe_soc_private->ubwc_static_ctrl[0]; + } + + list_add_tail(&comp_grp->list, &ver3_bus_priv->free_comp_grp); + + comp_grp->top_half_handler = cam_vfe_bus_ver3_handle_comp_done_top_half; + comp_grp->hw_intf = ver3_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = + comp_grp->res_priv; + + comp_grp->start = NULL; + comp_grp->stop = NULL; + comp_grp->top_half_handler = NULL; + comp_grp->bottom_half_handler = NULL; + comp_grp->hw_intf = NULL; + + list_del_init(&comp_grp->list); + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + + comp_grp->res_priv = NULL; + + if (!rsrc_data) { + CAM_ERR(CAM_ISP, "comp_grp_priv is NULL"); + return -ENODEV; + } + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_ver3_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + bool *mode = cmd_args; + struct cam_isp_resource_node *res = + (struct cam_isp_resource_node *) priv; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = + (struct cam_vfe_bus_ver3_vfe_out_data *)res->res_priv; + + *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? + true : false; + + return 0; +} + +static int cam_vfe_bus_ver3_acquire_vfe_out(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id; + uint32_t format; + int num_wm; + struct cam_vfe_bus_ver3_priv *ver3_bus_priv = bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *out_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + enum cam_vfe_bus_ver3_comp_grp_type comp_grp_id; + uint32_t client_done_mask = 0; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + out_acquire_args = &acq_args->vfe_out; + format = out_acquire_args->out_port_info->format; + + CAM_DBG(CAM_ISP, "VFE:%d Acquire out_type:0x%X", + ver3_bus_priv->common_data.core_index, + out_acquire_args->out_port_info->res_type); + + vfe_out_res_id = cam_vfe_bus_ver3_get_out_res_id( + out_acquire_args->out_port_info->res_type); + if (vfe_out_res_id == CAM_VFE_BUS_VER3_VFE_OUT_MAX) + return -ENODEV; + + num_wm = cam_vfe_bus_ver3_get_num_wm(vfe_out_res_id, format); + if (num_wm < 1) + return -EINVAL; + + rsrc_node = &ver3_bus_priv->vfe_out[vfe_out_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "VFE:%d out_type:0x%X resource not available state:%d", + ver3_bus_priv->common_data.core_index, + vfe_out_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + + secure_caps = cam_vfe_bus_ver3_can_be_secure( + rsrc_data->out_type); + mode = out_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + ver3_bus_priv->tasklet_info = acq_args->tasklet; + rsrc_data->num_wm = num_wm; + rsrc_node->res_id = out_acquire_args->out_port_info->res_type; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = out_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = out_acquire_args->cdm_ops; + + /* Acquire WM and retrieve COMP GRP ID */ + for (i = 0; i < num_wm; i++) { + rc = cam_vfe_bus_ver3_acquire_wm(ver3_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + vfe_out_res_id, + i, + &rsrc_data->wm_res[i], + &client_done_mask, + out_acquire_args->is_dual, + &comp_grp_id); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to acquire WM VFE:%d out_type:%d rc:%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + goto release_wm; + } + } + + /* Acquire composite group using COMP GRP ID */ + rc = cam_vfe_bus_ver3_acquire_comp_grp(ver3_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + out_acquire_args->is_dual, + out_acquire_args->is_master, + out_acquire_args->dual_slave_core, + &rsrc_data->comp_grp, + comp_grp_id); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to acquire comp_grp VFE:%d out_typp:%d rc:%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + return rc; + } + + rsrc_data->is_dual = out_acquire_args->is_dual; + rsrc_data->is_master = out_acquire_args->is_master; + + cam_vfe_bus_ver3_add_wm_to_comp_grp(rsrc_data->comp_grp, + client_done_mask); + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + out_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_wm: + for (i--; i >= 0; i--) + cam_vfe_bus_ver3_release_wm(ver3_bus_priv, + rsrc_data->wm_res[i]); + + cam_vfe_bus_ver3_release_comp_grp(ver3_bus_priv, rsrc_data->comp_grp); + + return rc; +} + +static int cam_vfe_bus_ver3_release_vfe_out(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_out = release_args; + rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, + "Invalid resource state:%d VFE:%d out_type:0x%X", + vfe_out->res_state, rsrc_data->common_data->core_index, + vfe_out->res_id); + } + + for (i = 0; i < rsrc_data->num_wm; i++) + cam_vfe_bus_ver3_release_wm(bus_priv, rsrc_data->wm_res[i]); + rsrc_data->num_wm = 0; + + if (rsrc_data->comp_grp) + cam_vfe_bus_ver3_release_comp_grp(bus_priv, + rsrc_data->comp_grp); + rsrc_data->comp_grp = NULL; + + vfe_out->tasklet_info = NULL; + vfe_out->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_ver3_can_be_secure(rsrc_data->out_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_ver3_start_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_MAX]; + uint32_t rup_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_MAX]; + uint32_t source_group = 0; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + source_group = rsrc_data->source_group; + + CAM_DBG(CAM_ISP, "Start VFE:%d out_type:0x%X", + rsrc_data->common_data->core_index, rsrc_data->out_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, + "Invalid resource state:%d VFE:%d out_type:0x%X", + vfe_out->res_state, rsrc_data->common_data->core_index, + rsrc_data->out_type); + return -EACCES; + } + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_ver3_start_wm(rsrc_data->wm_res[i]); + + memset(bus_irq_reg_mask, 0, sizeof(bus_irq_reg_mask)); + rc = cam_vfe_bus_ver3_start_comp_grp(rsrc_data->comp_grp, + bus_irq_reg_mask); + + if (rsrc_data->is_dual && !rsrc_data->is_master) + goto end; + + vfe_out->irq_handle = cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, + CAM_IRQ_PRIORITY_1, + bus_irq_reg_mask, + vfe_out, + vfe_out->top_half_handler, + vfe_out->bottom_half_handler, + vfe_out->tasklet_info, + &tasklet_bh_api); + + if (vfe_out->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Subscribe IRQ failed for VFE out_res %d", + vfe_out->res_id); + vfe_out->irq_handle = 0; + return -EFAULT; + } + + if (!common_data->rup_irq_handle[source_group]) { + memset(rup_irq_reg_mask, 0, sizeof(rup_irq_reg_mask)); + rup_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0] |= + 0x1 << source_group; + + CAM_DBG(CAM_ISP, + "VFE:%d out_type:0x%X bus_irq_mask_0:0x%X for RUP", + rsrc_data->common_data->core_index, rsrc_data->out_type, + rup_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0]); + + common_data->rup_irq_handle[source_group] = + cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, + CAM_IRQ_PRIORITY_1, + rup_irq_reg_mask, + vfe_out, + cam_vfe_bus_ver3_handle_rup_top_half, + cam_vfe_bus_ver3_handle_rup_bottom_half, + vfe_out->tasklet_info, + &tasklet_bh_api); + + if (common_data->rup_irq_handle[source_group] < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe RUP IRQ"); + common_data->rup_irq_handle[source_group] = 0; + return -EFAULT; + } + } + +end: + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_ver3_stop_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "Stop VFE:%d out_type:0x%X state:%d", + rsrc_data->common_data->core_index, rsrc_data->out_type, + vfe_out->res_state); + return rc; + } + + rc = cam_vfe_bus_ver3_stop_comp_grp(rsrc_data->comp_grp); + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_ver3_stop_wm(rsrc_data->wm_res[i]); + + if (common_data->rup_irq_handle[rsrc_data->source_group]) { + rc = cam_irq_controller_unsubscribe_irq( + common_data->bus_irq_controller, + common_data->rup_irq_handle[rsrc_data->source_group]); + common_data->rup_irq_handle[rsrc_data->source_group] = 0; + } + + if (vfe_out->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + common_data->bus_irq_controller, + vfe_out->irq_handle); + vfe_out->irq_handle = 0; + } + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + vfe_out = th_payload->handler_priv; + if (!vfe_out) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + + rsrc_data = vfe_out->res_priv; + + CAM_DBG(CAM_ISP, "VFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + + rc = cam_vfe_bus_ver3_get_evt_payload(rsrc_data->common_data, + &evt_payload); + + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + evt_payload->core_index = rsrc_data->common_data->core_index; + evt_payload->evt_id = evt_id; + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_bus_ver3_handle_vfe_out_done_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int rc = -EINVAL, num_out = 0, i = 0; + struct cam_isp_resource_node *vfe_out = handler_priv; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = vfe_out->res_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_isp_hw_event_info evt_info; + void *ctx = NULL; + uint32_t evt_id = 0, comp_mask = 0; + uint32_t out_list[CAM_VFE_BUS_VER3_VFE_OUT_MAX]; + + rc = cam_vfe_bus_ver3_handle_comp_done_bottom_half( + rsrc_data->comp_grp, evt_payload_priv, &comp_mask); + CAM_DBG(CAM_ISP, "VFE:%d out_type:0x%X rc:%d", + rsrc_data->common_data->core_index, rsrc_data->out_type, + rsrc_data->out_type, rc); + + ctx = rsrc_data->priv; + memset(out_list, 0, sizeof(out_list)); + + switch (rc) { + case CAM_VFE_IRQ_STATUS_SUCCESS: + evt_id = evt_payload->evt_id; + + evt_info.res_type = vfe_out->res_type; + evt_info.hw_idx = vfe_out->hw_intf->hw_idx; + + rc = cam_vfe_bus_ver3_get_comp_vfe_out_res_id_list( + comp_mask, out_list, &num_out, + rsrc_data->common_data->is_lite); + for (i = 0; i < num_out; i++) { + evt_info.res_id = out_list[i]; + if (rsrc_data->common_data->event_cb) + rsrc_data->common_data->event_cb(ctx, evt_id, + (void *)&evt_info); + } + break; + default: + break; + } + + cam_vfe_bus_ver3_put_evt_payload(rsrc_data->common_data, &evt_payload); + + return rc; +} + +static int cam_vfe_bus_ver3_init_vfe_out_resource(uint32_t index, + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info) +{ + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_out_type = + ver3_hw_info->vfe_out_hw_info[index].vfe_out_type; + + if (vfe_out_type < 0 || + vfe_out_type >= CAM_VFE_BUS_VER3_VFE_OUT_MAX) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_out_type); + return -EINVAL; + } + + vfe_out = &ver3_bus_priv->vfe_out[vfe_out_type]; + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_out->res_priv) { + CAM_ERR(CAM_ISP, "vfe_out_type %d has already been initialized", + vfe_out_type); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver3_vfe_out_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_out->res_priv = rsrc_data; + + vfe_out->res_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + + rsrc_data->source_group = + ver3_hw_info->vfe_out_hw_info[index].source_group; + rsrc_data->out_type = + ver3_hw_info->vfe_out_hw_info[index].vfe_out_type; + rsrc_data->common_data = &ver3_bus_priv->common_data; + rsrc_data->max_width = + ver3_hw_info->vfe_out_hw_info[index].max_width; + rsrc_data->max_height = + ver3_hw_info->vfe_out_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_out->start = cam_vfe_bus_ver3_start_vfe_out; + vfe_out->stop = cam_vfe_bus_ver3_stop_vfe_out; + vfe_out->top_half_handler = + cam_vfe_bus_ver3_handle_vfe_out_done_top_half; + vfe_out->bottom_half_handler = + cam_vfe_bus_ver3_handle_vfe_out_done_bottom_half; + vfe_out->process_cmd = cam_vfe_bus_ver3_process_cmd; + vfe_out->hw_intf = ver3_bus_priv->common_data.hw_intf; + vfe_out->irq_handle = 0; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_vfe_out_resource( + struct cam_isp_resource_node *vfe_out) +{ + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "VFE:%d out_type:%d already deinitialized", + rsrc_data->common_data->core_index, + rsrc_data->out_type); + return 0; + } + + vfe_out->start = NULL; + vfe_out->stop = NULL; + vfe_out->top_half_handler = NULL; + vfe_out->bottom_half_handler = NULL; + vfe_out->hw_intf = NULL; + vfe_out->irq_handle = 0; + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + vfe_out->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static void cam_vfe_bus_ver3_print_dimensions( + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + struct cam_vfe_bus_ver3_priv *bus_priv) +{ + struct cam_isp_resource_node *wm_res = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + int wm_idx = 0; + + wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, plane, + bus_priv->common_data.is_lite); + + if (wm_idx < 0 || wm_idx >= bus_priv->num_client || plane > PLANE_C) { + CAM_ERR(CAM_ISP, + "Unsupported VFE out_type:0x%X plane:%d wm_idx:%d max_idx:%d", + vfe_out_res_id, plane, wm_idx, + bus_priv->num_client - 1); + return; + } + + wm_res = &bus_priv->bus_client[wm_idx]; + wm_data = wm_res->res_priv; + + CAM_INFO(CAM_ISP, + "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u", + wm_data->common_data->core_index, wm_idx, wm_data->width, + wm_data->height, wm_data->stride, wm_data->h_init, + wm_data->en_cfg); +} + +static int cam_vfe_bus_ver3_handle_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + int rc = 0; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "Enter"); + rc = cam_irq_controller_handle_irq(evt_id, + bus_priv->common_data.bus_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; +} + +static int cam_vfe_bus_ver3_err_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int i = 0, rc = 0; + struct cam_vfe_bus_ver3_priv *bus_priv = + th_payload->handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d BUS Err IRQ", + bus_priv->common_data.core_index); + for (i = 0; i < th_payload->num_registers; i++) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d BUS IRQ status_%d: 0x%X", + bus_priv->common_data.core_index, i, + th_payload->evt_status_arr[i]); + } + cam_irq_controller_disable_irq(bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + + rc = cam_vfe_bus_ver3_get_evt_payload(&bus_priv->common_data, + &evt_payload); + if (rc) + return rc; + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->core_index = bus_priv->common_data.core_index; + + evt_payload->ccif_violation_status = cam_io_r_mb( + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->ccif_violation_status); + + evt_payload->image_size_violation_status = cam_io_r_mb( + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->image_size_violation_status); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_bus_ver3_err_irq_bottom_half( + void *handler_priv, void *evt_payload_priv) +{ + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver3_priv *bus_priv = handler_priv; + struct cam_vfe_bus_ver3_common_data *common_data; + struct cam_isp_hw_event_info evt_info; + uint32_t val = 0, image_size_violation = 0, ccif_violation = 0; + + if (!handler_priv || !evt_payload_priv) + return -EINVAL; + + common_data = &bus_priv->common_data; + + val = evt_payload->irq_reg_val[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + image_size_violation = (val >> 31) & 0x1; + ccif_violation = (val >> 30) & 0x1; + + CAM_ERR(CAM_ISP, + "VFE:%d BUS Violation image_size_violation %d ccif_violation %d", + bus_priv->common_data.core_index, image_size_violation, + ccif_violation); + CAM_INFO(CAM_ISP, + "image_size_violation_status 0x%X ccif_violation_status 0x%X", + evt_payload->image_size_violation_status, + evt_payload->ccif_violation_status); + + if (common_data->is_lite) { + if (image_size_violation) { + val = evt_payload->image_size_violation_status; + + if (val & 0x01) { + CAM_INFO(CAM_ISP, + "RDI 0 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + PLANE_Y, + bus_priv); + } + + if (val & 0x02) { + CAM_INFO(CAM_ISP, + "RDI 1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + PLANE_Y, + bus_priv); + } + + if (val & 0x04) { + CAM_INFO(CAM_ISP, + "RDI 2 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + PLANE_Y, + bus_priv); + } + + if (val & 0x08) { + CAM_INFO(CAM_ISP, + "RDI 3 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI3, + PLANE_Y, + bus_priv); + } + } + + if (ccif_violation) { + val = evt_payload->ccif_violation_status; + + if (val & 0x01) + CAM_INFO(CAM_ISP, + "RDI 0 ccif violation"); + + if (val & 0x02) + CAM_INFO(CAM_ISP, + "RDI 1 ccif violation"); + + if (val & 0x04) + CAM_INFO(CAM_ISP, + "RDI 2 ccif violation"); + + if (val & 0x08) + CAM_INFO(CAM_ISP, + "RDI 3 ccif violation"); + } + + goto end; + } + + if (image_size_violation) { + val = evt_payload->image_size_violation_status; + + if (val & 0x01) { + CAM_INFO(CAM_ISP, "VID Y 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL, + PLANE_Y, + bus_priv); + } + + if (val & 0x02) { + CAM_INFO(CAM_ISP, "VID C 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL, + PLANE_C, + bus_priv); + } + + if (val & 0x04) { + CAM_INFO(CAM_ISP, "VID YC 4:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS4, + PLANE_Y, + bus_priv); + } + + if (val & 0x08) { + CAM_INFO(CAM_ISP, "VID YC 16:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS16, + PLANE_Y, + bus_priv); + } + + if (val & 0x010) { + CAM_INFO(CAM_ISP, "DISP Y 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + PLANE_Y, + bus_priv); + } + + if (val & 0x020) { + CAM_INFO(CAM_ISP, "DISP C 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + PLANE_C, + bus_priv); + } + + if (val & 0x040) { + CAM_INFO(CAM_ISP, "DISP YC 4:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, + PLANE_Y, + bus_priv); + } + + if (val & 0x080) { + CAM_INFO(CAM_ISP, "DISP YC 16:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, + PLANE_Y, + bus_priv); + } + + if (val & 0x0100) { + CAM_INFO(CAM_ISP, "FD Y image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FD, + PLANE_Y, + bus_priv); + } + + if (val & 0x0200) { + CAM_INFO(CAM_ISP, "FD C image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FD, + PLANE_C, + bus_priv); + } + + if (val & 0x0400) { + CAM_INFO(CAM_ISP, + "PIXEL RAW DUMP image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, + PLANE_Y, + bus_priv); + } + + if (val & 0x01000) { + CAM_INFO(CAM_ISP, "STATS HDR BE image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, + PLANE_Y, + bus_priv); + } + + if (val & 0x02000) { + CAM_INFO(CAM_ISP, + "STATS HDR BHIST image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, + PLANE_Y, + bus_priv); + } + + if (val & 0x04000) { + CAM_INFO(CAM_ISP, + "STATS TINTLESS BG image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, + PLANE_Y, + bus_priv); + } + + if (val & 0x08000) { + CAM_INFO(CAM_ISP, "STATS AWB BG image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, + PLANE_Y, + bus_priv); + } + + if (val & 0x010000) { + CAM_INFO(CAM_ISP, "STATS BHIST image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, + PLANE_Y, + bus_priv); + } + + if (val & 0x020000) { + CAM_INFO(CAM_ISP, "STATS RS image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, + PLANE_Y, + bus_priv); + } + + if (val & 0x040000) { + CAM_INFO(CAM_ISP, "STATS CS image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, + PLANE_Y, + bus_priv); + } + + if (val & 0x080000) { + CAM_INFO(CAM_ISP, "STATS IHIST image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, + PLANE_Y, + bus_priv); + } + + if (val & 0x0100000) { + CAM_INFO(CAM_ISP, "STATS BAF image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, + PLANE_Y, + bus_priv); + } + + if (val & 0x0200000) { + CAM_INFO(CAM_ISP, "PD image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_2PD, + PLANE_Y, + bus_priv); + } + + if (val & 0x0400000) { + CAM_INFO(CAM_ISP, "LCR image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_LCR, + PLANE_Y, + bus_priv); + } + + if (val & 0x0800000) { + CAM_INFO(CAM_ISP, "RDI 0 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + PLANE_Y, + bus_priv); + } + + if (val & 0x01000000) { + CAM_INFO(CAM_ISP, "RDI 1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + PLANE_Y, + bus_priv); + } + + if (val & 0x02000000) { + CAM_INFO(CAM_ISP, "RDI 2 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + PLANE_Y, + bus_priv); + } + + } + + if (ccif_violation) { + val = evt_payload->ccif_violation_status; + + if (val & 0x01) + CAM_INFO(CAM_ISP, "VID Y 1:1 ccif violation"); + + if (val & 0x02) + CAM_INFO(CAM_ISP, "VID C 1:1 ccif violation"); + + if (val & 0x04) + CAM_INFO(CAM_ISP, "VID YC 4:1 ccif violation"); + + if (val & 0x08) + CAM_INFO(CAM_ISP, "VID YC 16:1 ccif violation"); + + if (val & 0x010) + CAM_INFO(CAM_ISP, "DISP Y 1:1 ccif violation"); + + if (val & 0x020) + CAM_INFO(CAM_ISP, "DISP C 1:1 ccif violation"); + + if (val & 0x040) + CAM_INFO(CAM_ISP, "DISP YC 4:1 ccif violation"); + + if (val & 0x080) + CAM_INFO(CAM_ISP, "DISP YC 16:1 ccif violation"); + + if (val & 0x0100) + CAM_INFO(CAM_ISP, "FD Y ccif violation"); + + if (val & 0x0200) + CAM_INFO(CAM_ISP, "FD C ccif violation"); + + if (val & 0x0400) + CAM_INFO(CAM_ISP, "PIXEL RAW DUMP ccif violation"); + + if (val & 0x01000) + CAM_INFO(CAM_ISP, "STATS HDR BE ccif violation"); + + if (val & 0x02000) + CAM_INFO(CAM_ISP, "STATS HDR BHIST ccif violation"); + + if (val & 0x04000) + CAM_INFO(CAM_ISP, "STATS TINTLESS BG ccif violation"); + + if (val & 0x08000) + CAM_INFO(CAM_ISP, "STATS AWB BG ccif violation"); + + if (val & 0x010000) + CAM_INFO(CAM_ISP, "STATS BHIST ccif violation"); + + if (val & 0x020000) + CAM_INFO(CAM_ISP, "STATS RS ccif violation"); + + if (val & 0x040000) + CAM_INFO(CAM_ISP, "STATS CS ccif violation"); + + if (val & 0x080000) + CAM_INFO(CAM_ISP, "STATS IHIST ccif violation"); + + if (val & 0x0100000) + CAM_INFO(CAM_ISP, "STATS BAF ccif violation"); + + if (val & 0x0200000) + CAM_INFO(CAM_ISP, "PD ccif violation"); + + if (val & 0x0400000) + CAM_INFO(CAM_ISP, "LCR ccif violation"); + + if (val & 0x0800000) + CAM_INFO(CAM_ISP, "RDI 0 ccif violation"); + + if (val & 0x01000000) + CAM_INFO(CAM_ISP, "RDI 1 ccif violation"); + + if (val & 0x02000000) + CAM_INFO(CAM_ISP, "RDI 2 ccif violation"); + + } + +end: + cam_vfe_bus_ver3_put_evt_payload(common_data, &evt_payload); + + evt_info.hw_idx = common_data->core_index; + evt_info.res_type = CAM_ISP_RESOURCE_VFE_OUT; + evt_info.res_id = CAM_VFE_BUS_VER3_VFE_OUT_MAX; + evt_info.err_type = CAM_VFE_IRQ_STATUS_VIOLATION; + + if (common_data->event_cb) + common_data->event_cb(NULL, CAM_ISP_HW_EVENT_ERROR, + (void *)&evt_info); + return 0; +} + +static void cam_vfe_bus_ver3_update_ubwc_meta_addr( + uint32_t *reg_val_pair, + uint32_t *j, + void *regs, + uint64_t image_buf) +{ + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_regs; + + if (!regs || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver3_reg_offset_ubwc_client *)regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_addr, image_buf); + +end: + return; +} + +static int cam_vfe_bus_ver3_update_ubwc_regs( + struct cam_vfe_bus_ver3_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_regs; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver3_reg_offset_ubwc_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM:%d packer cfg 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_cfg, wm_data->ubwc_meta_cfg); + CAM_DBG(CAM_ISP, "WM:%d meta stride 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg, wm_data->ubwc_mode_cfg); + CAM_DBG(CAM_ISP, "WM:%d ubwc_mode_cfg 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->ctrl_2, wm_data->ubwc_ctrl_2); + CAM_DBG(CAM_ISP, "WM:%d ubwc_ctrl_2 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->lossy_thresh0, wm_data->ubwc_lossy_threshold_0); + CAM_DBG(CAM_ISP, "WM:%d lossy_thresh0 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->lossy_thresh1, wm_data->ubwc_lossy_threshold_1); + CAM_DBG(CAM_ISP, "WM:%d lossy_thresh1 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->off_lossy_var, wm_data->ubwc_offset_lossy_variance); + CAM_DBG(CAM_ISP, "WM:%d off_lossy_var 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->ubwc_bandwidth_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, wm_data->ubwc_bandwidth_limit); + CAM_DBG(CAM_ISP, "WM:%d ubwc bw limit 0x%X", + wm_data->index, wm_data->ubwc_bandwidth_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_client = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, k, size = 0; + uint32_t frame_inc = 0, val; + uint32_t loop_size = 0; + + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + update_buf->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + if (update_buf->wm_update->num_buf != vfe_out_data->num_wm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->wm_update->num_buf, vfe_out_data->num_wm); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + io_cfg = update_buf->wm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_client = wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, wm_data->en_cfg); + CAM_DBG(CAM_ISP, "WM:%d en_cfg 0x%X", + wm_data->index, reg_val_pair[j-1]); + + val = (wm_data->height << 16) | wm_data->width; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_0, val); + CAM_DBG(CAM_ISP, "WM:%d image height and width 0x%X", + wm_data->index, reg_val_pair[j-1]); + + /* For initial configuration program all bus registers */ + val = io_cfg->planes[i].plane_stride; + CAM_DBG(CAM_ISP, "before stride %d", val); + val = ALIGNUP(val, 16); + if (val != io_cfg->planes[i].plane_stride && + val != wm_data->stride) + CAM_WARN(CAM_ISP, "Warning stride %u expected %u", + io_cfg->planes[i].plane_stride, val); + + if ((wm_data->stride != val || + !wm_data->init_cfg_done) && + (!bus_priv->common_data.is_lite && + wm_data->index < 23)) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_2, + io_cfg->planes[i].plane_stride); + wm_data->stride = val; + CAM_DBG(CAM_ISP, "WM:%d image stride 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->en_ubwc) { + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + return -EINVAL; + } + if (wm_data->ubwc_updated) { + wm_data->ubwc_updated = false; + cam_vfe_bus_ver3_update_ubwc_regs( + wm_data, reg_val_pair, i, &j); + } + + /* UBWC meta address */ + cam_vfe_bus_ver3_update_ubwc_meta_addr( + reg_val_pair, &j, + wm_data->hw_regs->ubwc_regs, + update_buf->wm_update->image_buf[i]); + CAM_DBG(CAM_ISP, "WM:%d ubwc meta addr 0x%llx", + wm_data->index, + update_buf->wm_update->image_buf[i]); + } + + if (wm_data->en_ubwc) { + frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height, 4096); + frame_inc += io_cfg->planes[i].meta_size; + CAM_DBG(CAM_ISP, + "WM:%d frm %d: ht: %d stride %d meta: %d", + wm_data->index, frame_inc, + io_cfg->planes[i].slice_height, + io_cfg->planes[i].plane_stride, + io_cfg->planes[i].meta_size); + } else { + frame_inc = io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height; + } + + if (!(wm_data->en_cfg & (0x3 << 16))) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_1, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM:%d h_init 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + if ((!bus_priv->common_data.is_lite && wm_data->index > 22) || + bus_priv->common_data.is_lite) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_ubwc) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size + + k * frame_inc); + else if (wm_data->en_cfg & (0x3 << 16)) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc)); + else + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + k * frame_inc)); + + CAM_DBG(CAM_ISP, "WM:%d image address 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_incr, frame_inc); + CAM_DBG(CAM_ISP, "WM:%d frame_inc %d", + wm_data->index, reg_val_pair[j-1]); + + + /* enable the WM */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, + wm_data->en_cfg); + + /* set initial configuration done */ + if (!wm_data->init_cfg_done) + wm_data->init_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_ver3_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_hfr; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_isp_port_hfr_config *hfr_cfg = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + update_hfr = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + update_hfr->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + hfr_cfg = update_hfr->hfr_update; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + + if (((!bus_priv->common_data.is_lite && wm_data->index > 22) || + bus_priv->common_data.is_lite) && + hfr_cfg->subsample_period > 3) { + CAM_ERR(CAM_ISP, + "RDI doesn't support irq subsample period %d", + hfr_cfg->subsample_period); + return -EINVAL; + } + + if ((wm_data->framedrop_pattern != + hfr_cfg->framedrop_pattern) || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_pattern, + hfr_cfg->framedrop_pattern); + wm_data->framedrop_pattern = hfr_cfg->framedrop_pattern; + CAM_DBG(CAM_ISP, "WM:%d framedrop pattern 0x%X", + wm_data->index, wm_data->framedrop_pattern); + } + + if (wm_data->framedrop_period != hfr_cfg->framedrop_period || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_period, + hfr_cfg->framedrop_period); + wm_data->framedrop_period = hfr_cfg->framedrop_period; + CAM_DBG(CAM_ISP, "WM:%d framedrop period 0x%X", + wm_data->index, wm_data->framedrop_period); + } + + if (wm_data->irq_subsample_period != hfr_cfg->subsample_period + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_period, + hfr_cfg->subsample_period); + wm_data->irq_subsample_period = + hfr_cfg->subsample_period; + CAM_DBG(CAM_ISP, "WM:%d irq subsample period 0x%X", + wm_data->index, wm_data->irq_subsample_period); + } + + if (wm_data->irq_subsample_pattern != hfr_cfg->subsample_pattern + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_pattern, + hfr_cfg->subsample_pattern); + wm_data->irq_subsample_pattern = + hfr_cfg->subsample_pattern; + CAM_DBG(CAM_ISP, "WM:%d irq subsample pattern 0x%X", + wm_data->index, wm_data->irq_subsample_pattern); + } + + /* set initial configuration done */ + if (!wm_data->hfr_cfg_done) + wm_data->hfr_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_hfr->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_hfr->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_hfr->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_hfr->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_ver3_update_ubwc_config_v2(void *cmd_args) +{ + struct cam_isp_hw_get_cmd_update *update_ubwc; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_vfe_generic_ubwc_config *ubwc_generic_cfg = NULL; + struct cam_vfe_generic_ubwc_plane_config *ubwc_generic_plane_cfg = NULL; + uint32_t i; + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + update_ubwc->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid data"); + rc = -EINVAL; + goto end; + } + + ubwc_generic_cfg = update_ubwc->ubwc_config; + + for (i = 0; i < vfe_out_data->num_wm; i++) { + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_generic_plane_cfg = &ubwc_generic_cfg->ubwc_plane_cfg[i]; + + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + rc = -EINVAL; + goto end; + } + + if (!wm_data->en_ubwc) { + CAM_ERR(CAM_ISP, "UBWC Disabled"); + rc = -EINVAL; + goto end; + } + + if (wm_data->packer_cfg != + ubwc_generic_plane_cfg->packer_config || + !wm_data->init_cfg_done) { + wm_data->packer_cfg = + ubwc_generic_plane_cfg->packer_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->h_init != + ubwc_generic_plane_cfg->h_init) || + !wm_data->init_cfg_done)) { + wm_data->h_init = ubwc_generic_plane_cfg->h_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_cfg != + ubwc_generic_plane_cfg->meta_stride || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_cfg = + ubwc_generic_plane_cfg->meta_stride; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg != + ubwc_generic_plane_cfg->mode_config_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg = + ubwc_generic_plane_cfg->mode_config_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_ctrl_2 != + ubwc_generic_plane_cfg->ctrl_2 || + !wm_data->init_cfg_done) { + wm_data->ubwc_ctrl_2 = + ubwc_generic_plane_cfg->ctrl_2; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_0 != + ubwc_generic_plane_cfg->lossy_threshold_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_0 = + ubwc_generic_plane_cfg->lossy_threshold_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_1 != + ubwc_generic_plane_cfg->lossy_threshold_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_1 = + ubwc_generic_plane_cfg->lossy_threshold_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_offset_lossy_variance != + ubwc_generic_plane_cfg->lossy_var_offset || + !wm_data->init_cfg_done) { + wm_data->ubwc_offset_lossy_variance = + ubwc_generic_plane_cfg->lossy_var_offset; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_bandwidth_limit != + ubwc_generic_plane_cfg->bandwidth_limit || + !wm_data->init_cfg_done) { + wm_data->ubwc_bandwidth_limit = + ubwc_generic_plane_cfg->bandwidth_limit; + wm_data->ubwc_updated = true; + } + } + +end: + return rc; +} + +static int cam_vfe_bus_ver3_update_stripe_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + struct cam_isp_hw_dual_isp_update_args *stripe_args; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_isp_dual_stripe_config *stripe_config; + uint32_t outport_id, ports_plane_idx, i; + + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + stripe_args = (struct cam_isp_hw_dual_isp_update_args *)cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + stripe_args->res->res_priv; + + if (!vfe_out_data) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + outport_id = stripe_args->res->res_id & 0xFF; + if (stripe_args->res->res_id < CAM_ISP_IFE_OUT_RES_BASE || + stripe_args->res->res_id >= CAM_ISP_IFE_OUT_RES_MAX) + return 0; + + ports_plane_idx = (stripe_args->split_id * + (stripe_args->dual_cfg->num_ports * CAM_PACKET_MAX_PLANES)) + + (outport_id * CAM_PACKET_MAX_PLANES); + for (i = 0; i < vfe_out_data->num_wm; i++) { + wm_data = vfe_out_data->wm_res[i]->res_priv; + stripe_config = (struct cam_isp_dual_stripe_config *) + &stripe_args->dual_cfg->stripes[ports_plane_idx + i]; + wm_data->width = stripe_config->width; + + /* + * UMD sends buffer offset address as offset for clients + * programmed to operate in frame/index based mode and h_init + * value as offset for clients programmed to operate in line + * based mode. + */ + + if (wm_data->en_cfg & (0x3 << 16)) + wm_data->offset = stripe_config->offset; + else + wm_data->h_init = stripe_config->offset; + + CAM_DBG(CAM_ISP, + "out_type:0x%X WM:%d width:%d offset:0x%X h_init:%d", + stripe_args->res->res_id, wm_data->index, + wm_data->width, wm_data->offset, wm_data->h_init); + } + + return 0; +} + +static int cam_vfe_bus_ver3_update_wm_config( + void *cmd_args) +{ + int i; + struct cam_isp_hw_get_cmd_update *wm_config_update; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_isp_vfe_wm_config *wm_config = NULL; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + wm_config_update = cmd_args; + vfe_out_data = wm_config_update->res->res_priv; + wm_config = wm_config_update->wm_config; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops || !wm_config) { + CAM_ERR(CAM_ISP, "Invalid data"); + return -EINVAL; + } + + for (i = 0; i < vfe_out_data->num_wm; i++) { + wm_data = vfe_out_data->wm_res[i]->res_priv; + + if (wm_config->wm_mode > 0x2) { + CAM_ERR(CAM_ISP, "Invalid wm_mode: 0x%X WM:%d", + wm_config->wm_mode, wm_data->index); + return -EINVAL; + } + + wm_data->en_cfg = (wm_config->wm_mode << 16) | 0x1; + wm_data->height = wm_config->height; + wm_data->width = wm_config->width; + + CAM_DBG(CAM_ISP, + "WM:%d en_cfg:0x%X height:%d width:%d", + wm_data->index, wm_data->en_cfg, wm_data->height, + wm_data->width); + } + + return 0; +} + +static int cam_vfe_bus_ver3_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_ver3_start_vfe_out(hw_priv); +} + +static int cam_vfe_bus_ver3_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_ver3_stop_vfe_out(hw_priv); +} + +static int cam_vfe_bus_ver3_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[3] = {0}; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + if (bus_priv->common_data.hw_init) + return 0; + + top_irq_reg_mask[0] = (1 << bus_priv->top_irq_shift); + + bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_ver3_handle_irq, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + bus_priv->irq_handle = 0; + return -EFAULT; + } + + if (bus_priv->tasklet_info != NULL) { + bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.bus_irq_controller, + CAM_IRQ_PRIORITY_0, + bus_error_irq_mask, + bus_priv, + cam_vfe_bus_ver3_err_irq_top_half, + cam_vfe_bus_ver3_err_irq_bottom_half, + bus_priv->tasklet_info, + &tasklet_bh_api); + + if (bus_priv->error_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS Error IRQ"); + bus_priv->error_irq_handle = 0; + return -EFAULT; + } + } + + /* no clock gating at bus input */ + CAM_INFO(CAM_ISP, "Overriding clock gating at bus input"); + cam_io_w_mb(0x3FFFFFF, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->cgc_ovd); + + /* BUS_WR_TEST_BUS_CTRL */ + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->test_bus_ctrl); + + bus_priv->common_data.hw_init = true; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv = hw_priv; + int rc = 0, i; + unsigned long flags; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (!bus_priv->common_data.hw_init) + return 0; + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + + if (bus_priv->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->irq_handle); + bus_priv->irq_handle = 0; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER3_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + return rc; +} + +static int __cam_vfe_bus_ver3_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + return cam_vfe_bus_ver3_process_cmd(priv, cmd_type, cmd_args, arg_size); +} + +static int cam_vfe_bus_ver3_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_bus_ver3_priv *bus_priv; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + rc = cam_vfe_bus_ver3_update_wm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + rc = cam_vfe_bus_ver3_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_ver3_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + rc = cam_vfe_bus_ver3_update_stripe_cfg(priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + if (bus_priv->error_irq_handle) { + CAM_DBG(CAM_ISP, "Mask off bus error irq handler"); + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + break; + case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: + rc = cam_vfe_bus_ver3_update_ubwc_config_v2(cmd_args); + break; + case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + rc = cam_vfe_bus_ver3_update_wm_config(cmd_args); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_ver3_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver3_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info = bus_hw_info; + struct cam_vfe_soc_private *soc_private = NULL; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + rc = -ENODEV; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_ver3_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = ver3_hw_info->num_client; + bus_priv->num_out = ver3_hw_info->num_out; + bus_priv->top_irq_shift = ver3_hw_info->top_irq_shift; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &ver3_hw_info->common_reg; + bus_priv->common_data.comp_done_shift = + ver3_hw_info->comp_done_shift; + bus_priv->common_data.hw_init = false; + + bus_priv->common_data.is_lite = soc_private->is_ife_lite; + + for (i = 0; i < CAM_VFE_BUS_VER3_SRC_GRP_MAX; i++) + bus_priv->common_data.rup_irq_handle[i] = 0; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &ver3_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller); + if (rc) { + CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + goto free_bus_priv; + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_ver3_init_wm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "VFE:%d init WM:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_wm; + } + } + + for (i = 0; i < CAM_VFE_BUS_VER3_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_ver3_init_comp_grp(i, soc_info, + bus_priv, bus_hw_info, + &bus_priv->comp_grp[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "VFE:%d init comp_grp:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_comp_grp; + } + } + + for (i = 0; i < bus_priv->num_out; i++) { + rc = cam_vfe_bus_ver3_init_vfe_out_resource(i, bus_priv, + bus_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "VFE:%d init out_type:0x%X failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_vfe_out; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER3_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_ver3_acquire_vfe_out; + vfe_bus_local->hw_ops.release = cam_vfe_bus_ver3_release_vfe_out; + vfe_bus_local->hw_ops.start = cam_vfe_bus_ver3_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_ver3_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_ver3_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_ver3_deinit_hw; + vfe_bus_local->top_half_handler = cam_vfe_bus_ver3_handle_irq; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_ver3_process_cmd; + + *vfe_bus = vfe_bus_local; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; + +deinit_vfe_out: + if (i < 0) + i = CAM_VFE_BUS_VER3_VFE_OUT_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_ver3_deinit_vfe_out_resource(&bus_priv->vfe_out[i]); + +deinit_comp_grp: + if (i < 0) + i = CAM_VFE_BUS_VER3_COMP_GRP_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_ver3_deinit_comp_grp(&bus_priv->comp_grp[i]); + +deinit_wm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_ver3_deinit_wm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_ver3_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver3_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + unsigned long flags; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER3_PAYLOAD_MAX; i++) + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_ver3_deinit_wm_resource( + &bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "VFE:%d deinit WM:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER3_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_ver3_deinit_comp_grp(&bus_priv->comp_grp[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "VFE:%d deinit comp_grp:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER3_VFE_OUT_MAX; i++) { + rc = cam_vfe_bus_ver3_deinit_vfe_out_resource( + &bus_priv->vfe_out[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "VFE:%d deinit out_type:0x%X failed rc:%d", + bus_priv->common_data.core_index, i, rc); + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h new file mode 100644 index 000000000000..c5b4ab69fa9f --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_VFE_BUS_VER3_H_ +#define _CAM_VFE_BUS_VER3_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_VER3_MAX_CLIENTS 26 +#define CAM_VFE_BUS_VER3_MAX_SUB_GRPS 6 + +enum cam_vfe_bus_ver3_vfe_core_id { + CAM_VFE_BUS_VER3_VFE_CORE_0, + CAM_VFE_BUS_VER3_VFE_CORE_1, + CAM_VFE_BUS_VER3_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_ver3_src_grp { + CAM_VFE_BUS_VER3_SRC_GRP_0, + CAM_VFE_BUS_VER3_SRC_GRP_1, + CAM_VFE_BUS_VER3_SRC_GRP_2, + CAM_VFE_BUS_VER3_SRC_GRP_3, + CAM_VFE_BUS_VER3_SRC_GRP_4, + CAM_VFE_BUS_VER3_SRC_GRP_5, + CAM_VFE_BUS_VER3_SRC_GRP_MAX, +}; + +enum cam_vfe_bus_ver3_comp_grp_type { + CAM_VFE_BUS_VER3_COMP_GRP_0, + CAM_VFE_BUS_VER3_COMP_GRP_1, + CAM_VFE_BUS_VER3_COMP_GRP_2, + CAM_VFE_BUS_VER3_COMP_GRP_3, + CAM_VFE_BUS_VER3_COMP_GRP_4, + CAM_VFE_BUS_VER3_COMP_GRP_5, + CAM_VFE_BUS_VER3_COMP_GRP_6, + CAM_VFE_BUS_VER3_COMP_GRP_7, + CAM_VFE_BUS_VER3_COMP_GRP_8, + CAM_VFE_BUS_VER3_COMP_GRP_9, + CAM_VFE_BUS_VER3_COMP_GRP_10, + CAM_VFE_BUS_VER3_COMP_GRP_11, + CAM_VFE_BUS_VER3_COMP_GRP_12, + CAM_VFE_BUS_VER3_COMP_GRP_13, + CAM_VFE_BUS_VER3_COMP_GRP_MAX, +}; + +enum cam_vfe_bus_ver3_vfe_out_type { + CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + CAM_VFE_BUS_VER3_VFE_OUT_RDI3, + CAM_VFE_BUS_VER3_VFE_OUT_FULL, + CAM_VFE_BUS_VER3_VFE_OUT_DS4, + CAM_VFE_BUS_VER3_VFE_OUT_DS16, + CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, + CAM_VFE_BUS_VER3_VFE_OUT_FD, + CAM_VFE_BUS_VER3_VFE_OUT_PDAF, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, + CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, + CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, + CAM_VFE_BUS_VER3_VFE_OUT_2PD, + CAM_VFE_BUS_VER3_VFE_OUT_LCR, + CAM_VFE_BUS_VER3_VFE_OUT_MAX, +}; + +/* + * struct cam_vfe_bus_ver3_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_ver3_reg_offset_common { + uint32_t hw_version; + uint32_t cgc_ovd; + uint32_t comp_cfg_0; + uint32_t comp_cfg_1; + uint32_t if_frameheader_cfg[CAM_VFE_BUS_VER3_MAX_SUB_GRPS]; + uint32_t ubwc_static_ctrl; + uint32_t pwr_iso_cfg; + uint32_t overflow_status_clear; + uint32_t ccif_violation_status; + uint32_t overflow_status; + uint32_t image_size_violation_status; + uint32_t debug_status_top_cfg; + uint32_t debug_status_top; + uint32_t test_bus_ctrl; + struct cam_irq_controller_reg_info irq_reg_info; +}; + +/* + * struct cam_vfe_bus_ver3_reg_offset_ubwc_client: + * + * @Brief: UBWC register offsets for BUS Clients + */ +struct cam_vfe_bus_ver3_reg_offset_ubwc_client { + uint32_t meta_addr; + uint32_t meta_cfg; + uint32_t mode_cfg; + uint32_t stats_ctrl; + uint32_t ctrl_2; + uint32_t lossy_thresh0; + uint32_t lossy_thresh1; + uint32_t off_lossy_var; + uint32_t bw_limit; +}; + +/* + * struct cam_vfe_bus_ver3_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_ver3_reg_offset_bus_client { + uint32_t cfg; + uint32_t image_addr; + uint32_t frame_incr; + uint32_t image_cfg_0; + uint32_t image_cfg_1; + uint32_t image_cfg_2; + uint32_t packer_cfg; + uint32_t frame_header_addr; + uint32_t frame_header_incr; + uint32_t frame_header_cfg; + uint32_t line_done_cfg; + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t burst_limit; + uint32_t system_cache_cfg; + void *ubwc_regs; + uint32_t addr_status_0; + uint32_t addr_status_1; + uint32_t addr_status_2; + uint32_t addr_status_3; + uint32_t debug_status_cfg; + uint32_t debug_status_0; + uint32_t debug_status_1; + uint32_t comp_group; +}; + +/* + * struct cam_vfe_bus_ver3_vfe_out_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_ver3_vfe_out_hw_info { + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_type; + uint32_t max_width; + uint32_t max_height; + uint32_t source_group; +}; + +/* + * struct cam_vfe_bus_ver3_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @num_client: Total number of write clients + * @bus_client_reg: Bus client register info + * @vfe_out_hw_info: VFE output capability + * @comp_done_shift: Mask shift for comp done mask + * @top_irq_shift: Mask shift for top level BUS WR irq + */ +struct cam_vfe_bus_ver3_hw_info { + struct cam_vfe_bus_ver3_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_ver3_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_VER3_MAX_CLIENTS]; + uint32_t num_out; + struct cam_vfe_bus_ver3_vfe_out_hw_info + vfe_out_hw_info[CAM_VFE_BUS_VER3_VFE_OUT_MAX]; + uint32_t comp_done_shift; + uint32_t top_irq_shift; +}; + +/* + * cam_vfe_bus_ver3_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver3_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_ver3_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver3_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_VER3_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h new file mode 100644 index 000000000000..97336a2da3b8 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_H_ +#define _CAM_VFE_BUS_H_ + +#include +#include "cam_hw_intf.h" +#include "cam_isp_hw.h" + +#define CAM_VFE_BUS_VER_1_0 0x1000 +#define CAM_VFE_BUS_VER_2_0 0x2000 +#define CAM_VFE_BUS_VER_3_0 0x3000 + +#define CAM_VFE_BUS_RD_VER_1_0 0x1000 + +#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ + } while (0) + +#define ALIGNUP(value, alignment) \ + ((value + alignment - 1) / alignment * alignment) + +enum cam_vfe_bus_plane_type { + PLANE_Y, + PLANE_C, + PLANE_MAX, +}; + +enum cam_vfe_bus_type { + BUS_TYPE_WR, + BUS_TYPE_RD, + BUS_TYPE_MAX, +}; + +/* + * struct cam_vfe_bus: + * + * @Brief: Bus interface structure + * + * @bus_priv: Private data of BUS + * @hw_ops: Hardware interface functions + * @top_half_handler: Top Half handler function + * @bottom_half_handler: Bottom Half handler function + */ +struct cam_vfe_bus { + void *bus_priv; + + struct cam_hw_ops hw_ops; + CAM_IRQ_HANDLER_TOP_HALF top_half_handler; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/* + * cam_vfe_bus_init() + * + * @Brief: Initialize Bus layer + * + * @bus_version: Version of BUS to initialize + * @bus_type: Bus Type RD/WR + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @bus_version: Version of BUS to deinitialize + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_deinit(uint32_t bus_version, + struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile new file mode 100644 index 000000000000..0ed6a870efa9 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_lite_ver2.o cam_vfe_top.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top_ver3.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_ver3.o cam_vfe_rdi.o cam_vfe_fe_ver1.o cam_vfe_camif_lite_ver3.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c new file mode 100644 index 000000000000..0c1179c69776 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -0,0 +1,556 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" + +struct cam_vfe_mux_camif_lite_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_lite_ver2_reg *camif_lite_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver2_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + enum cam_isp_hw_sync_mode sync_mode; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload + evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; +}; + +static int cam_vfe_camif_lite_get_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_lite_priv->spin_lock); + if (list_empty(&camif_lite_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_lite_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&camif_lite_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_lite_put_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_lite_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, + &camif_lite_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_lite_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_lite_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x, IRQ status_1 = %x", + th_payload->evt_status_arr[0], th_payload->evt_status_arr[1]); + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[1] || (th_payload->evt_status_arr[0] & + camif_lite_priv->reg_data->lite_err_irq_mask0)) { + CAM_ERR(CAM_ISP, + "CAMIF LITE ERR VFE:%d IRQ STATUS_0=0x%x STATUS_1=0x%x", + camif_lite_node->hw_intf->hw_idx, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from VFE:%d", + camif_lite_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_lite_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ STATUS_0=0x%x STATUS_1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->violation_status); + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = 0x%x", + evt_payload->irq_reg_val[i]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + + +static int cam_vfe_camif_lite_get_reg_update( + struct cam_isp_resource_node *camif_lite_res, + void *cmd_args, + uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_lite_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = camif_lite_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_lite_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->dual_pd_reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF Lite reg_update_cmd %x offset %x", + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_lite_ver2_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_data; + struct cam_vfe_acquire_args *acquire_data; + int rc = 0; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_lite_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + camif_lite_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_lite_data->event_cb = acquire_data->event_cb; + camif_lite_data->priv = acquire_data->priv; + + CAM_DBG(CAM_ISP, "hw id:%d sync_mode=%d", + camif_lite_res->hw_intf->hw_idx, + camif_lite_data->sync_mode); + return rc; +} + +static int cam_vfe_camif_lite_resource_start( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *rsrc_data; + uint32_t val = 0; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (camif_lite_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid camif lite res res_state:%d", + camif_lite_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->lite_err_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->lite_err_irq_mask1; + + /* vfe core config */ + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg); + + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + val |= (1 << rsrc_data->reg_data->dual_pd_path_sel_shift); + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg val:%d", + camif_lite_res->hw_intf->hw_idx, val); + + /* epoch config with 20 line */ + cam_io_w_mb(rsrc_data->reg_data->lite_epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->lite_epoch_irq); + + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->dual_pd_reg_update_cmd_data, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP val:%d", + camif_lite_res->hw_intf->hw_idx, + rsrc_data->reg_data->dual_pd_reg_update_cmd_data); + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + err_irq_mask, + camif_lite_res, + cam_vfe_camif_lite_err_irq_top_half, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "Start Camif Lite IFE %d Done", + camif_lite_res->hw_intf->hw_idx); + return rc; +} + +static int cam_vfe_camif_lite_resource_stop( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + int rc = 0; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_lite_priv = (struct cam_vfe_mux_camif_lite_data *)camif_lite_res; + + if (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + if (camif_lite_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_handle); + camif_lite_priv->irq_handle = 0; + } + + if (camif_lite_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_err_handle); + camif_lite_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_lite_process_cmd( + struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_lite_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_camif_lite_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ status0=0x%x status1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_lite_handle_irq_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_MAX; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + uint32_t irq_status1; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + camif_lite_node = handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + evt_info.hw_idx = camif_lite_node->hw_intf->hw_idx; + evt_info.res_id = camif_lite_node->res_id; + evt_info.res_type = camif_lite_node->res_type; + + CAM_DBG(CAM_ISP, "irq_status_0 = 0x%x irq_status_1 = 0x%x", + irq_status0, irq_status1); + + if (irq_status0 & camif_lite_priv->reg_data->lite_sof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received SOF", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_lite_priv->reg_data->lite_epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received EPOCH", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_lite_priv->reg_data->dual_pd_reg_upd_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite hReceived REG_UPDATE_ACK", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_lite_priv->reg_data->lite_eof_irq_mask) { + CAM_DBG(CAM_ISP, "VF:%d CAMIF Lite Received EOF", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if ((irq_status0 & camif_lite_priv->reg_data->lite_err_irq_mask0) || + (irq_status1 & camif_lite_priv->reg_data->lite_err_irq_mask1)) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE Received ERROR", + evt_info.hw_idx); + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + } + + cam_vfe_camif_lite_put_evt_payload(camif_lite_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_lite_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = NULL; + struct cam_vfe_camif_lite_ver2_hw_info *camif_lite_info = + camif_lite_hw_info; + int i = 0; + + camif_lite_priv = kzalloc(sizeof(*camif_lite_priv), + GFP_KERNEL); + if (!camif_lite_priv) + return -ENOMEM; + + camif_lite_node->res_priv = camif_lite_priv; + + camif_lite_priv->mem_base = + soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_lite_priv->camif_lite_reg = camif_lite_info->camif_lite_reg; + camif_lite_priv->common_reg = camif_lite_info->common_reg; + camif_lite_priv->reg_data = camif_lite_info->reg_data; + camif_lite_priv->hw_intf = hw_intf; + camif_lite_priv->soc_info = soc_info; + camif_lite_priv->vfe_irq_controller = vfe_irq_controller; + + camif_lite_node->init = NULL; + camif_lite_node->deinit = NULL; + camif_lite_node->start = cam_vfe_camif_lite_resource_start; + camif_lite_node->stop = cam_vfe_camif_lite_resource_stop; + camif_lite_node->process_cmd = cam_vfe_camif_lite_process_cmd; + camif_lite_node->top_half_handler = + cam_vfe_camif_lite_handle_irq_top_half; + camif_lite_node->bottom_half_handler = + cam_vfe_camif_lite_handle_irq_bottom_half; + + spin_lock_init(&camif_lite_priv->spin_lock); + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + list_add_tail(&camif_lite_priv->evt_payload[i].list, + &camif_lite_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_lite_ver2_deinit( + struct cam_isp_resource_node *camif_lite_node) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = + camif_lite_node->res_priv; + int i = 0; + + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + + camif_lite_node->start = NULL; + camif_lite_node->stop = NULL; + camif_lite_node->process_cmd = NULL; + camif_lite_node->top_half_handler = NULL; + camif_lite_node->bottom_half_handler = NULL; + + camif_lite_node->res_priv = NULL; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Error! camif_priv is NULL"); + return -ENODEV; + } + + kfree(camif_lite_priv); + + return 0; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h new file mode 100644 index 000000000000..7813e55f508b --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_LITE_VER2_H_ +#define _CAM_VFE_CAMIF_LITE_VER2_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +#define CAM_VFE_CAMIF_LITE_EVT_MAX 256 + +struct cam_vfe_camif_lite_ver2_reg { + uint32_t camif_lite_cmd; + uint32_t camif_lite_config; + uint32_t lite_skip_period; + uint32_t lite_irq_subsample_pattern; + uint32_t lite_epoch_irq; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_camif_lite_ver2_reg_data { + uint32_t dual_pd_reg_update_cmd_data; + uint32_t lite_epoch_line_cfg; + uint32_t lite_sof_irq_mask; + uint32_t lite_epoch0_irq_mask; + uint32_t dual_pd_reg_upd_irq_mask; + uint32_t lite_eof_irq_mask; + uint32_t lite_err_irq_mask0; + uint32_t lite_err_irq_mask1; + uint32_t lite_subscribe_irq_mask0; + uint32_t lite_subscribe_irq_mask1; + uint32_t extern_reg_update_shift; + uint32_t dual_pd_path_sel_shift; +}; + +struct cam_vfe_camif_lite_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver2_reg *camif_lite_reg; + struct cam_vfe_camif_lite_ver2_reg_data *reg_data; +}; + +int cam_vfe_camif_lite_ver2_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param); + +int cam_vfe_camif_lite_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller); + +int cam_vfe_camif_lite_ver2_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_LITE_VER2_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c new file mode 100644 index 000000000000..bf527440e2d7 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -0,0 +1,1145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver3.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_lite_ver3.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" + +struct cam_vfe_mux_camif_lite_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_lite_ver3_reg *camif_lite_reg; + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver3_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + enum cam_isp_hw_sync_mode sync_mode; + struct cam_vfe_camif_common_cfg cam_common_cfg; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct list_head free_payload_list; + spinlock_t spin_lock; + uint32_t camif_debug; + struct cam_vfe_top_irq_evt_payload + evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; +}; + +static int cam_vfe_camif_lite_get_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_lite_priv->spin_lock); + if (list_empty(&camif_lite_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free CAMIF LITE event payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_lite_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&camif_lite_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_lite_put_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_lite_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, + &camif_lite_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_lite_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_lite_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_vfe_soc_private *soc_private = NULL; + bool error_flag = false; + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + + soc_private = camif_lite_priv->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[2] || (th_payload->evt_status_arr[0] & + camif_lite_priv->reg_data->error_irq_mask0)) { + CAM_ERR(CAM_ISP, + "VFE:%d CAMIF LITE:%d Err IRQ status_1: 0x%X status_2: 0x%X", + camif_lite_node->hw_intf->hw_idx, + camif_lite_node->res_id, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[2]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from VFE:%d", + camif_lite_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_lite_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) + return rc; + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->violation_status); + + if (error_flag && !soc_private->is_ife_lite) + CAM_INFO(CAM_ISP, "Violation status = 0x%X", + evt_payload->irq_reg_val[i]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + + +static int cam_vfe_camif_lite_get_reg_update( + struct cam_isp_resource_node *camif_lite_res, + void *cmd_args, + uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_lite_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, + "Invalid args: cdm args %pK", cdm_args); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CAMIF LITE:%d get RUP", camif_lite_res->res_id); + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = camif_lite_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_lite_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF LITE:%d reg_update_cmd 0x%X offset 0x%X", + camif_lite_res->res_id, reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_lite_ver3_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_data; + struct cam_vfe_acquire_args *acquire_data; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_lite_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + camif_lite_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_lite_data->event_cb = acquire_data->event_cb; + camif_lite_data->priv = acquire_data->priv; + + CAM_DBG(CAM_ISP, "Acquired VFE:%d CAMIF LITE:%d sync_mode=%d", + camif_lite_res->hw_intf->hw_idx, + camif_lite_res->res_id, + camif_lite_data->sync_mode); + return 0; +} + +static int cam_vfe_camif_lite_resource_start( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *rsrc_data; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t val = 0; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + if (camif_lite_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid camif lite res res_state:%d", + camif_lite_res->res_state); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CAMIF LITE:%d Start", camif_lite_res->res_id); + + rsrc_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + + soc_private = rsrc_data->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + if (soc_private->is_ife_lite) + goto skip_core_cfg; + + /* vfe core config */ + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + if (camif_lite_res->res_id == CAM_ISP_HW_VFE_IN_LCR && + rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if (camif_lite_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) { + val |= (1 << rsrc_data->reg_data->operating_mode_shift); + val |= (rsrc_data->cam_common_cfg.input_mux_sel_pdaf & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_MUXSEL_PDAF; + } + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + CAM_DBG(CAM_ISP, "VFE:%d core_cfg val:%d", + camif_lite_res->hw_intf->hw_idx, val); + + /* epoch config */ + cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->lite_epoch_irq); + +skip_core_cfg: + /* Enable Camif */ + cam_io_w_mb(0x1, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->lite_module_config); + + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->reg_update_cmd); + + memset(err_irq_mask, 0, sizeof(err_irq_mask)); + memset(irq_mask, 0, sizeof(irq_mask)); + + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = + rsrc_data->reg_data->error_irq_mask2; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->subscribe_irq_mask1; + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + irq_mask, + camif_lite_res, + camif_lite_res->top_half_handler, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + err_irq_mask, + camif_lite_res, + cam_vfe_camif_lite_err_irq_top_half, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Start Done", + camif_lite_res->hw_intf->hw_idx, + camif_lite_res->res_id); + return rc; +} + +static int cam_vfe_camif_lite_reg_dump( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t offset, val, wm_idx; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if ((camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_lite_priv = + (struct cam_vfe_mux_camif_lite_data *)camif_lite_res->res_priv; + + soc_private = camif_lite_priv->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + CAM_INFO(CAM_ISP, "IFE:%d TOP", camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x0; offset <= 0x1FC; offset += 0x4) { + if (offset == 0x1C || offset == 0x34 || + offset == 0x38 || offset == 0x90) + continue; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } else { + for (offset = 0x0; offset <= 0x74; offset += 0x4) { + if (offset == 0xC || offset == 0x20 || offset == 0x24) + continue; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } + + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI0) + goto dump_rdi_1; + + CAM_INFO(CAM_ISP, "IFE:%d RDI0 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x9A00; offset <= 0x9BFC; offset += 0x4) { + if (offset == 0x9A08) + offset = 0x9A60; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x9A60) + offset = 0x9A64; + else if (offset == 0x9A70) + offset = 0x9AEC; + } + } else { + for (offset = 0x1200; offset <= 0x13FC; offset += 0x4) { + if (offset == 0x1208) + offset = 0x1260; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1260) + offset = 0x1264; + else if (offset == 0x1270) + offset = 0x12EC; + } + } + + goto wr_dump; + +dump_rdi_1: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI1) + goto dump_rdi_2; + + CAM_INFO(CAM_ISP, "IFE:%d RDI1 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x9C00; offset <= 0x9DFC; offset += 0x4) { + if (offset == 0x9A08) + offset = 0x9A60; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x9A60) + offset = 0x9A64; + else if (offset == 0x9A70) + offset = 0x9BEC; + } + } else { + for (offset = 0x1400; offset <= 0x15FC; offset += 0x4) { + if (offset == 0x1408) + offset = 0x1460; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1460) + offset = 0x1464; + else if (offset == 0x1470) + offset = 0x15EC; + } + } + + goto wr_dump; + +dump_rdi_2: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI2) + goto dump_rdi_3; + + CAM_INFO(CAM_ISP, "IFE:%d RDI2 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x9E00; offset <= 0x9FFC; offset += 0x4) { + if (offset == 0x9E08) + offset = 0x9E60; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x9E60) + offset = 0x9E64; + else if (offset == 0x9E80) + offset = 0x9FEC; + } + } else { + for (offset = 0x1600; offset <= 0x17FC; offset += 0x4) { + if (offset == 0x1608) + offset = 0x1660; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1660) + offset = 0x1664; + else if (offset == 0x1670) + offset = 0x17EC; + } + } + + goto wr_dump; + +dump_rdi_3: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI3) + goto dump_pdlib; + + CAM_INFO(CAM_ISP, "IFE:%d RDI3 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (soc_private->is_ife_lite) { + for (offset = 0x1800; offset <= 0x19FC; offset += 0x4) { + if (offset == 0x1808) + offset = 0x1860; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1860) + offset = 0x1864; + else if (offset == 0x1870) + offset = 0x19EC; + } + } + + goto wr_dump; + +dump_pdlib: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_PDLIB) + goto dump_lcr; + + CAM_INFO(CAM_ISP, "IFE:%d PDLIB CAMIF", + camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA400; offset <= 0xA5FC; offset += 0x4) { + if (offset == 0xA408) + offset = 0xA460; + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0xA460) + offset = 0xA464; + else if (offset == 0xA470) + offset = 0xA5EC; + } + + CAM_INFO(CAM_ISP, "IFE:%d CLC PDLIB", + camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA600; offset <= 0xA718; offset += 0x4) { + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + goto wr_dump; + +dump_lcr: + CAM_INFO(CAM_ISP, "IFE:%d LCR CAMIF", camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA000; offset <= 0xA1FC; offset += 0x4) { + if (offset == 0xA008) + offset = 0xA060; + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0xA060) + offset = 0xA064; + else if (offset == 0xA070) + offset = 0xA1EC; + } + + CAM_INFO(CAM_ISP, "IFE:%d CLC LCR", camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA200; offset <= 0xA3FC; offset += 0x4) { + if (offset == 0xA208) + offset = 0xA260; + else if (offset == 0xA288) + offset = 0xA3F8; + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0xA260) + offset = 0xA264; + else if (offset == 0xA280) + offset = 0xA1EC; + } + +wr_dump: + if (!soc_private->is_ife_lite) + goto end_dump; + + CAM_INFO(CAM_ISP, "IFE:%d LITE BUS WR", + camif_lite_priv->hw_intf->hw_idx); + for (offset = 0x1A00; offset <= 0x1AE0; offset += 0x4) { + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_DBG(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + for (wm_idx = 0; wm_idx <= 3; wm_idx++) { + for (offset = 0x1C00 + 0x100 * wm_idx; offset < (0x1C00 + + 0x100 * wm_idx + 0x84); offset += 0x4) { + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } + +end_dump: + return 0; +} + +static int cam_vfe_camif_lite_resource_stop( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *rsrc_data; + int rc = 0; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Stop", + camif_lite_res->hw_intf->hw_idx, + camif_lite_res->res_id); + + if ((camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + rsrc_data = + (struct cam_vfe_mux_camif_lite_data *)camif_lite_res->res_priv; + + /* Disable Camif */ + cam_io_w_mb(0x0, rsrc_data->mem_base + + rsrc_data->camif_lite_reg->lite_module_config); + + if (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + if (rsrc_data->irq_handle > 0) { + cam_irq_controller_unsubscribe_irq( + rsrc_data->vfe_irq_controller, + rsrc_data->irq_handle); + rsrc_data->irq_handle = 0; + } + + if (rsrc_data->irq_err_handle > 0) { + cam_irq_controller_unsubscribe_irq( + rsrc_data->vfe_irq_controller, + rsrc_data->irq_err_handle); + rsrc_data->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_lite_ver3_core_config( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_core_config_args *vfe_core_cfg = + (struct cam_vfe_core_config_args *)cmd_args; + + camif_lite_priv = + (struct cam_vfe_mux_camif_lite_data *)rsrc_node->res_priv; + camif_lite_priv->cam_common_cfg.vid_ds16_r2pd = + vfe_core_cfg->core_config.vid_ds16_r2pd; + camif_lite_priv->cam_common_cfg.vid_ds4_r2pd = + vfe_core_cfg->core_config.vid_ds4_r2pd; + camif_lite_priv->cam_common_cfg.disp_ds16_r2pd = + vfe_core_cfg->core_config.disp_ds16_r2pd; + camif_lite_priv->cam_common_cfg.disp_ds4_r2pd = + vfe_core_cfg->core_config.disp_ds4_r2pd; + camif_lite_priv->cam_common_cfg.dsp_streaming_tap_point = + vfe_core_cfg->core_config.dsp_streaming_tap_point; + camif_lite_priv->cam_common_cfg.ihist_src_sel = + vfe_core_cfg->core_config.ihist_src_sel; + camif_lite_priv->cam_common_cfg.hdr_be_src_sel = + vfe_core_cfg->core_config.hdr_be_src_sel; + camif_lite_priv->cam_common_cfg.hdr_bhist_src_sel = + vfe_core_cfg->core_config.hdr_bhist_src_sel; + camif_lite_priv->cam_common_cfg.input_mux_sel_pdaf = + vfe_core_cfg->core_config.input_mux_sel_pdaf; + camif_lite_priv->cam_common_cfg.input_mux_sel_pp = + vfe_core_cfg->core_config.input_mux_sel_pp; + + return 0; +} + +static int cam_vfe_camif_lite_process_cmd( + struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = NULL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_lite_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = cam_vfe_camif_lite_ver3_core_config(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + camif_lite_priv = (struct cam_vfe_mux_camif_lite_data *) + rsrc_node->res_priv; + camif_lite_priv->camif_debug = *((uint32_t *)cmd_args); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static void cam_vfe_camif_lite_print_status(uint32_t *status, + int err_type, bool is_ife_lite) +{ + uint32_t violation_mask = 0x3F00, violation_status = 0; + uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; + + if (!status) { + CAM_ERR(CAM_ISP, "Invalid params"); + return; + } + + bus_overflow_status = status[CAM_IFE_IRQ_REGISTERS_MAX]; + violation_status = status[CAM_IFE_IRQ_VIOLATION_STATUS]; + status_0 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + status_2 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]; + + if (is_ife_lite) + goto ife_lite; + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW) { + if (status_0 & 0x200000) + CAM_INFO(CAM_ISP, "RDI2 FRAME DROP"); + + if (status_0 & 0x400000) + CAM_INFO(CAM_ISP, "RDI1 FRAME DROP"); + + if (status_0 & 0x800000) + CAM_INFO(CAM_ISP, "RDI0 FRAME DROP"); + + if (status_0 & 0x1000000) + CAM_INFO(CAM_ISP, "PD PIPE FRAME DROP"); + + if (status_0 & 0x8000000) + CAM_INFO(CAM_ISP, "RDI2 OVERFLOW"); + + if (status_0 & 0x10000000) + CAM_INFO(CAM_ISP, "RDI1 OVERFLOW"); + + if (status_0 & 0x20000000) + CAM_INFO(CAM_ISP, "RDI0 OVERFLOW"); + + if (status_0 & 0x40000000) + CAM_INFO(CAM_ISP, "PD PIPE OVERFLOW"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && bus_overflow_status) { + if (bus_overflow_status & 0x0800) + CAM_INFO(CAM_ISP, "CAMIF PD BUS OVERFLOW"); + + if (bus_overflow_status & 0x0400000) + CAM_INFO(CAM_ISP, "LCR BUS OVERFLOW"); + + if (bus_overflow_status & 0x0800000) + CAM_INFO(CAM_ISP, "RDI0 BUS OVERFLOW"); + + if (bus_overflow_status & 0x01000000) + CAM_INFO(CAM_ISP, "RDI1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x02000000) + CAM_INFO(CAM_ISP, "RDI2 BUS OVERFLOW"); + + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { + CAM_INFO(CAM_ISP, "PDLIB / LCR Module hang"); + /* print debug registers here */ + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION) { + if (status_2 & 0x02000) + CAM_INFO(CAM_ISP, "PD CAMIF VIOLATION"); + + if (status_2 & 0x04000) + CAM_INFO(CAM_ISP, "PD VIOLATION"); + + if (status_2 & 0x08000) + CAM_INFO(CAM_ISP, "LCR CAMIF VIOLATION"); + + if (status_2 & 0x010000) + CAM_INFO(CAM_ISP, "LCR VIOLATION"); + + if (status_2 & 0x020000) + CAM_INFO(CAM_ISP, "RDI0 CAMIF VIOLATION"); + + if (status_2 & 0x040000) + CAM_INFO(CAM_ISP, "RDI1 CAMIF VIOLATION"); + + if (status_2 & 0x080000) + CAM_INFO(CAM_ISP, "RDI2 CAMIF VIOLATION"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION && violation_status) { + if (violation_mask & violation_status) + CAM_INFO(CAM_ISP, "LCR VIOLATION Module ID:%d", + violation_mask & violation_status); + + violation_mask = 0x0F0000; + if (violation_mask & violation_status) + CAM_INFO(CAM_ISP, "PD VIOLATION Module ID:%d", + violation_mask & violation_status); + + } + + return; + +ife_lite: + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW) { + if (status_0 & 0x100) + CAM_INFO(CAM_ISP, "RDI3 FRAME DROP"); + + if (status_0 & 0x80) + CAM_INFO(CAM_ISP, "RDI2 FRAME DROP"); + + if (status_0 & 0x40) + CAM_INFO(CAM_ISP, "RDI1 FRAME DROP"); + + if (status_0 & 0x20) + CAM_INFO(CAM_ISP, "RDI0 FRAME DROP"); + + if (status_0 & 0x8) + CAM_INFO(CAM_ISP, "RDI3 OVERFLOW"); + + if (status_0 & 0x4) + CAM_INFO(CAM_ISP, "RDI2 OVERFLOW"); + + if (status_0 & 0x2) + CAM_INFO(CAM_ISP, "RDI1 OVERFLOW"); + + if (status_0 & 0x1) + CAM_INFO(CAM_ISP, "RDI0 OVERFLOW"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && bus_overflow_status) { + if (bus_overflow_status & 0x01) + CAM_INFO(CAM_ISP, "RDI0 BUS OVERFLOW"); + + if (bus_overflow_status & 0x02) + CAM_INFO(CAM_ISP, "RDI1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x04) + CAM_INFO(CAM_ISP, "RDI2 BUS OVERFLOW"); + + if (bus_overflow_status & 0x08) + CAM_INFO(CAM_ISP, "RDI3 BUS OVERFLOW"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION) { + if (status_2 & 0x100) + CAM_INFO(CAM_ISP, "RDI0 CAMIF VIOLATION"); + + if (status_2 & 0x200) + CAM_INFO(CAM_ISP, "RDI1 CAMIF VIOLATION"); + + if (status_2 & 0x400) + CAM_INFO(CAM_ISP, "RDI2 CAMIF VIOLATION"); + + if (status_2 & 0x800) + CAM_INFO(CAM_ISP, "RDI3 CAMIF VIOLATION"); + } +} + +static int cam_vfe_camif_lite_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + + CAM_DBG(CAM_ISP, + "VFE:%d CAMIF LITE:%d IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_lite_node->hw_intf->hw_idx, + camif_lite_node->res_id, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], + th_payload->evt_status_arr[2]); + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d CAMIF LITE:%d IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_lite_node->hw_intf->hw_idx, + camif_lite_node->res_id, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], + th_payload->evt_status_arr[2]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_lite_handle_irq_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_MAX; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX + 1]; + int i = 0; + bool is_ife_lite = true; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + camif_lite_node = handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + payload = evt_payload_priv; + + soc_private = camif_lite_priv->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + is_ife_lite = soc_private->is_ife_lite; + + memset(irq_status, 0, + sizeof(uint32_t) * (CAM_IFE_IRQ_REGISTERS_MAX + 1)); + for (i = 0; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) + irq_status[i] = payload->irq_reg_val[i]; + + evt_info.hw_idx = camif_lite_node->hw_intf->hw_idx; + evt_info.res_id = camif_lite_node->res_id; + evt_info.res_type = camif_lite_node->res_type; + + CAM_DBG(CAM_ISP, + "VFE:%d CAMIF LITE:%d IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + evt_info.hw_idx, evt_info.res_id, + irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0], + irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]); + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_lite_priv->reg_data->sof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received SOF", + evt_info.hw_idx, evt_info.res_id); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_lite_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EPOCH", + evt_info.hw_idx, evt_info.res_id); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_lite_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EOF", + evt_info.hw_idx, evt_info.res_id); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_lite_priv->reg_data->error_irq_mask0) { + CAM_ERR(CAM_ISP, "VFE:%d Overflow", + camif_lite_node->hw_intf->hw_idx); + + evt_info.err_type = CAM_VFE_IRQ_STATUS_OVERFLOW; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = + cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->bus_overflow_status); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + cam_vfe_camif_lite_print_status(irq_status, ret, is_ife_lite); + + if (camif_lite_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_lite_reg_dump(camif_lite_node); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { + CAM_ERR(CAM_ISP, "VFE:%d Violation", + camif_lite_node->hw_intf->hw_idx); + + evt_info.err_type = CAM_VFE_IRQ_STATUS_VIOLATION; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_VIOLATION; + + cam_vfe_camif_lite_print_status(irq_status, ret, is_ife_lite); + + if (camif_lite_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_lite_reg_dump(camif_lite_node); + } + + cam_vfe_camif_lite_put_evt_payload(camif_lite_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_lite_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = NULL; + struct cam_vfe_camif_lite_ver3_hw_info *camif_lite_info = + camif_lite_hw_info; + int i = 0; + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Init", + camif_lite_node->res_id, camif_lite_node->res_id); + + camif_lite_priv = kzalloc(sizeof(*camif_lite_priv), + GFP_KERNEL); + if (!camif_lite_priv) + return -ENOMEM; + + camif_lite_node->res_priv = camif_lite_priv; + + camif_lite_priv->mem_base = + soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_lite_priv->camif_lite_reg = camif_lite_info->camif_lite_reg; + camif_lite_priv->common_reg = camif_lite_info->common_reg; + camif_lite_priv->reg_data = camif_lite_info->reg_data; + camif_lite_priv->hw_intf = hw_intf; + camif_lite_priv->soc_info = soc_info; + camif_lite_priv->vfe_irq_controller = vfe_irq_controller; + + camif_lite_node->init = NULL; + camif_lite_node->deinit = NULL; + camif_lite_node->start = cam_vfe_camif_lite_resource_start; + camif_lite_node->stop = cam_vfe_camif_lite_resource_stop; + camif_lite_node->process_cmd = cam_vfe_camif_lite_process_cmd; + camif_lite_node->top_half_handler = + cam_vfe_camif_lite_handle_irq_top_half; + camif_lite_node->bottom_half_handler = + cam_vfe_camif_lite_handle_irq_bottom_half; + + spin_lock_init(&camif_lite_priv->spin_lock); + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + list_add_tail(&camif_lite_priv->evt_payload[i].list, + &camif_lite_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_lite_ver3_deinit( + struct cam_isp_resource_node *camif_lite_node) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = + camif_lite_node->res_priv; + int i = 0; + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Deinit", + camif_lite_node->hw_intf->hw_idx, camif_lite_node->res_id); + + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + + camif_lite_node->start = NULL; + camif_lite_node->stop = NULL; + camif_lite_node->process_cmd = NULL; + camif_lite_node->top_half_handler = NULL; + camif_lite_node->bottom_half_handler = NULL; + + camif_lite_node->res_priv = NULL; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Error. camif_priv is NULL"); + return -ENODEV; + } + + kfree(camif_lite_priv); + + return 0; +} + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h new file mode 100644 index 000000000000..ad8e44ef8e6c --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_LITE_VER3_H_ +#define _CAM_VFE_CAMIF_LITE_VER3_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +#define CAM_VFE_RDI_VER2_MAX 4 +#define CAM_VFE_CAMIF_LITE_EVT_MAX 256 + +struct cam_vfe_camif_lite_ver3_reg { + uint32_t lite_hw_version; + uint32_t lite_hw_status; + uint32_t lite_module_config; + uint32_t lite_skip_period; + uint32_t lite_irq_subsample_pattern; + uint32_t lite_epoch_irq; + uint32_t lite_debug_1; + uint32_t lite_debug_0; + uint32_t lite_test_bus_ctrl; + uint32_t camif_lite_spare; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_camif_lite_ver3_reg_data { + uint32_t extern_reg_update_shift; + uint32_t operating_mode_shift; + uint32_t input_mux_sel_shift; + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask2; + uint32_t subscribe_irq_mask1; + uint32_t enable_diagnostic_hw; +}; + +struct cam_vfe_camif_lite_ver3_hw_info { + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver3_reg *camif_lite_reg; + struct cam_vfe_camif_lite_ver3_reg_data *reg_data; +}; + +int cam_vfe_camif_lite_ver3_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param); + +int cam_vfe_camif_lite_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller); + +int cam_vfe_camif_lite_ver3_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_LITE_VER3_H_ */ + diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c new file mode 100644 index 000000000000..d641d647b65a --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -0,0 +1,881 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_ver2.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_camif_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_ver2_reg *camif_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t camif_debug; +}; + +static int cam_vfe_camif_get_evt_payload( + struct cam_vfe_mux_camif_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_priv->spin_lock); + if (list_empty(&camif_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); +done: + spin_unlock(&camif_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_put_evt_payload( + struct cam_vfe_mux_camif_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, &camif_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x, IRQ status_1 = %x", + th_payload->evt_status_arr[0], th_payload->evt_status_arr[1]); + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[1] || (th_payload->evt_status_arr[0] & + camif_priv->reg_data->error_irq_mask0)) { + CAM_ERR(CAM_ISP, + "Camif Error: vfe:%d: IRQ STATUS_0=0x%x STATUS_1=0x%x", + camif_node->hw_intf->hw_idx, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from vfe=%d", + camif_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq(camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_get_evt_payload(camif_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ STATUS_0=0x%x STATUS_1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->violation_status); + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = 0x%x", + evt_payload->irq_reg_val[2]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_camif_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error! Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_camif_get_reg_update( + struct cam_isp_resource_node *camif_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = camif_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF reg_update_cmd %x offset %x", + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_ver2_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_data *camif_data; + struct cam_vfe_acquire_args *acquire_data; + + int rc = 0; + + camif_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_camif_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + if (rc) + return rc; + + camif_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + camif_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + camif_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + camif_data->first_line = acquire_data->vfe_in.in_port->line_start; + camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + camif_data->event_cb = acquire_data->event_cb; + camif_data->priv = acquire_data->priv; + + CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", + camif_res->hw_intf->hw_idx, + camif_data->pix_pattern, camif_data->dsp_mode); + return rc; +} + +static int cam_vfe_camif_resource_init( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to enable dsp clk"); + } + + return rc; +} + +static int cam_vfe_camif_resource_deinit( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; +} + +static int cam_vfe_camif_resource_start( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + struct cam_vfe_soc_private *soc_private; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (camif_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid camif res res_state:%d", + camif_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->error_irq_mask1; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->subscribe_irq_mask0; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->subscribe_irq_mask1; + + soc_private = rsrc_data->soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + return -ENODEV; + } + + /*config vfe core*/ + val = (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg val:%d", camif_res->hw_intf->hw_idx, + val); + + /* disable the CGC for stats */ + cam_io_w_mb(0xFFFFFFFF, rsrc_data->mem_base + + rsrc_data->common_reg->module_ctrl[ + CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); + + /* epoch config */ + switch (soc_private->cpas_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_reg->epoch_irq); + break; + default: + epoch0_irq_mask = ((rsrc_data->last_line - + rsrc_data->first_line) / 2) + + rsrc_data->first_line; + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & + 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | + epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_reg->epoch_irq); + CAM_DBG(CAM_ISP, "first_line: %u\n" + "last_line: %u\n" + "epoch_line_cfg: 0x%x", + rsrc_data->first_line, + rsrc_data->last_line, + computed_epoch_line_cfg); + break; + } + + camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP val:%d", camif_res->hw_intf->hw_idx, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + if (rsrc_data->camif_debug & + CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->camif_reg->vfe_diag_config); + val |= rsrc_data->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->camif_reg->vfe_diag_config); + } + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + irq_mask, + camif_res, + camif_res->top_half_handler, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + err_irq_mask, + camif_res, + cam_vfe_camif_err_irq_top_half, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "Start Camif IFE %d Done", camif_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_camif_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_soc_private *soc_private; + uint32_t offset, val, wm_idx; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + for (offset = 0x0; offset < 0x1160; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + } + + for (offset = 0x2000; offset <= 0x20B8; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + } + + for (wm_idx = 0; wm_idx <= 23; wm_idx++) { + for (offset = 0x2200 + 0x100 * wm_idx; + offset < 0x2278 + 0x100 * wm_idx; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, + "offset 0x%x value 0x%x", offset, val); + } + } + + soc_private = camif_priv->soc_info->soc_private; + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || + soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_INFO(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + + } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } + + return 0; +} + +static int cam_vfe_camif_resource_stop( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_camif_ver2_reg *camif_reg; + int rc = 0; + uint32_t val = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + camif_reg = camif_priv->camif_reg; + + if ((camif_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->core_cfg); + val &= (~(1 << camif_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->common_reg->core_cfg); + } + + if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->camif_reg->vfe_diag_config); + if (val & camif_priv->reg_data->enable_diagnostic_hw) { + val &= ~camif_priv->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->camif_reg->vfe_diag_config); + } + + if (camif_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, camif_priv->irq_handle); + camif_priv->irq_handle = 0; + } + + if (camif_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + camif_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_data *camif_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + camif_priv->enable_sof_irq_debug = true; + else + camif_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_mux_camif_data *camif_priv = NULL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_camif_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + camif_priv->camif_debug = *((uint32_t *)cmd_args); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_camif_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rc = cam_vfe_camif_get_evt_payload(camif_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ status0=0x%x status1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_MAX; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + uint32_t irq_status1; + uint32_t val; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + camif_node = handler_priv; + camif_priv = camif_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + evt_info.hw_idx = camif_node->hw_intf->hw_idx; + evt_info.res_id = camif_node->res_id; + evt_info.res_type = camif_node->res_type; + + CAM_DBG(CAM_ISP, "irq_status_0 = 0x%x irq_status_1 = 0x%x", + irq_status0, irq_status1); + + if (irq_status0 & camif_priv->reg_data->sof_irq_mask) { + if ((camif_priv->enable_sof_irq_debug) && + (camif_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "Received SOF"); + + camif_priv->irq_debug_cnt++; + if (camif_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + camif_priv->enable_sof_irq_debug = + false; + camif_priv->irq_debug_cnt = 0; + } + } else + CAM_DBG(CAM_ISP, "Received SOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_REG_UPDATE, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->error_irq_mask0) { + CAM_DBG(CAM_ISP, "Received ERROR"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + CAM_INFO(CAM_ISP, "Violation status = %x", + payload->irq_reg_val[2]); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_reg_dump(camif_node->res_priv); + } + + if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { + CAM_DBG(CAM_ISP, "Received ERROR"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + CAM_INFO(CAM_ISP, "Violation status = %x", + payload->irq_reg_val[2]); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_reg_dump(camif_node->res_priv); + } + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r(camif_priv->mem_base + + camif_priv->camif_reg->vfe_diag_sensor_status); + CAM_DBG(CAM_ISP, "VFE_DIAG_SENSOR_STATUS: 0x%x", + camif_priv->mem_base, val); + } + + cam_vfe_camif_put_evt_payload(camif_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_data *camif_priv = NULL; + struct cam_vfe_camif_ver2_hw_info *camif_info = camif_hw_info; + int i = 0; + + camif_priv = kzalloc(sizeof(struct cam_vfe_mux_camif_data), + GFP_KERNEL); + if (!camif_priv) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for camif_priv"); + return -ENOMEM; + } + + camif_node->res_priv = camif_priv; + + camif_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_priv->camif_reg = camif_info->camif_reg; + camif_priv->common_reg = camif_info->common_reg; + camif_priv->reg_data = camif_info->reg_data; + camif_priv->hw_intf = hw_intf; + camif_priv->soc_info = soc_info; + camif_priv->vfe_irq_controller = vfe_irq_controller; + + camif_node->init = cam_vfe_camif_resource_init; + camif_node->deinit = cam_vfe_camif_resource_deinit; + camif_node->start = cam_vfe_camif_resource_start; + camif_node->stop = cam_vfe_camif_resource_stop; + camif_node->process_cmd = cam_vfe_camif_process_cmd; + camif_node->top_half_handler = cam_vfe_camif_handle_irq_top_half; + camif_node->bottom_half_handler = cam_vfe_camif_handle_irq_bottom_half; + + spin_lock_init(&camif_priv->spin_lock); + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + list_add_tail(&camif_priv->evt_payload[i].list, + &camif_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_ver2_deinit( + struct cam_isp_resource_node *camif_node) +{ + struct cam_vfe_mux_camif_data *camif_priv = camif_node->res_priv; + int i = 0; + + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + + camif_node->start = NULL; + camif_node->stop = NULL; + camif_node->process_cmd = NULL; + camif_node->top_half_handler = NULL; + camif_node->bottom_half_handler = NULL; + + camif_node->res_priv = NULL; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Error! camif_priv is NULL"); + return -ENODEV; + } + + kfree(camif_priv); + + return 0; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h new file mode 100644 index 000000000000..f071a0627bbc --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_VER2_H_ +#define _CAM_VFE_CAMIF_VER2_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_camif_ver2_reg { + uint32_t camif_cmd; + uint32_t camif_config; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t skip_period; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq; + uint32_t raw_crop_width_cfg; + uint32_t raw_crop_height_cfg; + uint32_t reg_update_cmd; + uint32_t vfe_diag_config; + uint32_t vfe_diag_sensor_status; +}; + +struct cam_vfe_camif_reg_data { + uint32_t raw_crop_first_pixel_shift; + uint32_t raw_crop_first_pixel_mask; + + uint32_t raw_crop_last_pixel_shift; + uint32_t raw_crop_last_pixel_mask; + + uint32_t raw_crop_first_line_shift; + uint32_t raw_crop_first_line_mask; + + uint32_t raw_crop_last_line_shift; + uint32_t raw_crop_last_line_mask; + + uint32_t input_mux_sel_shift; + uint32_t input_mux_sel_mask; + uint32_t extern_reg_update_shift; + uint32_t extern_reg_update_mask; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t reg_update_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + uint32_t subscribe_irq_mask0; + uint32_t subscribe_irq_mask1; + + uint32_t enable_diagnostic_hw; +}; + +struct cam_vfe_camif_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_ver2_reg *camif_reg; + struct cam_vfe_camif_reg_data *reg_data; +}; + +int cam_vfe_camif_ver2_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_camif_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller); + +int cam_vfe_camif_ver2_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_VER2_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c new file mode 100644 index 000000000000..450d03428c63 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -0,0 +1,1299 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver3.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_ver3.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_camif_ver3_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_ver3_pp_clc_reg *camif_reg; + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_ver3_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + struct cam_vfe_camif_common_cfg cam_common_cfg; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t camif_debug; +}; + +static int cam_vfe_camif_ver3_get_evt_payload( + struct cam_vfe_mux_camif_ver3_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_priv->spin_lock); + if (list_empty(&camif_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free CAMIF event payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); +done: + spin_unlock(&camif_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_ver3_put_evt_payload( + struct cam_vfe_mux_camif_ver3_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, &camif_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_ver3_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[2] || (th_payload->evt_status_arr[0] & + camif_priv->reg_data->error_irq_mask0)) { + CAM_ERR(CAM_ISP, + "VFE:%d CAMIF Err IRQ status_0: 0x%X status_2: 0x%X", + camif_node->hw_intf->hw_idx, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[2]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from VFE:%d", + camif_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq(camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_ver3_get_evt_payload(camif_priv, &evt_payload); + if (rc) + return rc; + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->violation_status); + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = 0x%X", + evt_payload->irq_reg_val[i]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_camif_ver3_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error, Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_camif_ver3_get_reg_update( + struct cam_isp_resource_node *camif_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_ver3_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid arg size: %d expected:%ld", + arg_size, sizeof(struct cam_isp_hw_get_cmd_update)); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args: %pK", cdm_args); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, (size*4)); + return -EINVAL; + } + + rsrc_data = camif_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "VFE:%d CAMIF reg_update_cmd 0x%X offset 0x%X", + camif_res->hw_intf->hw_idx, + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_ver3_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_ver3_data *camif_data; + struct cam_vfe_acquire_args *acquire_data; + int rc = 0; + + camif_data = (struct cam_vfe_mux_camif_ver3_data *) + camif_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_camif_ver3_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + + if (rc) { + CAM_ERR(CAM_ISP, "Validate pix pattern failed, rc = %d", rc); + return rc; + } + + camif_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + camif_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + camif_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + camif_data->first_line = acquire_data->vfe_in.in_port->line_start; + camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + camif_data->event_cb = acquire_data->event_cb; + camif_data->priv = acquire_data->priv; + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF pix_pattern:%d dsp_mode=%d", + camif_res->hw_intf->hw_idx, + camif_data->pix_pattern, camif_data->dsp_mode); + + return rc; +} + +static int cam_vfe_camif_ver3_resource_init( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_ver3_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_ver3_data *) + camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, + "failed to enable dsp clk, rc = %d", rc); + } + + /* All auto clock gating disabled by default */ + CAM_INFO(CAM_ISP, "overriding clock gating"); + cam_io_w_mb(0xFFFFFFFF, camif_data->mem_base + + camif_data->common_reg->core_cgc_ovd_0); + + cam_io_w_mb(0xFF, camif_data->mem_base + + camif_data->common_reg->core_cgc_ovd_1); + + cam_io_w_mb(0x1, camif_data->mem_base + + camif_data->common_reg->ahb_cgc_ovd); + + cam_io_w_mb(0x1, camif_data->mem_base + + camif_data->common_reg->noc_cgc_ovd); + + return rc; +} + +static int cam_vfe_camif_ver3_resource_deinit( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_ver3_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_ver3_data *) + camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; +} + +static int cam_vfe_camif_ver3_resource_start( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_ver3_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_line_cfg; + uint32_t epoch1_line_cfg; + uint32_t computed_epoch_line_cfg; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + struct cam_vfe_soc_private *soc_private; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if (camif_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error, Invalid camif res res_state:%d", + camif_res->res_state); + return -EINVAL; + } + + memset(err_irq_mask, 0, sizeof(err_irq_mask)); + memset(irq_mask, 0, sizeof(irq_mask)); + + rsrc_data = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = + rsrc_data->reg_data->error_irq_mask2; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->subscribe_irq_mask1; + + soc_private = rsrc_data->soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error, soc_private NULL"); + return -ENODEV; + } + + /*config vfe core*/ + val = (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + val |= (1 << rsrc_data->reg_data->pp_camif_cfg_en_shift); + val |= (1 << rsrc_data->reg_data->pp_camif_cfg_ife_out_en_shift); + cam_io_w_mb(val, + rsrc_data->mem_base + rsrc_data->camif_reg->module_cfg); + CAM_DBG(CAM_ISP, "write module_cfg val = 0x%X", val); + + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + /* AF stitching by hw disabled by default + * PP CAMIF currently operates only in offline mode + */ + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->pp_extern_reg_update_shift); + + if ((rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) || + (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_MASTER)) + val |= (1 << rsrc_data->reg_data->dual_ife_pix_en_shift); + + val |= (~rsrc_data->cam_common_cfg.vid_ds16_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_VID_DS16_R2PD; + val |= (~rsrc_data->cam_common_cfg.vid_ds4_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_VID_DS4_R2PD; + val |= (~rsrc_data->cam_common_cfg.disp_ds16_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_DISP_DS16_R2PD; + val |= (~rsrc_data->cam_common_cfg.disp_ds4_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_DISP_DS4_R2PD; + val |= (rsrc_data->cam_common_cfg.dsp_streaming_tap_point & 0x3) << + CAM_SHIFT_TOP_CORE_CFG_DSP_STREAMING; + val |= (rsrc_data->cam_common_cfg.ihist_src_sel & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_STATS_IHIST; + val |= (rsrc_data->cam_common_cfg.hdr_be_src_sel & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BE; + val |= (rsrc_data->cam_common_cfg.hdr_bhist_src_sel & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BHIST; + val |= (rsrc_data->cam_common_cfg.input_mux_sel_pp & 0x3) << + CAM_SHIFT_TOP_CORE_CFG_INPUTMUX_PP; + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + /* epoch config */ + switch (soc_private->cpas_version) { + case CAM_CPAS_TITAN_480_V100: + epoch0_line_cfg = ((rsrc_data->last_line - + rsrc_data->first_line) / 4) + + rsrc_data->first_line; + /* epoch line cfg will still be configured at midpoint of the + * frame width. We use '/ 4' instead of '/ 2' + * cause it is multipixel path + */ + epoch1_line_cfg = rsrc_data->reg_data->epoch_line_cfg & + 0xFFFF; + computed_epoch_line_cfg = (epoch1_line_cfg << 16) | + epoch0_line_cfg; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_reg->epoch_irq_cfg); + CAM_DBG(CAM_ISP, "epoch_line_cfg: 0x%X", + computed_epoch_line_cfg); + break; + default: + CAM_ERR(CAM_ISP, "Hardware version not proper: 0x%X", + soc_private->cpas_version); + return -EINVAL; + break; + } + + camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "VFE:%d CAMIF RUP val:0x%X", + camif_res->hw_intf->hw_idx, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + if (rsrc_data->camif_debug & + CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->diag_config); + val |= rsrc_data->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->diag_config); + } + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + irq_mask, + camif_res, + camif_res->top_half_handler, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + err_irq_mask, + camif_res, + cam_vfe_camif_ver3_err_irq_top_half, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Start Done", camif_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_camif_ver3_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + uint32_t offset, val, wm_idx; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; + + CAM_INFO(CAM_ISP, "IFE:%d TOP", camif_res->hw_intf->hw_idx); + for (offset = 0x0; offset <= 0x1FC; offset += 0x4) { + if (offset == 0x1C || offset == 0x34 || + offset == 0x38 || offset == 0x90) + continue; + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + CAM_INFO(CAM_ISP, "IFE:%d PP CLC PREPROCESS", + camif_res->hw_intf->hw_idx); + for (offset = 0x2200; offset <= 0x23FC; offset += 0x4) { + if (offset == 0x2208) + offset = 0x2260; + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + if (offset == 0x2260) + offset = 0x23F4; + } + + CAM_INFO(CAM_ISP, "IFE:%d PP CLC CAMIF", camif_res->hw_intf->hw_idx); + for (offset = 0x2600; offset <= 0x27FC; offset += 0x4) { + if (offset == 0x2608) + offset = 0x2660; + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + if (offset == 0x2660) + offset = 0x2664; + else if (offset == 0x2680) + offset = 0x27EC; + } + + CAM_INFO(CAM_ISP, "IFE:%d PP CLC Modules", camif_res->hw_intf->hw_idx); + for (offset = 0x2800; offset <= 0x8FFC; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + CAM_INFO(CAM_ISP, "IFE:%d BUS WR", camif_res->hw_intf->hw_idx); + for (offset = 0xAA00; offset <= 0xAADC; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_DBG(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + for (wm_idx = 0; wm_idx <= 25; wm_idx++) { + for (offset = 0xAC00 + 0x100 * wm_idx; + offset < 0xAC84 + 0x100 * wm_idx; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } + + return 0; +} + +static int cam_vfe_camif_ver3_resource_stop( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_camif_ver3_pp_clc_reg *camif_reg; + int rc = 0; + uint32_t val = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; + camif_reg = camif_priv->camif_reg; + + if ((camif_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->core_cfg_0); + val &= (~(1 << camif_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->common_reg->core_cfg_0); + } + + if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->diag_config); + if (val & camif_priv->reg_data->enable_diagnostic_hw) { + val &= ~camif_priv->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->common_reg->diag_config); + } + + if (camif_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, camif_priv->irq_handle); + camif_priv->irq_handle = 0; + } + + if (camif_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + camif_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_ver3_core_config( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_core_config_args *vfe_core_cfg = + (struct cam_vfe_core_config_args *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_ver3_data *)rsrc_node->res_priv; + camif_priv->cam_common_cfg.vid_ds16_r2pd = + vfe_core_cfg->core_config.vid_ds16_r2pd; + camif_priv->cam_common_cfg.vid_ds4_r2pd = + vfe_core_cfg->core_config.vid_ds4_r2pd; + camif_priv->cam_common_cfg.disp_ds16_r2pd = + vfe_core_cfg->core_config.disp_ds16_r2pd; + camif_priv->cam_common_cfg.disp_ds4_r2pd = + vfe_core_cfg->core_config.disp_ds4_r2pd; + camif_priv->cam_common_cfg.dsp_streaming_tap_point = + vfe_core_cfg->core_config.dsp_streaming_tap_point; + camif_priv->cam_common_cfg.ihist_src_sel = + vfe_core_cfg->core_config.ihist_src_sel; + camif_priv->cam_common_cfg.hdr_be_src_sel = + vfe_core_cfg->core_config.hdr_be_src_sel; + camif_priv->cam_common_cfg.hdr_bhist_src_sel = + vfe_core_cfg->core_config.hdr_bhist_src_sel; + camif_priv->cam_common_cfg.input_mux_sel_pdaf = + vfe_core_cfg->core_config.input_mux_sel_pdaf; + camif_priv->cam_common_cfg.input_mux_sel_pp = + vfe_core_cfg->core_config.input_mux_sel_pp; + + return 0; +} + +static int cam_vfe_camif_ver3_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_ver3_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + camif_priv->enable_sof_irq_debug = true; + else + camif_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_camif_ver3_process_cmd( + struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_mux_camif_ver3_data *camif_priv = NULL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, + "Invalid input arguments rsesource node:%pK cmd_args:%pK", + rsrc_node, cmd_args); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_ver3_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_camif_ver3_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = cam_vfe_camif_ver3_core_config(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + camif_priv = (struct cam_vfe_mux_camif_ver3_data *) + rsrc_node->res_priv; + camif_priv->camif_debug = *((uint32_t *)cmd_args); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static void cam_vfe_camif_ver3_print_status(uint32_t *status, + int err_type) +{ + uint32_t violation_mask = 0x3F, module_id = 0; + uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; + + if (!status) { + CAM_ERR(CAM_ISP, "Invalid params"); + return; + } + + bus_overflow_status = status[CAM_IFE_IRQ_REGISTERS_MAX]; + status_0 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + status_2 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]; + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW) { + if (status_0 & 0x0200) + CAM_INFO(CAM_ISP, "DSP OVERFLOW"); + + if (status_0 & 0x2000000) + CAM_INFO(CAM_ISP, "PIXEL PIPE FRAME DROP"); + + if (status_0 & 0x80000000) + CAM_INFO(CAM_ISP, "PIXEL PIPE OVERFLOW"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && bus_overflow_status) { + if (bus_overflow_status & 0x01) + CAM_INFO(CAM_ISP, "VID Y 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x02) + CAM_INFO(CAM_ISP, "VID C 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x04) + CAM_INFO(CAM_ISP, "VID YC 4:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x08) + CAM_INFO(CAM_ISP, "VID YC 16:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x010) + CAM_INFO(CAM_ISP, "DISP Y 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x020) + CAM_INFO(CAM_ISP, "DISP C 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x040) + CAM_INFO(CAM_ISP, "DISP YC 4:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x080) + CAM_INFO(CAM_ISP, "DISP YC 16:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x0100) + CAM_INFO(CAM_ISP, "FD Y BUS OVERFLOW"); + + if (bus_overflow_status & 0x0200) + CAM_INFO(CAM_ISP, "FD C BUS OVERFLOW"); + + if (bus_overflow_status & 0x0400) + CAM_INFO(CAM_ISP, "PIXEL RAW DUMP BUS OVERFLOW"); + + if (bus_overflow_status & 0x01000) + CAM_INFO(CAM_ISP, "STATS HDR BE BUS OVERFLOW"); + + if (bus_overflow_status & 0x02000) + CAM_INFO(CAM_ISP, "STATS HDR BHIST BUS OVERFLOW"); + + if (bus_overflow_status & 0x04000) + CAM_INFO(CAM_ISP, "STATS TINTLESS BG BUS OVERFLOW"); + + if (bus_overflow_status & 0x08000) + CAM_INFO(CAM_ISP, "STATS AWB BG BUS OVERFLOW"); + + if (bus_overflow_status & 0x010000) + CAM_INFO(CAM_ISP, "STATS BHIST BUS OVERFLOW"); + + if (bus_overflow_status & 0x020000) + CAM_INFO(CAM_ISP, "STATS RS BUS OVERFLOW"); + + if (bus_overflow_status & 0x040000) + CAM_INFO(CAM_ISP, "STATS CS BUS OVERFLOW"); + + if (bus_overflow_status & 0x080000) + CAM_INFO(CAM_ISP, "STATS IHIST BUS OVERFLOW"); + + if (bus_overflow_status & 0x0100000) + CAM_INFO(CAM_ISP, "STATS BAF BUS OVERFLOW"); + + if (bus_overflow_status & 0x0200000) + CAM_INFO(CAM_ISP, "PDAF BUS OVERFLOW"); + + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { + CAM_INFO(CAM_ISP, "PIXEL PIPE Module hang"); + /* print debug registers */ + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION) { + if (status_2 & 0x080) + CAM_INFO(CAM_ISP, "DSP IFE PROTOCOL VIOLATION"); + + if (status_2 & 0x0100) + CAM_INFO(CAM_ISP, "IFE DSP TX PROTOCOL VIOLATION"); + + if (status_2 & 0x0200) + CAM_INFO(CAM_ISP, "DSP IFE RX PROTOCOL VIOLATION"); + + if (status_2 & 0x0400) + CAM_INFO(CAM_ISP, "PP PREPROCESS VIOLATION"); + + if (status_2 & 0x0800) + CAM_INFO(CAM_ISP, "PP CAMIF VIOLATION"); + + if (status_2 & 0x01000) + CAM_INFO(CAM_ISP, "PP VIOLATION"); + + if (status_2 & 0x0100000) + CAM_INFO(CAM_ISP, + "DSP_TX_VIOLATION:overflow on DSP interface TX path FIFO"); + + if (status_2 & 0x0200000) + CAM_INFO(CAM_ISP, + "DSP_RX_VIOLATION:overflow on DSP interface RX path FIFO"); + + if (status_2 & 0x10000000) + CAM_INFO(CAM_ISP, "DSP ERROR VIOLATION"); + + if (status_2 & 0x20000000) + CAM_INFO(CAM_ISP, + "DIAG VIOLATION: HBI is less than the minimum required HBI"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION && + status[CAM_IFE_IRQ_VIOLATION_STATUS]) { + module_id = + violation_mask & status[CAM_IFE_IRQ_VIOLATION_STATUS]; + CAM_INFO(CAM_ISP, "PIXEL PIPE VIOLATION Module ID:%d", + module_id); + + switch (module_id) { + case 0: + CAM_INFO(CAM_ISP, "DEMUX"); + break; + case 1: + CAM_INFO(CAM_ISP, "CHROMA_UP"); + break; + case 2: + CAM_INFO(CAM_ISP, "PEDESTAL"); + break; + case 3: + CAM_INFO(CAM_ISP, "LINEARIZATION"); + break; + case 4: + CAM_INFO(CAM_ISP, "BPC_PDPC"); + break; + case 5: + CAM_INFO(CAM_ISP, "HDR_BINCORRECT"); + break; + case 6: + CAM_INFO(CAM_ISP, "ABF"); + break; + case 7: + CAM_INFO(CAM_ISP, "LSC"); + break; + case 8: + CAM_INFO(CAM_ISP, "DEMOSAIC"); + break; + case 9: + CAM_INFO(CAM_ISP, "COLOR_CORRECT"); + break; + case 10: + CAM_INFO(CAM_ISP, "GTM"); + break; + case 11: + CAM_INFO(CAM_ISP, "GLUT"); + break; + case 12: + CAM_INFO(CAM_ISP, "COLOR_XFORM"); + break; + case 13: + CAM_INFO(CAM_ISP, "CROP_RND_CLAMP_PIXEL_RAW_OUT"); + break; + case 14: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_Y_FD_OUT"); + break; + case 15: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_C_FD_OUT"); + break; + case 16: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_FD_OUT"); + break; + case 17: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_FD_OUT"); + break; + case 18: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_Y_DISP_OUT"); + break; + case 19: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_C_DISP_OUT"); + break; + case 20: + CAM_INFO(CAM_ISP, + "module: CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_DISP_OUT"); + break; + case 21: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_DISP_OUT"); + break; + case 22: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_Y_DISP_DS4_OUT"); + break; + case 23: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_C_DISP_DS4_OUT"); + break; + case 24: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_DISP_DS4_OUT"); + break; + case 25: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_DISP_DS4_OUT"); + break; + case 26: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_Y_DISP_DS16_OUT"); + break; + case 27: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_C_DISP_DS16_OUT"); + break; + case 28: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_DISP_DS16_OUT"); + break; + case 29: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_DISP_DS16_OUT"); + break; + case 30: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_Y_VID_OUT"); + break; + case 31: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_C_VID_OUT"); + break; + case 32: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT"); + break; + case 33: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT"); + break; + case 34: + CAM_INFO(CAM_ISP, "DSX_Y_VID_OUT"); + break; + case 35: + CAM_INFO(CAM_ISP, "DSX_C_VID_OUT"); + break; + case 36: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DSX_Y_VID_OUT"); + break; + case 37: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DSX_C_VID_OUT"); + break; + case 38: + CAM_INFO(CAM_ISP, + "DOWNSCALE_4TO1_Y_VID_DS16_OUT"); + break; + case 39: + CAM_INFO(CAM_ISP, + "DOWNSCALE_4TO1_C_VID_DS16_OUT"); + break; + case 40: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT"); + break; + case 41: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT"); + break; + case 42: + CAM_INFO(CAM_ISP, "BLS"); + break; + case 43: + CAM_INFO(CAM_ISP, "STATS_TINTLESS_BG"); + break; + case 44: + CAM_INFO(CAM_ISP, "STATS_HDR_BHIST"); + break; + case 45: + CAM_INFO(CAM_ISP, "STATS_HDR_BE"); + break; + case 46: + CAM_INFO(CAM_ISP, "STATS_AWB_BG"); + break; + case 47: + CAM_INFO(CAM_ISP, "STATS_BHIST"); + break; + case 48: + CAM_INFO(CAM_ISP, "STATS_BAF"); + break; + case 49: + CAM_INFO(CAM_ISP, "STATS_RS"); + break; + case 50: + CAM_INFO(CAM_ISP, "STATS_CS"); + break; + case 51: + CAM_INFO(CAM_ISP, "STATS_IHIST"); + break; + default: + CAM_ERR(CAM_ISP, + "Invalid Module ID:%d", module_id); + break; + } + } +} + +static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + + CAM_DBG(CAM_ISP, + "VFE:%d CAMIF IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_node->hw_intf->hw_idx, th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], th_payload->evt_status_arr[2]); + + rc = cam_vfe_camif_ver3_get_evt_payload(camif_priv, &evt_payload); + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d CAMIF IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_node->hw_intf->hw_idx, th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], th_payload->evt_status_arr[2]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX + 1] = {0}; + int i = 0; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid params handle_priv:%pK, evt_payload_priv:%pK", + handler_priv, evt_payload_priv); + return ret; + } + + camif_node = handler_priv; + camif_priv = camif_node->res_priv; + payload = evt_payload_priv; + + for (i = 0; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) + irq_status[i] = payload->irq_reg_val[i]; + + evt_info.hw_idx = camif_node->hw_intf->hw_idx; + evt_info.res_id = camif_node->res_id; + evt_info.res_type = camif_node->res_type; + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->sof_irq_mask) { + if ((camif_priv->enable_sof_irq_debug) && + (camif_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "VFE:%d Received SOF", + evt_info.hw_idx); + + camif_priv->irq_debug_cnt++; + if (camif_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + camif_priv->enable_sof_irq_debug = + false; + camif_priv->irq_debug_cnt = 0; + } + } else + CAM_DBG(CAM_ISP, "VFE:%d Received SOF", + evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d Received EOF", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_priv->reg_data->error_irq_mask0) { + CAM_ERR(CAM_ISP, "VFE:%d Overflow", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = + cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->bus_overflow_status); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + cam_vfe_camif_ver3_print_status(irq_status, ret); + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_ver3_reg_dump(camif_node); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { + CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_VIOLATION; + + cam_vfe_camif_ver3_print_status(irq_status, ret); + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_ver3_reg_dump(camif_node); + } + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + CAM_DBG(CAM_ISP, "VFE:%d VFE_DIAG_SENSOR_STATUS: 0x%X", + evt_info.hw_idx, camif_priv->mem_base, + cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->diag_sensor_status_0)); + } + + cam_vfe_camif_ver3_put_evt_payload(camif_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv = NULL; + struct cam_vfe_camif_ver3_hw_info *camif_info = camif_hw_info; + int i = 0; + + camif_priv = kzalloc(sizeof(struct cam_vfe_mux_camif_ver3_data), + GFP_KERNEL); + if (!camif_priv) + return -ENOMEM; + + camif_node->res_priv = camif_priv; + + camif_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_priv->camif_reg = camif_info->camif_reg; + camif_priv->common_reg = camif_info->common_reg; + camif_priv->reg_data = camif_info->reg_data; + camif_priv->hw_intf = hw_intf; + camif_priv->soc_info = soc_info; + camif_priv->vfe_irq_controller = vfe_irq_controller; + + camif_node->init = cam_vfe_camif_ver3_resource_init; + camif_node->deinit = cam_vfe_camif_ver3_resource_deinit; + camif_node->start = cam_vfe_camif_ver3_resource_start; + camif_node->stop = cam_vfe_camif_ver3_resource_stop; + camif_node->process_cmd = cam_vfe_camif_ver3_process_cmd; + camif_node->top_half_handler = cam_vfe_camif_ver3_handle_irq_top_half; + camif_node->bottom_half_handler = + cam_vfe_camif_ver3_handle_irq_bottom_half; + spin_lock_init(&camif_priv->spin_lock); + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + list_add_tail(&camif_priv->evt_payload[i].list, + &camif_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_ver3_deinit( + struct cam_isp_resource_node *camif_node) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + int i = 0; + + if (!camif_node) { + CAM_ERR(CAM_ISP, "Error, camif_node is NULL %pK", camif_node); + return -ENODEV; + } + + camif_priv = camif_node->res_priv; + + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + + camif_priv = camif_node->res_priv; + + camif_node->start = NULL; + camif_node->stop = NULL; + camif_node->process_cmd = NULL; + camif_node->top_half_handler = NULL; + camif_node->bottom_half_handler = NULL; + camif_node->res_priv = NULL; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Error, camif_priv is NULL %pK", camif_priv); + return -ENODEV; + } + + kfree(camif_priv); + + return 0; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h new file mode 100644 index 000000000000..3c82ca2ba7d6 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_VER3_H_ +#define _CAM_VFE_CAMIF_VER3_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_camif_ver3_pp_clc_reg { + uint32_t hw_version; + uint32_t hw_status; + uint32_t module_cfg; + uint32_t pdaf_raw_crop_width_cfg; + uint32_t pdaf_raw_crop_height_cfg; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t period_cfg; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq_cfg; + uint32_t debug_1; + uint32_t debug_0; + uint32_t test_bus_ctrl; + uint32_t spare; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_camif_ver3_reg_data { + uint32_t pp_extern_reg_update_shift; + uint32_t dual_pd_extern_reg_update_shift; + uint32_t extern_reg_update_mask; + uint32_t dual_ife_pix_en_shift; + uint32_t operating_mode_shift; + uint32_t input_mux_sel_shift; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask2; + uint32_t subscribe_irq_mask1; + + uint32_t enable_diagnostic_hw; + uint32_t pp_camif_cfg_en_shift; + uint32_t pp_camif_cfg_ife_out_en_shift; +}; + +struct cam_vfe_camif_ver3_hw_info { + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_ver3_pp_clc_reg *camif_reg; + struct cam_vfe_camif_ver3_reg_data *reg_data; +}; + +int cam_vfe_camif_ver3_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_camif_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller); + +int cam_vfe_camif_ver3_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_VER3_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c new file mode 100644 index 000000000000..98c84ad77d93 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_fe_ver1.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_fe_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t fe_cfg_data; + uint32_t hbi_count; +}; + +static int cam_vfe_fe_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error! Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_fe_update( + struct cam_isp_resource_node *fe_res, + void *cmd_data, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + struct cam_vfe_fe_update_args *args = cmd_data; + uint32_t fe_cfg_data; + + if (arg_size != sizeof(struct cam_vfe_fe_update_args)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "fe_update->min_vbi = 0x%x", args->fe_config.min_vbi); + CAM_DBG(CAM_ISP, "fe_update->hbi_count = 0x%x", + args->fe_config.hbi_count); + CAM_DBG(CAM_ISP, "fe_update->fs_mode = 0x%x", args->fe_config.fs_mode); + CAM_DBG(CAM_ISP, "fe_update->fs_line_sync_en = 0x%x", + args->fe_config.fs_line_sync_en); + + fe_cfg_data = args->fe_config.min_vbi | + args->fe_config.fs_mode << 8 | + args->fe_config.fs_line_sync_en; + + rsrc_data = fe_res->res_priv; + rsrc_data->fe_cfg_data = fe_cfg_data; + rsrc_data->hbi_count = args->fe_config.hbi_count; + + CAM_DBG(CAM_ISP, "fe_cfg_data = 0x%x", fe_cfg_data); + return 0; +} + +static int cam_vfe_fe_get_reg_update( + struct cam_isp_resource_node *fe_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = fe_res->res_priv; + reg_val_pair[0] = rsrc_data->fe_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF reg_update_cmd 0x%x offset 0x%x", + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *fe_res, + void *acquire_param) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_vfe_acquire_args *acquire_data; + + int rc = 0; + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_fe_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + if (rc) { + CAM_ERR(CAM_ISP, "pix validation failed: id:%d pix_pattern %d", + fe_res->hw_intf->hw_idx, + acquire_data->vfe_in.in_port->test_pattern); + return rc; + } + + fe_data->sync_mode = acquire_data->vfe_in.sync_mode; + fe_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + fe_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + fe_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + fe_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + fe_data->first_line = acquire_data->vfe_in.in_port->line_start; + fe_data->last_line = acquire_data->vfe_in.in_port->line_stop; + + CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", + fe_res->hw_intf->hw_idx, + fe_data->pix_pattern, fe_data->dsp_mode); + return rc; +} + +static int cam_vfe_fe_resource_init( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to enable dsp clk"); + } + + return rc; +} + +static int cam_vfe_fe_resource_deinit( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; + +} + +static int cam_vfe_fe_resource_start( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid fe res res_state:%d", + fe_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + /* config vfe core */ + val = (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + if (rsrc_data->fe_cfg_data) { + /*set Mux mode value to EXT_RD_PATH */ + val |= (rsrc_data->reg_data->fe_mux_data << + rsrc_data->reg_data->input_mux_sel_shift); + } + + if (rsrc_data->hbi_count) { + /*set hbi count*/ + val |= (rsrc_data->hbi_count << + rsrc_data->reg_data->hbi_cnt_shift); + } + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->common_reg->core_cfg, + val); + + /* disable the CGC for stats */ + cam_io_w_mb(0xFFFFFFFF, rsrc_data->mem_base + + rsrc_data->common_reg->module_ctrl[ + CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); + + /* epoch config */ + epoch0_irq_mask = ((rsrc_data->last_line - rsrc_data->first_line) / 2) + + rsrc_data->first_line; + + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + rsrc_data->fe_reg->epoch_irq); + CAM_DBG(CAM_ISP, "first_line:0x%x last_line:0x%x epoch_line_cfg: 0x%x", + rsrc_data->first_line, rsrc_data->last_line, + computed_epoch_line_cfg); + + fe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Read Back cfg */ + cam_io_w_mb(rsrc_data->fe_cfg_data, + rsrc_data->mem_base + rsrc_data->fe_reg->fe_cfg); + CAM_DBG(CAM_ISP, "hw id:%d fe_cfg_data(off:0x%x val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->fe_cfg, + rsrc_data->fe_cfg_data); + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->fe_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->reg_update_cmd, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + CAM_DBG(CAM_ISP, "Start Camif IFE %d Done", fe_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_fe_reg_dump( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0, i; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + soc_private = fe_priv->soc_info->soc_private; + for (i = 0xA3C; i <= 0xA90; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0xE0C; i <= 0xE3C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2000; i <= 0x20B8; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2500; i <= 0x255C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2600; i <= 0x265C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + + return rc; +} + +static int cam_vfe_fe_resource_stop( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_fe_ver1_reg *fe_reg; + int rc = 0; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + fe_reg = fe_priv->fe_reg; + + if ((fe_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + val &= (~(1 << fe_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + fe_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return rc; +} + +static int cam_vfe_fe_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_fe_data *fe_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + fe_priv = + (struct cam_vfe_mux_fe_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + fe_priv->enable_sof_irq_debug = true; + else + fe_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_fe_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_fe_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_fe_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_fe_update(rsrc_node, cmd_args, arg_size); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_fe_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_fe_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *fe_node; + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + uint32_t irq_status1; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + fe_node = handler_priv; + fe_priv = fe_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + evt_info.hw_idx = fe_node->hw_intf->hw_idx; + evt_info.res_id = fe_node->res_id; + evt_info.res_type = fe_node->res_type; + + CAM_DBG(CAM_ISP, "event ID, irq_status_0 = 0x%x", irq_status0); + + if (irq_status0 & fe_priv->reg_data->sof_irq_mask) { + if ((fe_priv->enable_sof_irq_debug) && + (fe_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "Received SOF"); + + fe_priv->irq_debug_cnt++; + if (fe_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + fe_priv->enable_sof_irq_debug = + false; + fe_priv->irq_debug_cnt = 0; + } + } else { + CAM_DBG(CAM_ISP, "Received SOF"); + } + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & fe_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & fe_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & fe_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status1 & fe_priv->reg_data->error_irq_mask1) { + CAM_DBG(CAM_ISP, "Received ERROR"); + ret = CAM_ISP_HW_ERROR_OVERFLOW; + evt_info.err_type = CAM_VFE_IRQ_STATUS_OVERFLOW; + cam_vfe_fe_reg_dump(fe_node); + } else { + ret = CAM_ISP_HW_ERROR_NONE; + } + + CAM_DBG(CAM_ISP, "returing status = %d", ret); + return ret; +} + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *fe_hw_info, + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = NULL; + struct cam_vfe_fe_ver1_hw_info *fe_info = fe_hw_info; + + fe_priv = kzalloc(sizeof(struct cam_vfe_mux_fe_data), + GFP_KERNEL); + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! Failed to alloc for fe_priv"); + return -ENOMEM; + } + + fe_node->res_priv = fe_priv; + + fe_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + fe_priv->fe_reg = fe_info->fe_reg; + fe_priv->common_reg = fe_info->common_reg; + fe_priv->reg_data = fe_info->reg_data; + fe_priv->hw_intf = hw_intf; + fe_priv->soc_info = soc_info; + + fe_node->init = cam_vfe_fe_resource_init; + fe_node->deinit = cam_vfe_fe_resource_deinit; + fe_node->start = cam_vfe_fe_resource_start; + fe_node->stop = cam_vfe_fe_resource_stop; + fe_node->process_cmd = cam_vfe_fe_process_cmd; + fe_node->top_half_handler = cam_vfe_fe_handle_irq_top_half; + fe_node->bottom_half_handler = cam_vfe_fe_handle_irq_bottom_half; + + return 0; +} + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = fe_node->res_priv; + + fe_node->start = NULL; + fe_node->stop = NULL; + fe_node->process_cmd = NULL; + fe_node->top_half_handler = NULL; + fe_node->bottom_half_handler = NULL; + + fe_node->res_priv = NULL; + + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! fe_priv is NULL"); + return -ENODEV; + } + + kfree(fe_priv); + + return 0; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h new file mode 100644 index 000000000000..6974a568fd6c --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_FE_VER1_H_ +#define _CAM_VFE_FE_VER1_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_fe_ver1_reg { + uint32_t camif_cmd; + uint32_t camif_config; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t skip_period; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq; + uint32_t raw_crop_width_cfg; + uint32_t raw_crop_height_cfg; + uint32_t reg_update_cmd; + uint32_t vfe_diag_config; + uint32_t vfe_diag_sensor_status; + uint32_t fe_cfg; +}; + +struct cam_vfe_fe_reg_data { + uint32_t raw_crop_first_pixel_shift; + uint32_t raw_crop_first_pixel_mask; + + uint32_t raw_crop_last_pixel_shift; + uint32_t raw_crop_last_pixel_mask; + + uint32_t raw_crop_first_line_shift; + uint32_t raw_crop_first_line_mask; + + uint32_t raw_crop_last_line_shift; + uint32_t raw_crop_last_line_mask; + + uint32_t input_mux_sel_shift; + uint32_t input_mux_sel_mask; + uint32_t extern_reg_update_shift; + uint32_t extern_reg_update_mask; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t reg_update_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + + uint32_t enable_diagnostic_hw; + uint32_t fe_mux_data; + uint32_t hbi_cnt_shift; +}; + +struct cam_vfe_fe_ver1_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_fe_reg_data *reg_data; +}; + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node); + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_FE_VER1_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c new file mode 100644 index 000000000000..0b230ce19621 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -0,0 +1,526 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_vfe_rdi.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_top_ver2.h" +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" + +struct cam_vfe_mux_rdi_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_rdi_ver2_reg *rdi_reg; + struct cam_vfe_rdi_common_reg_data *rdi_common_reg_data; + struct cam_vfe_rdi_reg_data *reg_data; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_RDI_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + + enum cam_isp_hw_sync_mode sync_mode; +}; + +static int cam_vfe_rdi_get_evt_payload( + struct cam_vfe_mux_rdi_data *rdi_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&rdi_priv->spin_lock); + if (list_empty(&rdi_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&rdi_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&rdi_priv->spin_lock); + return rc; +} + +static int cam_vfe_rdi_put_evt_payload( + struct cam_vfe_mux_rdi_data *rdi_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!rdi_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&rdi_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, &rdi_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&rdi_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_rdi_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *rdi_node; + struct cam_vfe_mux_rdi_data *rdi_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rdi_node = th_payload->handler_priv; + rdi_priv = rdi_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[1]) { + CAM_ERR(CAM_ISP, + "RDI Error: vfe:%d: STATUS_1=0x%x", + rdi_node->hw_intf->hw_idx, + th_payload->evt_status_arr[1]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from vfe=%d", + rdi_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq(rdi_priv->vfe_irq_controller, + rdi_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + rdi_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_rdi_get_evt_payload(rdi_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "STATUS_1=0x%x", + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(rdi_priv->mem_base + + rdi_priv->common_reg->violation_status); + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = 0x%x", + evt_payload->irq_reg_val[i]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_rdi_get_reg_update( + struct cam_isp_resource_node *rdi_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_rdi_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Error - Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Error - Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Error - Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, + "Error - buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size * 4); + return -EINVAL; + } + + rsrc_data = rdi_res->res_priv; + reg_val_pair[0] = rsrc_data->rdi_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "RDI%d reg_update_cmd %x", + rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0, reg_val_pair[1]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_rdi_ver2_acquire_resource( + struct cam_isp_resource_node *rdi_res, + void *acquire_param) +{ + struct cam_vfe_mux_rdi_data *rdi_data; + struct cam_vfe_acquire_args *acquire_data; + + rdi_data = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rdi_data->event_cb = acquire_data->event_cb; + rdi_data->priv = acquire_data->priv; + rdi_data->sync_mode = acquire_data->vfe_in.sync_mode; + + return 0; +} + +static int cam_vfe_rdi_resource_start( + struct cam_isp_resource_node *rdi_res) +{ + struct cam_vfe_mux_rdi_data *rsrc_data; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + + if (!rdi_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (rdi_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid rdi res res_state:%d", + rdi_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->rdi_common_reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->rdi_common_reg_data->error_irq_mask1; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->rdi_common_reg_data->subscribe_irq_mask0; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->rdi_common_reg_data->subscribe_irq_mask1; + + rdi_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->rdi_reg->reg_update_cmd); + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + err_irq_mask, + rdi_res, + cam_vfe_rdi_err_irq_top_half, + rdi_res->bottom_half_handler, + rdi_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + if (!rdi_res->rdi_only_ctx) + goto end; + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + irq_mask, + rdi_res, + rdi_res->top_half_handler, + rdi_res->bottom_half_handler, + rdi_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "Start RDI %d", + rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0); +end: + return rc; +} + + +static int cam_vfe_rdi_resource_stop( + struct cam_isp_resource_node *rdi_res) +{ + struct cam_vfe_mux_rdi_data *rdi_priv; + int rc = 0; + + if (!rdi_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (rdi_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + rdi_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + rdi_priv = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv; + + if (rdi_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + rdi_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + if (rdi_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + rdi_priv->vfe_irq_controller, rdi_priv->irq_handle); + rdi_priv->irq_handle = 0; + } + + if (rdi_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + rdi_priv->vfe_irq_controller, rdi_priv->irq_err_handle); + rdi_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_rdi_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_rdi_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported RDI process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_rdi_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *rdi_node; + struct cam_vfe_mux_rdi_data *rdi_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + rdi_node = th_payload->handler_priv; + rdi_priv = rdi_node->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rc = cam_vfe_rdi_get_evt_payload(rdi_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ status0=0x%x status1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *rdi_node; + struct cam_vfe_mux_rdi_data *rdi_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + rdi_node = handler_priv; + rdi_priv = rdi_node->res_priv; + payload = evt_payload_priv; + + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + + evt_info.hw_idx = rdi_node->hw_intf->hw_idx; + evt_info.res_id = rdi_node->res_id; + evt_info.res_type = rdi_node->res_type; + + CAM_DBG(CAM_ISP, "irq_status_0 = %x", irq_status0); + + if (irq_status0 & rdi_priv->reg_data->sof_irq_mask) { + CAM_DBG(CAM_ISP, "Received SOF"); + + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } else if (irq_status0 & rdi_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG UPDATE"); + + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_REG_UPDATE, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + cam_vfe_rdi_put_evt_payload(rdi_priv, &payload); + CAM_DBG(CAM_ISP, "returing status = %d", ret); + return ret; +} + +int cam_vfe_rdi_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *rdi_hw_info, + struct cam_isp_resource_node *rdi_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_rdi_data *rdi_priv = NULL; + struct cam_vfe_rdi_ver2_hw_info *rdi_info = rdi_hw_info; + int i = 0; + + rdi_priv = kzalloc(sizeof(struct cam_vfe_mux_rdi_data), + GFP_KERNEL); + if (!rdi_priv) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for rdi_priv"); + return -ENOMEM; + } + + rdi_node->res_priv = rdi_priv; + + rdi_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + rdi_priv->hw_intf = hw_intf; + rdi_priv->common_reg = rdi_info->common_reg; + rdi_priv->rdi_reg = rdi_info->rdi_reg; + rdi_priv->vfe_irq_controller = vfe_irq_controller; + rdi_priv->rdi_common_reg_data = rdi_info->common_reg_data; + + switch (rdi_node->res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + rdi_priv->reg_data = rdi_info->reg_data[0]; + break; + case CAM_ISP_HW_VFE_IN_RDI1: + rdi_priv->reg_data = rdi_info->reg_data[1]; + break; + case CAM_ISP_HW_VFE_IN_RDI2: + rdi_priv->reg_data = rdi_info->reg_data[2]; + break; + case CAM_ISP_HW_VFE_IN_RDI3: + if (rdi_info->reg_data[3]) { + rdi_priv->reg_data = rdi_info->reg_data[3]; + } else { + CAM_ERR(CAM_ISP, "Error! RDI3 is not supported"); + goto err_init; + } + break; + default: + CAM_DBG(CAM_ISP, "invalid Resource id:%d", rdi_node->res_id); + goto err_init; + } + + rdi_node->start = cam_vfe_rdi_resource_start; + rdi_node->stop = cam_vfe_rdi_resource_stop; + rdi_node->process_cmd = cam_vfe_rdi_process_cmd; + rdi_node->top_half_handler = cam_vfe_rdi_handle_irq_top_half; + rdi_node->bottom_half_handler = cam_vfe_rdi_handle_irq_bottom_half; + + spin_lock_init(&rdi_priv->spin_lock); + INIT_LIST_HEAD(&rdi_priv->free_payload_list); + for (i = 0; i < CAM_VFE_RDI_EVT_MAX; i++) { + INIT_LIST_HEAD(&rdi_priv->evt_payload[i].list); + list_add_tail(&rdi_priv->evt_payload[i].list, + &rdi_priv->free_payload_list); + } + + return 0; +err_init: + kfree(rdi_priv); + return -EINVAL; +} + +int cam_vfe_rdi_ver2_deinit( + struct cam_isp_resource_node *rdi_node) +{ + struct cam_vfe_mux_rdi_data *rdi_priv = rdi_node->res_priv; + int i = 0; + + INIT_LIST_HEAD(&rdi_priv->free_payload_list); + for (i = 0; i < CAM_VFE_RDI_EVT_MAX; i++) + INIT_LIST_HEAD(&rdi_priv->evt_payload[i].list); + + rdi_node->start = NULL; + rdi_node->stop = NULL; + rdi_node->process_cmd = NULL; + rdi_node->top_half_handler = NULL; + rdi_node->bottom_half_handler = NULL; + + rdi_node->res_priv = NULL; + + if (!rdi_priv) { + CAM_ERR(CAM_ISP, "Error! rdi_priv NULL"); + return -ENODEV; + } + kfree(rdi_priv); + + return 0; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h new file mode 100644 index 000000000000..c570e84a011c --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_RDI_H_ +#define _CAM_VFE_RDI_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +#define CAM_VFE_RDI_VER2_MAX 4 + +#define CAM_VFE_RDI_EVT_MAX 256 + +struct cam_vfe_rdi_ver2_reg { + uint32_t reg_update_cmd; +}; + +struct cam_vfe_rdi_common_reg_data { + uint32_t subscribe_irq_mask0; + uint32_t subscribe_irq_mask1; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + uint32_t error_irq_mask2; + uint32_t rdi_frame_drop_mask; +}; + +struct cam_vfe_rdi_reg_data { + uint32_t reg_update_cmd_data; + uint32_t sof_irq_mask; + uint32_t reg_update_irq_mask; +}; +struct cam_vfe_rdi_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_rdi_ver2_reg *rdi_reg; + struct cam_vfe_rdi_common_reg_data *common_reg_data; + struct cam_vfe_rdi_reg_data *reg_data[CAM_VFE_RDI_VER2_MAX]; +}; + +int cam_vfe_rdi_ver2_acquire_resource( + struct cam_isp_resource_node *rdi_res, + void *acquire_param); + +int cam_vfe_rdi_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *rdi_hw_info, + struct cam_isp_resource_node *rdi_node, + void *vfe_irq_controller); + +int cam_vfe_rdi_ver2_deinit( + struct cam_isp_resource_node *rdi_node); + +#endif /* _CAM_VFE_RDI_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c new file mode 100644 index 000000000000..077f89060bca --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_top_ver3.h" +#include "cam_debug_util.h" + +int cam_vfe_top_init(uint32_t top_version, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top) +{ + int rc = -EINVAL; + + switch (top_version) { + case CAM_VFE_TOP_VER_2_0: + rc = cam_vfe_top_ver2_init(soc_info, hw_intf, top_hw_info, + vfe_irq_controller, vfe_top); + break; + case CAM_VFE_TOP_VER_3_0: + rc = cam_vfe_top_ver3_init(soc_info, hw_intf, top_hw_info, + vfe_irq_controller, vfe_top); + break; + default: + CAM_ERR(CAM_ISP, "Error! Unsupported Version %x", top_version); + break; + } + + return rc; +} + +int cam_vfe_top_deinit(uint32_t top_version, + struct cam_vfe_top **vfe_top) +{ + int rc = -EINVAL; + + switch (top_version) { + case CAM_VFE_TOP_VER_2_0: + rc = cam_vfe_top_ver2_deinit(vfe_top); + break; + case CAM_VFE_TOP_VER_3_0: + rc = cam_vfe_top_ver3_deinit(vfe_top); + break; + default: + CAM_ERR(CAM_ISP, "Error! Unsupported Version %x", top_version); + break; + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c new file mode 100644 index 000000000000..78a72eb6846a --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -0,0 +1,1059 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_io_util.h" +#include "cam_cdm_util.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_vfe_soc.h" + +#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00003F9F +#define CAM_VFE_HW_RESET_HW_VAL 0x00003F87 +#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 3 + +struct cam_vfe_top_ver2_common_data { + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *hw_intf; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; +}; + +struct cam_vfe_top_ver2_priv { + struct cam_vfe_top_ver2_common_data common_data; + struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX]; + unsigned long hw_clk_rate; + struct cam_axi_vote applied_axi_vote; + struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX]; + unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX]; + struct cam_axi_vote last_vote[CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; + uint32_t last_counter; + uint64_t total_bw_applied; + enum cam_vfe_bw_control_action + axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX]; +}; + +static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t mem_base = 0; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Error! Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res || !top_priv || + !top_priv->common_data.soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid args"); + return -EINVAL; + } + + cdm_util_ops = + (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_changebase(); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE( + top_priv->common_data.soc_info, VFE_CORE_BASE_IDX); + CAM_DBG(CAM_ISP, "core %d mem_base 0x%x", + top_priv->common_data.soc_info->index, mem_base); + + cdm_util_ops->cdm_write_changebase( + cdm_args->cmd.cmd_buf_addr, mem_base); + cdm_args->cmd.used_bytes = (size * 4); + + return 0; +} + +static int cam_vfe_top_set_hw_clk_rate( + struct cam_vfe_top_ver2_priv *top_priv) +{ + struct cam_hw_soc_info *soc_info = NULL; + int i, rc = 0; + unsigned long max_clk_rate = 0; + + soc_info = top_priv->common_data.soc_info; + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->req_clk_rate[i] > max_clk_rate) + max_clk_rate = top_priv->req_clk_rate[i]; + } + if (max_clk_rate == top_priv->hw_clk_rate) + return 0; + + CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%llu", + soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, max_clk_rate); + + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); + + if (!rc) + top_priv->hw_clk_rate = max_clk_rate; + else + CAM_ERR(CAM_ISP, "Set Clock rate failed, rc=%d", rc); + + return rc; +} + +static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction( + struct cam_vfe_top_ver2_priv *top_priv, + uint64_t *to_be_applied_bw) +{ + uint32_t i, j; + int vote_idx = -1; + uint64_t max_bw = 0; + uint64_t total_bw; + struct cam_axi_vote *curr_l_vote; + + for (i = 0; i < (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { + total_bw = 0; + curr_l_vote = &top_priv->last_vote[i]; + for (j = 0; j < curr_l_vote->num_paths; j++) { + if (total_bw > + (U64_MAX - + curr_l_vote->axi_path[j].camnoc_bw)) { + CAM_ERR(CAM_ISP, "Overflow at idx: %d", j); + return NULL; + } + + total_bw += curr_l_vote->axi_path[j].camnoc_bw; + } + + if (total_bw > max_bw) { + vote_idx = i; + max_bw = total_bw; + } + } + + if (vote_idx < 0) + return NULL; + + *to_be_applied_bw = max_bw; + + return &top_priv->last_vote[vote_idx]; +} + +static int cam_vfe_top_set_axi_bw_vote( + struct cam_vfe_top_ver2_priv *top_priv, + bool start_stop) +{ + struct cam_axi_vote agg_vote = {0}; + struct cam_axi_vote *to_be_applied_axi_vote = NULL; + int rc = 0; + uint32_t i; + uint32_t num_paths = 0; + uint64_t total_bw_new_vote = 0; + bool bw_unchanged = true; + struct cam_hw_soc_info *soc_info = + top_priv->common_data.soc_info; + struct cam_vfe_soc_private *soc_private = + soc_info->soc_private; + bool apply_bw_update = false; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->axi_vote_control[i] == + CAM_VFE_BW_CONTROL_INCLUDE) { + if (num_paths + + top_priv->req_axi_vote[i].num_paths > + CAM_CPAS_MAX_PATHS_PER_CLIENT) { + CAM_ERR(CAM_ISP, + "Required paths(%d) more than max(%d)", + num_paths + + top_priv->req_axi_vote[i].num_paths, + CAM_CPAS_MAX_PATHS_PER_CLIENT); + return -EINVAL; + } + + memcpy(&agg_vote.axi_path[num_paths], + &top_priv->req_axi_vote[i].axi_path[0], + top_priv->req_axi_vote[i].num_paths * + sizeof( + struct cam_axi_per_path_bw_vote)); + num_paths += top_priv->req_axi_vote[i].num_paths; + } + } + + agg_vote.num_paths = num_paths; + + for (i = 0; i < agg_vote.num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]", + top_priv->common_data.hw_intf->hw_idx, + top_priv->last_counter, + cam_cpas_axi_util_path_type_to_string( + agg_vote.axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + agg_vote.axi_path[i].transac_type), + agg_vote.axi_path[i].camnoc_bw, + agg_vote.axi_path[i].mnoc_ab_bw, + agg_vote.axi_path[i].mnoc_ib_bw); + + total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; + } + + memcpy(&top_priv->last_vote[top_priv->last_counter], &agg_vote, + sizeof(struct cam_axi_vote)); + top_priv->last_counter = (top_priv->last_counter + 1) % + (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); + + if ((agg_vote.num_paths != top_priv->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_priv->total_bw_applied)) + bw_unchanged = false; + + CAM_DBG(CAM_PERF, + "ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d", + top_priv->common_data.hw_intf->hw_idx, + top_priv->total_bw_applied, total_bw_new_vote, + bw_unchanged, start_stop); + + if (bw_unchanged) { + CAM_DBG(CAM_ISP, "BW config unchanged"); + return 0; + } + + if (start_stop) { + /* need to vote current request immediately */ + to_be_applied_axi_vote = &agg_vote; + /* Reset everything, we can start afresh */ + memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * + (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); + top_priv->last_counter = 0; + top_priv->last_vote[top_priv->last_counter] = agg_vote; + top_priv->last_counter = (top_priv->last_counter + 1) % + (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); + } else { + /* + * Find max bw request in last few frames. This will the bw + * that we want to vote to CPAS now. + */ + to_be_applied_axi_vote = + cam_vfe_top_delay_bw_reduction(top_priv, + &total_bw_new_vote); + if (!to_be_applied_axi_vote) { + CAM_ERR(CAM_ISP, "to_be_applied_axi_vote is NULL"); + return -EINVAL; + } + } + + for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]", + top_priv->common_data.hw_intf->hw_idx, + cam_cpas_axi_util_path_type_to_string( + to_be_applied_axi_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + to_be_applied_axi_vote->axi_path[i].transac_type), + to_be_applied_axi_vote->axi_path[i].camnoc_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw); + } + + if ((to_be_applied_axi_vote->num_paths != + top_priv->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_priv->total_bw_applied)) + apply_bw_update = true; + + CAM_DBG(CAM_PERF, + "ife[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d", + top_priv->common_data.hw_intf->hw_idx, + top_priv->total_bw_applied, total_bw_new_vote, + apply_bw_update, start_stop); + + if (apply_bw_update) { + rc = cam_cpas_update_axi_vote(soc_private->cpas_handle, + to_be_applied_axi_vote); + if (!rc) { + memcpy(&top_priv->applied_axi_vote, + to_be_applied_axi_vote, + sizeof(struct cam_axi_vote)); + top_priv->total_bw_applied = total_bw_new_vote; + } else { + CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); + } + } + + return rc; +} + +static int cam_vfe_top_fs_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_fe_update_args *cmd_update = cmd_args; + + if (cmd_update->node_res->process_cmd) + return cmd_update->node_res->process_cmd(cmd_update->node_res, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, cmd_args, arg_size); + + return 0; +} + +static int cam_vfe_top_clock_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_clock_update_args *clk_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + clk_update = + (struct cam_vfe_clock_update_args *)cmd_args; + res = clk_update->node_res; + + if (!res || !res->hw_intf->hw_priv) { + CAM_ERR(CAM_ISP, "Invalid input res %pK", res); + return -EINVAL; + } + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + top_priv->req_clk_rate[i] = clk_update->clk_rate; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_DBG(CAM_ISP, + "VFE:%d Not ready to set clocks yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else + rc = cam_vfe_top_set_hw_clk_rate(top_priv); + + return rc; +} + +static int cam_vfe_top_bw_update_v2( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bw_update_args_v2 *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_update = (struct cam_vfe_bw_update_args_v2 *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + memcpy(&top_priv->req_axi_vote[i], &bw_update->isp_vote, + sizeof(struct cam_axi_vote)); + top_priv->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(top_priv, false); + } + + return rc; +} + +static int cam_vfe_top_bw_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bw_update_args *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + struct cam_axi_vote *mux_axi_vote; + bool vid_exists = false; + bool rdi_exists = false; + + bw_update = (struct cam_vfe_bw_update_args *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + CAM_DBG(CAM_ISP, "res_id=%d, BW=[%lld %lld]", + res->res_id, bw_update->camnoc_bw_bytes, + bw_update->external_bw_bytes); + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + mux_axi_vote = &top_priv->req_axi_vote[i]; + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + mux_axi_vote->num_paths = 1; + if ((res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && + (res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) { + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_RDI0 + + (res->res_id - CAM_ISP_HW_VFE_IN_RDI0); + } else { + /* + * Vote all bw into VIDEO path as we cannot + * differentiate to which path this has to go + */ + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; + } + + mux_axi_vote->axi_path[0].transac_type = + CAM_AXI_TRANSACTION_WRITE; + mux_axi_vote->axi_path[0].camnoc_bw = + bw_update->camnoc_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ib_bw = + bw_update->external_bw_bytes; + /* Make ddr bw same as mnoc bw */ + mux_axi_vote->axi_path[0].ddr_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].ddr_ib_bw = + bw_update->external_bw_bytes; + + top_priv->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + + if (mux_axi_vote->num_paths == 1) { + if (mux_axi_vote->axi_path[0].path_data_type == + CAM_AXI_PATH_DATA_IFE_VID) + vid_exists = true; + else if ((mux_axi_vote->axi_path[0].path_data_type >= + CAM_AXI_PATH_DATA_IFE_RDI0) && + (mux_axi_vote->axi_path[0].path_data_type <= + CAM_AXI_PATH_DATA_IFE_RDI3)) + rdi_exists = true; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(top_priv, false); + } + + return rc; +} + +static int cam_vfe_top_bw_control( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bw_control_args *bw_ctrl = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args; + res = bw_ctrl->node_res; + + if (!res || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + top_priv->axi_vote_control[i] = bw_ctrl->action; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(top_priv, true); + } + + return rc; +} + +static int cam_vfe_top_mux_get_reg_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + return cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_REG_UPDATE, cmd_args, arg_size); + + return -EINVAL; +} + +int cam_vfe_top_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv = device_priv; + + top_priv->hw_clk_rate = 0; + + return 0; +} + +int cam_vfe_top_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_top_ver2_reg_offset_common *reg_common = NULL; + uint32_t *reset_reg_args = reset_core_args; + uint32_t reset_reg_val; + + if (!top_priv || !reset_reg_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + switch (*reset_reg_args) { + case CAM_VFE_HW_RESET_HW_AND_REG: + reset_reg_val = CAM_VFE_HW_RESET_HW_AND_REG_VAL; + break; + default: + reset_reg_val = CAM_VFE_HW_RESET_HW_VAL; + break; + } + + CAM_DBG(CAM_ISP, "reset reg value: %x", reset_reg_val); + soc_info = top_priv->common_data.soc_info; + reg_common = top_priv->common_data.common_reg; + + /* Mask All the IRQs except RESET */ + cam_io_w_mb((1 << 31), + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + 0x5C); + + /* Reset HW */ + cam_io_w_mb(reset_reg_val, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + reg_common->global_reset_cmd); + + CAM_DBG(CAM_ISP, "Reset HW exit"); + return 0; +} + +int cam_vfe_top_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_vfe_acquire_args *args; + struct cam_vfe_hw_vfe_in_acquire_args *acquire_args; + uint32_t i; + int rc = -EINVAL; + + if (!device_priv || !reserve_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + args = (struct cam_vfe_acquire_args *)reserve_args; + acquire_args = &args->vfe_in; + + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == acquire_args->res_id && + top_priv->mux_rsrc[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { + rc = cam_vfe_camif_ver2_acquire_resource( + &top_priv->mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id == + CAM_ISP_HW_VFE_IN_PDLIB) { + rc = cam_vfe_camif_lite_ver2_acquire_resource( + &top_priv->mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { + rc = cam_vfe_fe_ver1_acquire_resource( + &top_priv->mux_rsrc[i], + args); + if (rc) + break; + } + + top_priv->mux_rsrc[i].cdm_ops = acquire_args->cdm_ops; + top_priv->mux_rsrc[i].tasklet_info = args->tasklet; + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + acquire_args->rsrc_node = + &top_priv->mux_rsrc[i]; + + rc = 0; + break; + } + } + + return rc; + +} + +int cam_vfe_top_release(void *device_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_isp_resource_node *mux_res; + + if (!device_priv || !release_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)release_args; + + CAM_DBG(CAM_ISP, "Resource in state %d", mux_res->res_state); + if (mux_res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Resource in Invalid res_state :%d", + mux_res->res_state); + return -EINVAL; + } + mux_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +int cam_vfe_top_start(void *device_priv, + void *start_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + + if (!device_priv || !start_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)start_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) { + rc = cam_vfe_top_set_hw_clk_rate(top_priv); + if (rc) { + CAM_ERR(CAM_ISP, + "set_hw_clk_rate failed, rc=%d", rc); + return rc; + } + + rc = cam_vfe_top_set_axi_bw_vote(top_priv, true); + if (rc) { + CAM_ERR(CAM_ISP, + "set_axi_bw_vote failed, rc=%d", rc); + return rc; + } + + if (mux_res->start) { + rc = mux_res->start(mux_res); + } else { + CAM_ERR(CAM_ISP, + "Invalid res id:%d", mux_res->res_id); + rc = -EINVAL; + } + } else { + CAM_ERR(CAM_ISP, "VFE HW not powered up"); + rc = -EPERM; + } + + return rc; +} + +int cam_vfe_top_stop(void *device_priv, + void *stop_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + if (!device_priv || !stop_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)stop_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if ((mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || + (mux_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) || + (mux_res->res_id == CAM_ISP_HW_VFE_IN_RD) || + ((mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && + (mux_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3))) { + rc = mux_res->stop(mux_res); + } else { + CAM_ERR(CAM_ISP, "Invalid res id:%d", mux_res->res_id); + return -EINVAL; + } + + if (!rc) { + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == mux_res->res_id) { + top_priv->req_clk_rate[i] = 0; + top_priv->req_clk_rate[i] = 0; + top_priv->req_axi_vote[i].axi_path[0].camnoc_bw + = 0; + top_priv->req_axi_vote[i].axi_path[0].mnoc_ab_bw + = 0; + top_priv->req_axi_vote[i].axi_path[0].mnoc_ib_bw + = 0; + top_priv->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_EXCLUDE; + break; + } + } + } + + return rc; +} + +int cam_vfe_top_read(void *device_priv, + void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_write(void *device_priv, + void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_vfe_top_ver2_priv *top_priv; + + if (!device_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Error! Invalid arguments"); + return -EINVAL; + } + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + rc = cam_vfe_top_mux_get_base(top_priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + rc = cam_vfe_top_clock_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_top_fs_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE: + rc = cam_vfe_top_bw_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + rc = cam_vfe_top_bw_update_v2(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_CONTROL: + rc = cam_vfe_top_bw_control(top_priv, cmd_args, arg_size); + break; + default: + rc = -EINVAL; + CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); + break; + } + + return rc; +} + +int cam_vfe_top_ver2_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top_ptr) +{ + int i, j, rc = 0; + struct cam_vfe_top_ver2_priv *top_priv = NULL; + struct cam_vfe_top_ver2_hw_info *ver2_hw_info = top_hw_info; + struct cam_vfe_top *vfe_top; + + vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL); + if (!vfe_top) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for vfe_top"); + rc = -ENOMEM; + goto end; + } + + top_priv = kzalloc(sizeof(struct cam_vfe_top_ver2_priv), + GFP_KERNEL); + if (!top_priv) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for vfe_top_priv"); + rc = -ENOMEM; + goto free_vfe_top; + } + vfe_top->top_priv = top_priv; + top_priv->hw_clk_rate = 0; + + for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN; + top_priv->mux_rsrc[i].hw_intf = hw_intf; + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + top_priv->req_clk_rate[i] = 0; + + if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_CAMIF; + + rc = cam_vfe_camif_ver2_init(hw_intf, soc_info, + &ver2_hw_info->camif_hw_info, + &top_priv->mux_rsrc[i], vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_CAMIF_LITE_VER_2_0) { + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_PDLIB; + + rc = cam_vfe_camif_lite_ver2_init(hw_intf, soc_info, + &ver2_hw_info->camif_lite_hw_info, + &top_priv->mux_rsrc[i], vfe_irq_controller); + + if (rc) + goto deinit_resources; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_RDI_VER_1_0) { + /* set the RDI resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RDI0 + j++; + + rc = cam_vfe_rdi_ver2_init(hw_intf, soc_info, + &ver2_hw_info->rdi_hw_info, + &top_priv->mux_rsrc[i], vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + /* set the RD resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RD; + + rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, + &ver2_hw_info->fe_hw_info, + &top_priv->mux_rsrc[i]); + if (rc) + goto deinit_resources; + } else { + CAM_WARN(CAM_ISP, "Invalid mux type: %u", + ver2_hw_info->mux_type[i]); + } + } + + vfe_top->hw_ops.get_hw_caps = cam_vfe_top_get_hw_caps; + vfe_top->hw_ops.init = cam_vfe_top_init_hw; + vfe_top->hw_ops.reset = cam_vfe_top_reset; + vfe_top->hw_ops.reserve = cam_vfe_top_reserve; + vfe_top->hw_ops.release = cam_vfe_top_release; + vfe_top->hw_ops.start = cam_vfe_top_start; + vfe_top->hw_ops.stop = cam_vfe_top_stop; + vfe_top->hw_ops.read = cam_vfe_top_read; + vfe_top->hw_ops.write = cam_vfe_top_write; + vfe_top->hw_ops.process_cmd = cam_vfe_top_process_cmd; + *vfe_top_ptr = vfe_top; + + top_priv->common_data.soc_info = soc_info; + top_priv->common_data.hw_intf = hw_intf; + top_priv->common_data.common_reg = ver2_hw_info->common_reg; + + return rc; + +deinit_resources: + for (--i; i >= 0; i--) { + if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { + if (cam_vfe_camif_ver2_deinit(&top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif Deinit failed"); + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_CAMIF_LITE_VER_2_0) { + if (cam_vfe_camif_lite_ver2_deinit( + &top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif lite deinit failed"); + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + if (cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "VFE FE deinit failed"); + } else { + if (cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "RDI Deinit failed"); + } + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + } + kfree(vfe_top->top_priv); + +free_vfe_top: + kfree(vfe_top); +end: + return rc; +} + +int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top_ptr) +{ + int i, rc = 0; + struct cam_vfe_top_ver2_priv *top_priv = NULL; + struct cam_vfe_top *vfe_top; + + if (!vfe_top_ptr) { + CAM_ERR(CAM_ISP, "Error! Invalid input"); + return -EINVAL; + } + + vfe_top = *vfe_top_ptr; + if (!vfe_top) { + CAM_ERR(CAM_ISP, "Error! vfe_top NULL"); + return -ENODEV; + } + + top_priv = vfe_top->top_priv; + if (!top_priv) { + CAM_ERR(CAM_ISP, "Error! vfe_top_priv NULL"); + rc = -ENODEV; + goto free_vfe_top; + } + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_CAMIF_VER_2_0) { + rc = cam_vfe_camif_ver2_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } else if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_CAMIF_LITE_VER_2_0) { + rc = cam_vfe_camif_lite_ver2_deinit( + &top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, + "Camif lite deinit failed rc=%d", rc); + } else if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_RDI_VER_1_0) { + rc = cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "RDI deinit failed rc=%d", rc); + } else if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_IN_RD_VER_1_0) { + rc = cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } + } + kfree(vfe_top->top_priv); + +free_vfe_top: + kfree(vfe_top); + *vfe_top_ptr = NULL; + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h new file mode 100644 index 000000000000..82e30b4285a5 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_VER2_H_ +#define _CAM_VFE_TOP_VER2_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_rdi.h" +#include "cam_vfe_fe_ver1.h" + +#define CAM_VFE_TOP_VER2_MUX_MAX 6 + +enum cam_vfe_top_ver2_module_type { + CAM_VFE_TOP_VER2_MODULE_LENS, + CAM_VFE_TOP_VER2_MODULE_STATS, + CAM_VFE_TOP_VER2_MODULE_COLOR, + CAM_VFE_TOP_VER2_MODULE_ZOOM, + CAM_VFE_TOP_VER2_MODULE_MAX, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl { + uint32_t reset; + uint32_t cgc_ovd; + uint32_t enable; +}; + +struct cam_vfe_top_ver2_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t lens_feature; + uint32_t stats_feature; + uint32_t color_feature; + uint32_t zoom_feature; + uint32_t global_reset_cmd; + struct cam_vfe_top_ver2_reg_offset_module_ctrl + *module_ctrl[CAM_VFE_TOP_VER2_MODULE_MAX]; + uint32_t bus_cgc_ovd; + uint32_t core_cfg; + uint32_t three_D_cfg; + uint32_t violation_status; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_top_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_ver2_hw_info camif_hw_info; + struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; + struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; + struct cam_vfe_fe_ver1_hw_info fe_hw_info; + uint32_t mux_type[CAM_VFE_TOP_VER2_MUX_MAX]; +}; + +int cam_vfe_top_ver2_init(struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top_ptr); + +int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top); + +#endif /* _CAM_VFE_TOP_VER2_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c new file mode 100644 index 000000000000..578b0771821f --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -0,0 +1,1101 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_io_util.h" +#include "cam_cdm_util.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver3.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_vfe_soc.h" + +#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00000003 +#define CAM_VFE_HW_RESET_HW_VAL 0x007F0000 +#define CAM_VFE_LITE_HW_RESET_AND_REG_VAL 0x00000002 +#define CAM_VFE_LITE_HW_RESET_HW_VAL 0x0000003D +#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 3 + +struct cam_vfe_top_ver3_common_data { + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *hw_intf; + struct cam_vfe_top_ver3_reg_offset_common *common_reg; +}; + +struct cam_vfe_top_ver3_priv { + struct cam_vfe_top_ver3_common_data common_data; + struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER3_MUX_MAX]; + unsigned long hw_clk_rate; + struct cam_axi_vote applied_axi_vote; + struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER3_MUX_MAX]; + unsigned long req_clk_rate[CAM_VFE_TOP_VER3_MUX_MAX]; + struct cam_axi_vote last_vote[CAM_VFE_TOP_VER3_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; + uint32_t last_counter; + uint64_t total_bw_applied; + enum cam_vfe_bw_control_action + axi_vote_control[CAM_VFE_TOP_VER3_MUX_MAX]; +}; + +static int cam_vfe_top_ver3_mux_get_base(struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t mem_base = 0; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Error, Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res || !top_priv || + !top_priv->common_data.soc_info) { + CAM_ERR(CAM_ISP, "Error, Invalid args"); + return -EINVAL; + } + + cdm_util_ops = + (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_changebase(); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE( + top_priv->common_data.soc_info, VFE_CORE_BASE_IDX); + CAM_DBG(CAM_ISP, "core %d mem_base 0x%x", + top_priv->common_data.soc_info->index, mem_base); + + cdm_util_ops->cdm_write_changebase( + cdm_args->cmd.cmd_buf_addr, mem_base); + cdm_args->cmd.used_bytes = (size * 4); + + return 0; +} + +static int cam_vfe_top_ver3_set_hw_clk_rate( + struct cam_vfe_top_ver3_priv *top_priv) +{ + struct cam_hw_soc_info *soc_info = NULL; + int i, rc = 0; + unsigned long max_clk_rate = 0; + + soc_info = top_priv->common_data.soc_info; + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + if (top_priv->req_clk_rate[i] > max_clk_rate) + max_clk_rate = top_priv->req_clk_rate[i]; + } + if (max_clk_rate == top_priv->hw_clk_rate) + return 0; + + CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%llu", + soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, max_clk_rate); + + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); + + if (!rc) + top_priv->hw_clk_rate = max_clk_rate; + else + CAM_ERR(CAM_ISP, "Set Clock rate failed, rc=%d", rc); + + return rc; +} + +static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction( + struct cam_vfe_top_ver3_priv *top_priv, + uint64_t *to_be_applied_bw) +{ + uint32_t i, j; + int vote_idx = -1; + uint64_t max_bw = 0; + uint64_t total_bw; + struct cam_axi_vote *curr_l_vote; + + for (i = 0; i < (CAM_VFE_TOP_VER3_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { + total_bw = 0; + curr_l_vote = &top_priv->last_vote[i]; + for (j = 0; j < curr_l_vote->num_paths; j++) { + if (total_bw > + (U64_MAX - + curr_l_vote->axi_path[j].camnoc_bw)) { + CAM_ERR(CAM_ISP, "Overflow at idx: %d", j); + return NULL; + } + + total_bw += curr_l_vote->axi_path[j].camnoc_bw; + } + + if (total_bw > max_bw) { + vote_idx = i; + max_bw = total_bw; + } + } + + if (vote_idx < 0) + return NULL; + + *to_be_applied_bw = max_bw; + + return &top_priv->last_vote[vote_idx]; +} + +static int cam_vfe_top_ver3_set_axi_bw_vote( + struct cam_vfe_top_ver3_priv *top_priv, + bool start_stop) +{ + struct cam_axi_vote agg_vote = {0}; + struct cam_axi_vote *to_be_applied_axi_vote = NULL; + int rc = 0; + uint32_t i; + uint32_t num_paths = 0; + uint64_t total_bw_new_vote = 0; + bool bw_unchanged = true; + struct cam_hw_soc_info *soc_info = + top_priv->common_data.soc_info; + struct cam_vfe_soc_private *soc_private = + soc_info->soc_private; + bool apply_bw_update = false; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + if (top_priv->axi_vote_control[i] == + CAM_VFE_BW_CONTROL_INCLUDE) { + if (num_paths + + top_priv->req_axi_vote[i].num_paths > + CAM_CPAS_MAX_PATHS_PER_CLIENT) { + CAM_ERR(CAM_ISP, + "Required paths(%d) more than max(%d)", + num_paths + + top_priv->req_axi_vote[i].num_paths, + CAM_CPAS_MAX_PATHS_PER_CLIENT); + return -EINVAL; + } + + memcpy(&agg_vote.axi_path[num_paths], + &top_priv->req_axi_vote[i].axi_path[0], + top_priv->req_axi_vote[i].num_paths * + sizeof( + struct cam_axi_per_path_bw_vote)); + num_paths += top_priv->req_axi_vote[i].num_paths; + } + } + + agg_vote.num_paths = num_paths; + + for (i = 0; i < agg_vote.num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]", + top_priv->common_data.hw_intf->hw_idx, + top_priv->last_counter, + cam_cpas_axi_util_path_type_to_string( + agg_vote.axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + agg_vote.axi_path[i].transac_type), + agg_vote.axi_path[i].camnoc_bw, + agg_vote.axi_path[i].mnoc_ab_bw, + agg_vote.axi_path[i].mnoc_ib_bw); + + total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; + } + + memcpy(&top_priv->last_vote[top_priv->last_counter], &agg_vote, + sizeof(struct cam_axi_vote)); + top_priv->last_counter = (top_priv->last_counter + 1) % + (CAM_VFE_TOP_VER3_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); + + if ((agg_vote.num_paths != top_priv->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_priv->total_bw_applied)) + bw_unchanged = false; + + CAM_DBG(CAM_PERF, + "ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d", + top_priv->common_data.hw_intf->hw_idx, + top_priv->total_bw_applied, total_bw_new_vote, + bw_unchanged, start_stop); + + if (bw_unchanged) { + CAM_DBG(CAM_ISP, "BW config unchanged"); + return 0; + } + + if (start_stop) { + /* need to vote current request immediately */ + to_be_applied_axi_vote = &agg_vote; + /* Reset everything, we can start afresh */ + memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * + (CAM_VFE_TOP_VER3_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); + top_priv->last_counter = 0; + top_priv->last_vote[top_priv->last_counter] = agg_vote; + top_priv->last_counter = (top_priv->last_counter + 1) % + (CAM_VFE_TOP_VER3_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); + } else { + /* + * Find max bw request in last few frames. This will the bw + * that we want to vote to CPAS now. + */ + to_be_applied_axi_vote = + cam_vfe_top_delay_bw_reduction(top_priv, + &total_bw_new_vote); + if (!to_be_applied_axi_vote) { + CAM_ERR(CAM_ISP, "to_be_applied_axi_vote is NULL"); + return -EINVAL; + } + } + + for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]", + top_priv->common_data.hw_intf->hw_idx, + cam_cpas_axi_util_path_type_to_string( + to_be_applied_axi_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + to_be_applied_axi_vote->axi_path[i].transac_type), + to_be_applied_axi_vote->axi_path[i].camnoc_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw); + } + + if ((to_be_applied_axi_vote->num_paths != + top_priv->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_priv->total_bw_applied)) + apply_bw_update = true; + + CAM_DBG(CAM_PERF, + "ife[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d", + top_priv->common_data.hw_intf->hw_idx, + top_priv->total_bw_applied, total_bw_new_vote, + apply_bw_update, start_stop); + + if (apply_bw_update) { + rc = cam_cpas_update_axi_vote(soc_private->cpas_handle, + to_be_applied_axi_vote); + if (!rc) { + memcpy(&top_priv->applied_axi_vote, + to_be_applied_axi_vote, + sizeof(struct cam_axi_vote)); + top_priv->total_bw_applied = total_bw_new_vote; + } else { + CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); + } + } + + return rc; +} + +static int cam_vfe_top_fs_update( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_fe_update_args *cmd_update = cmd_args; + + if (cmd_update->node_res->process_cmd) + return cmd_update->node_res->process_cmd(cmd_update->node_res, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, cmd_args, arg_size); + + return 0; +} + +static int cam_vfe_top_ver3_clock_update( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_clock_update_args *clk_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + clk_update = + (struct cam_vfe_clock_update_args *)cmd_args; + res = clk_update->node_res; + + if (!res || !res->hw_intf->hw_priv) { + CAM_ERR(CAM_ISP, "Invalid input res %pK", res); + return -EINVAL; + } + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + top_priv->req_clk_rate[i] = clk_update->clk_rate; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_DBG(CAM_ISP, + "VFE:%d Not ready to set clocks yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else + rc = cam_vfe_top_ver3_set_hw_clk_rate(top_priv); + + return rc; +} + +static int cam_vfe_top_ver3_bw_update_v2( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bw_update_args_v2 *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_update = (struct cam_vfe_bw_update_args_v2 *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + memcpy(&top_priv->req_axi_vote[i], &bw_update->isp_vote, + sizeof(struct cam_axi_vote)); + top_priv->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, false); + } + + return rc; +} + +static int cam_vfe_top_ver3_bw_update( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bw_update_args *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + struct cam_axi_vote *mux_axi_vote; + bool vid_exists = false; + bool rdi_exists = false; + + bw_update = (struct cam_vfe_bw_update_args *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + CAM_DBG(CAM_ISP, "res_id=%d, BW=[%lld %lld]", + res->res_id, bw_update->camnoc_bw_bytes, + bw_update->external_bw_bytes); + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + mux_axi_vote = &top_priv->req_axi_vote[i]; + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + mux_axi_vote->num_paths = 1; + if ((res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && + (res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) { + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_RDI0 + + (res->res_id - CAM_ISP_HW_VFE_IN_RDI0); + } else { + /* + * Vote all bw into VIDEO path as we cannot + * differentiate to which path this has to go + */ + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; + } + + mux_axi_vote->axi_path[0].transac_type = + CAM_AXI_TRANSACTION_WRITE; + mux_axi_vote->axi_path[0].camnoc_bw = + bw_update->camnoc_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ib_bw = + bw_update->external_bw_bytes; + /* Make ddr bw same as mnoc bw */ + mux_axi_vote->axi_path[0].ddr_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].ddr_ib_bw = + bw_update->external_bw_bytes; + + top_priv->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + + if (mux_axi_vote->num_paths == 1) { + if (mux_axi_vote->axi_path[0].path_data_type == + CAM_AXI_PATH_DATA_IFE_VID) + vid_exists = true; + else if ((mux_axi_vote->axi_path[0].path_data_type >= + CAM_AXI_PATH_DATA_IFE_RDI0) && + (mux_axi_vote->axi_path[0].path_data_type <= + CAM_AXI_PATH_DATA_IFE_RDI3)) + rdi_exists = true; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, false); + } + + return rc; +} + +static int cam_vfe_core_config_control( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_core_config_args *core_config = cmd_args; + + if (core_config->node_res->process_cmd) + return core_config->node_res->process_cmd(core_config->node_res, + CAM_ISP_HW_CMD_CORE_CONFIG, cmd_args, arg_size); + + return -EINVAL; +} + +static int cam_vfe_top_ver3_bw_control( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bw_control_args *bw_ctrl = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args; + res = bw_ctrl->node_res; + + if (!res || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + top_priv->axi_vote_control[i] = bw_ctrl->action; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, true); + } + + return rc; +} + +static int cam_vfe_top_ver3_mux_get_reg_update( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + return cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_REG_UPDATE, cmd_args, arg_size); + + return -EINVAL; +} + +int cam_vfe_top_ver3_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_ver3_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv = device_priv; + + top_priv->hw_clk_rate = 0; + + return 0; +} + +int cam_vfe_top_ver3_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct cam_vfe_top_ver3_reg_offset_common *reg_common = NULL; + uint32_t *reset_reg_args = reset_core_args; + uint32_t reset_reg_val; + + if (!top_priv || !reset_reg_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + soc_info = top_priv->common_data.soc_info; + reg_common = top_priv->common_data.common_reg; + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + switch (*reset_reg_args) { + case CAM_VFE_HW_RESET_HW_AND_REG: + if (!soc_private->is_ife_lite) + reset_reg_val = CAM_VFE_HW_RESET_HW_AND_REG_VAL; + else + reset_reg_val = CAM_VFE_LITE_HW_RESET_AND_REG_VAL; + break; + default: + if (!soc_private->is_ife_lite) + reset_reg_val = CAM_VFE_HW_RESET_HW_VAL; + else + reset_reg_val = CAM_VFE_LITE_HW_RESET_HW_VAL; + break; + } + /* override due to hw limitation */ + if (!soc_private->is_ife_lite) + reset_reg_val = CAM_VFE_HW_RESET_HW_AND_REG_VAL; + else + reset_reg_val = CAM_VFE_LITE_HW_RESET_AND_REG_VAL; + + CAM_DBG(CAM_ISP, "reset reg value: 0x%x", reset_reg_val); + + /* Mask All the IRQs except RESET */ + if (!soc_private->is_ife_lite) + cam_io_w_mb(0x00000001, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + 0x3C); + else + cam_io_w_mb(0x00020000, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + 0x28); + + /* Reset HW */ + cam_io_w_mb(reset_reg_val, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + reg_common->global_reset_cmd); + + CAM_DBG(CAM_ISP, "Reset HW exit"); + return 0; +} + +int cam_vfe_top_ver3_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_vfe_acquire_args *args; + struct cam_vfe_hw_vfe_in_acquire_args *acquire_args; + uint32_t i; + int rc = -EINVAL; + + if (!device_priv || !reserve_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + args = (struct cam_vfe_acquire_args *)reserve_args; + acquire_args = &args->vfe_in; + + CAM_DBG(CAM_ISP, "res id %d", acquire_args->res_id); + + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == acquire_args->res_id && + top_priv->mux_rsrc[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { + rc = cam_vfe_camif_ver3_acquire_resource( + &top_priv->mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id >= CAM_ISP_HW_VFE_IN_RDI0 && + acquire_args->res_id < CAM_ISP_HW_VFE_IN_MAX) { + rc = cam_vfe_camif_lite_ver3_acquire_resource( + &top_priv->mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { + rc = cam_vfe_fe_ver1_acquire_resource( + &top_priv->mux_rsrc[i], + args); + if (rc) + break; + } + + top_priv->mux_rsrc[i].cdm_ops = acquire_args->cdm_ops; + top_priv->mux_rsrc[i].tasklet_info = args->tasklet; + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + acquire_args->rsrc_node = + &top_priv->mux_rsrc[i]; + + rc = 0; + break; + } + } + + return rc; + +} + +int cam_vfe_top_ver3_release(void *device_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_isp_resource_node *mux_res; + + if (!device_priv || !release_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)release_args; + + CAM_DBG(CAM_ISP, "Resource in state %d", mux_res->res_state); + if (mux_res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error, Resource in Invalid res_state :%d", + mux_res->res_state); + return -EINVAL; + } + mux_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +int cam_vfe_top_ver3_start(void *device_priv, + void *start_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + + if (!device_priv || !start_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)start_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) { + rc = cam_vfe_top_ver3_set_hw_clk_rate(top_priv); + if (rc) { + CAM_ERR(CAM_ISP, + "set_hw_clk_rate failed, rc=%d", rc); + return rc; + } + + rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, true); + if (rc) { + CAM_ERR(CAM_ISP, + "set_axi_bw_vote failed, rc=%d", rc); + return rc; + } + + if (mux_res->start) { + rc = mux_res->start(mux_res); + } else { + CAM_ERR(CAM_ISP, + "Invalid res id:%d", mux_res->res_id); + rc = -EINVAL; + } + } else { + CAM_ERR(CAM_ISP, "VFE HW not powered up"); + rc = -EPERM; + } + + return rc; +} + +int cam_vfe_top_ver3_stop(void *device_priv, + void *stop_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + if (!device_priv || !stop_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)stop_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if (mux_res->res_id < CAM_ISP_HW_VFE_IN_MAX) { + rc = mux_res->stop(mux_res); + } else { + CAM_ERR(CAM_ISP, "Invalid res id:%d", mux_res->res_id); + return -EINVAL; + } + + if (!rc) { + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == mux_res->res_id) { + top_priv->req_clk_rate[i] = 0; + memset(&top_priv->req_axi_vote[i], 0, + sizeof(struct cam_axi_vote)); + top_priv->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_EXCLUDE; + break; + } + } + } + + return rc; +} + +int cam_vfe_top_ver3_read(void *device_priv, + void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_ver3_write(void *device_priv, + void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_vfe_top_ver3_priv *top_priv; + + if (!device_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Error, Invalid arguments"); + return -EINVAL; + } + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + rc = cam_vfe_top_ver3_mux_get_base(top_priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_top_ver3_mux_get_reg_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + rc = cam_vfe_top_ver3_clock_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_top_fs_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE: + rc = cam_vfe_top_ver3_bw_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + rc = cam_vfe_top_ver3_bw_update_v2(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_CONTROL: + rc = cam_vfe_top_ver3_bw_control(top_priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = cam_vfe_core_config_control(top_priv, cmd_args, arg_size); + break; + default: + rc = -EINVAL; + CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type); + break; + } + + return rc; +} + +int cam_vfe_top_ver3_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top_ptr) +{ + int i, j, rc = 0; + struct cam_vfe_top_ver3_priv *top_priv = NULL; + struct cam_vfe_top_ver3_hw_info *ver3_hw_info = top_hw_info; + struct cam_vfe_top *vfe_top; + + vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL); + if (!vfe_top) { + CAM_DBG(CAM_ISP, "Error, Failed to alloc for vfe_top"); + rc = -ENOMEM; + goto end; + } + + top_priv = kzalloc(sizeof(struct cam_vfe_top_ver3_priv), + GFP_KERNEL); + if (!top_priv) { + CAM_DBG(CAM_ISP, "Error, Failed to alloc for vfe_top_priv"); + rc = -ENOMEM; + goto free_vfe_top; + } + vfe_top->top_priv = top_priv; + top_priv->hw_clk_rate = 0; + + for (i = 0, j = 0; i < CAM_VFE_TOP_VER3_MUX_MAX && + j < CAM_VFE_RDI_VER2_MAX; i++) { + top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN; + top_priv->mux_rsrc[i].hw_intf = hw_intf; + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + top_priv->req_clk_rate[i] = 0; + + if (ver3_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_3_0) { + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_CAMIF; + + rc = cam_vfe_camif_ver3_init(hw_intf, soc_info, + &ver3_hw_info->camif_hw_info, + &top_priv->mux_rsrc[i], vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_PDLIB_VER_1_0) { + /* set the PDLIB resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_PDLIB; + + rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, + &ver3_hw_info->pdlib_hw_info, + &top_priv->mux_rsrc[i], vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + /* set the RD resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RD; + + rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, + &ver3_hw_info->fe_hw_info, + &top_priv->mux_rsrc[i]); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_RDI_VER_1_0) { + /* set the RDI resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RDI0 + j; + + rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, + ver3_hw_info->rdi_hw_info[j++], + &top_priv->mux_rsrc[i], vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_LCR_VER_1_0) { + /* set the LCR resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_LCR; + + rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, + &ver3_hw_info->lcr_hw_info, + &top_priv->mux_rsrc[i], vfe_irq_controller); + if (rc) + goto deinit_resources; + } else { + CAM_WARN(CAM_ISP, "Invalid mux type: %u", + ver3_hw_info->mux_type[i]); + } + } + + vfe_top->hw_ops.get_hw_caps = cam_vfe_top_ver3_get_hw_caps; + vfe_top->hw_ops.init = cam_vfe_top_ver3_init_hw; + vfe_top->hw_ops.reset = cam_vfe_top_ver3_reset; + vfe_top->hw_ops.reserve = cam_vfe_top_ver3_reserve; + vfe_top->hw_ops.release = cam_vfe_top_ver3_release; + vfe_top->hw_ops.start = cam_vfe_top_ver3_start; + vfe_top->hw_ops.stop = cam_vfe_top_ver3_stop; + vfe_top->hw_ops.read = cam_vfe_top_ver3_read; + vfe_top->hw_ops.write = cam_vfe_top_ver3_write; + vfe_top->hw_ops.process_cmd = cam_vfe_top_ver3_process_cmd; + *vfe_top_ptr = vfe_top; + + top_priv->common_data.soc_info = soc_info; + top_priv->common_data.hw_intf = hw_intf; + top_priv->common_data.common_reg = ver3_hw_info->common_reg; + + return rc; + +deinit_resources: + for (--i; i >= 0; i--) { + if (ver3_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_3_0) { + if (cam_vfe_camif_ver3_deinit(&top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif Deinit failed"); + } else if (ver3_hw_info->mux_type[i] == CAM_VFE_IN_RD_VER_1_0) { + if (cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif fe Deinit failed"); + } else { + if (cam_vfe_camif_lite_ver3_deinit( + &top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, + "Camif lite res id %d Deinit failed", + top_priv->mux_rsrc[i].res_id); + } + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + } + + kfree(vfe_top->top_priv); +free_vfe_top: + kfree(vfe_top); +end: + return rc; +} + +int cam_vfe_top_ver3_deinit(struct cam_vfe_top **vfe_top_ptr) +{ + int i, rc = 0; + struct cam_vfe_top_ver3_priv *top_priv = NULL; + struct cam_vfe_top *vfe_top; + + if (!vfe_top_ptr) { + CAM_ERR(CAM_ISP, "Error, Invalid input"); + return -EINVAL; + } + + vfe_top = *vfe_top_ptr; + if (!vfe_top) { + CAM_ERR(CAM_ISP, "Error, vfe_top NULL"); + return -ENODEV; + } + + top_priv = vfe_top->top_priv; + if (!top_priv) { + CAM_ERR(CAM_ISP, "Error, vfe_top_priv NULL"); + rc = -ENODEV; + goto free_vfe_top; + } + + for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_CAMIF_VER_3_0) { + rc = cam_vfe_camif_ver3_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } else if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_IN_RD_VER_1_0) { + rc = cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } else { + rc = cam_vfe_camif_lite_ver3_deinit( + &top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, + "Camif lite res id %d Deinit failed", + top_priv->mux_rsrc[i].res_id); + } + } + + kfree(vfe_top->top_priv); + +free_vfe_top: + kfree(vfe_top); + *vfe_top_ptr = NULL; + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h new file mode 100644 index 000000000000..1ae8e5d54a4d --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_VER3_H_ +#define _CAM_VFE_TOP_VER3_H_ + +#include "cam_vfe_camif_ver3.h" +#include "cam_vfe_camif_lite_ver3.h" +#include "cam_vfe_fe_ver1.h" + +#define CAM_VFE_TOP_VER3_MUX_MAX 6 + +#define CAM_SHIFT_TOP_CORE_CFG_MUXSEL_PDAF 31 +#define CAM_SHIFT_TOP_CORE_CFG_VID_DS16_R2PD 30 +#define CAM_SHIFT_TOP_CORE_CFG_VID_DS4_R2PD 29 +#define CAM_SHIFT_TOP_CORE_CFG_DISP_DS16_R2PD 28 +#define CAM_SHIFT_TOP_CORE_CFG_DISP_DS4_R2PD 27 +#define CAM_SHIFT_TOP_CORE_CFG_DSP_STREAMING 25 +#define CAM_SHIFT_TOP_CORE_CFG_STATS_IHIST 10 +#define CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BE 9 +#define CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BHIST 8 +#define CAM_SHIFT_TOP_CORE_CFG_INPUTMUX_PP 5 + +struct cam_vfe_top_ver3_reg_offset_common { + uint32_t hw_version; + uint32_t titan_version; + uint32_t hw_capability; + uint32_t lens_feature; + uint32_t stats_feature; + uint32_t color_feature; + uint32_t zoom_feature; + uint32_t global_reset_cmd; + uint32_t core_cgc_ovd_0; + uint32_t core_cgc_ovd_1; + uint32_t ahb_cgc_ovd; + uint32_t noc_cgc_ovd; + uint32_t bus_cgc_ovd; + uint32_t core_cfg_0; + uint32_t core_cfg_1; + uint32_t reg_update_cmd; + uint32_t trigger_cdm_events; + uint32_t violation_status; + uint32_t sbi_frame_idx; + uint32_t dsp_status; + uint32_t diag_config; + uint32_t diag_sensor_status_0; + uint32_t diag_sensor_status_1; + uint32_t bus_overflow_status; +}; + +struct cam_vfe_camif_common_cfg { + uint32_t vid_ds16_r2pd; + uint32_t vid_ds4_r2pd; + uint32_t disp_ds16_r2pd; + uint32_t disp_ds4_r2pd; + uint32_t dsp_streaming_tap_point; + uint32_t ihist_src_sel; + uint32_t hdr_be_src_sel; + uint32_t hdr_bhist_src_sel; + uint32_t input_mux_sel_pdaf; + uint32_t input_mux_sel_pp; +}; + +struct cam_vfe_top_ver3_hw_info { + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_ver3_hw_info camif_hw_info; + struct cam_vfe_camif_lite_ver3_hw_info pdlib_hw_info; + struct cam_vfe_camif_lite_ver3_hw_info + *rdi_hw_info[CAM_VFE_RDI_VER2_MAX]; + struct cam_vfe_camif_lite_ver3_hw_info lcr_hw_info; + struct cam_vfe_fe_ver1_hw_info fe_hw_info; + uint32_t mux_type[CAM_VFE_TOP_VER3_MUX_MAX]; +}; + +int cam_vfe_top_ver3_init(struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top); + +int cam_vfe_top_ver3_deinit(struct cam_vfe_top **vfe_top); + +#endif /* _CAM_VFE_TOP_VER3_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h new file mode 100644 index 000000000000..932cab858a70 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_H_ +#define _CAM_VFE_TOP_H_ + +#include "cam_hw_intf.h" +#include "cam_isp_hw.h" + +#define CAM_VFE_TOP_VER_1_0 0x100000 +#define CAM_VFE_TOP_VER_2_0 0x200000 +#define CAM_VFE_TOP_VER_3_0 0x300000 + +#define CAM_VFE_CAMIF_VER_1_0 0x10 +#define CAM_VFE_CAMIF_VER_2_0 0x20 +#define CAM_VFE_CAMIF_VER_3_0 0x30 + +#define CAM_VFE_CAMIF_LITE_VER_2_0 0x02 + +#define CAM_VFE_RDI_VER_1_0 0x1000 +#define CAM_VFE_IN_RD_VER_1_0 0x2000 + +#define CAM_VFE_LCR_VER_1_0 0x100 +#define CAM_VFE_PDLIB_VER_1_0 0x10000 + +/* + * Debug values for camif module + */ +#define CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS BIT(0) +#define CAMIF_DEBUG_ENABLE_REG_DUMP BIT(1) +#define CAM_VFE_CAMIF_EVT_MAX 256 + +struct cam_vfe_top { + void *top_priv; + struct cam_hw_ops hw_ops; +}; + +int cam_vfe_top_init(uint32_t top_version, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top); + +int cam_vfe_top_deinit(uint32_t top_version, + struct cam_vfe_top **vfe_top); + +#endif /* _CAM_VFE_TOP_H_*/ diff --git a/drivers/cam_jpeg/Makefile b/drivers/cam_jpeg/Makefile new file mode 100644 index 000000000000..3b9bbdbedb7b --- /dev/null +++ b/drivers/cam_jpeg/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include/ + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg_dev.o cam_jpeg_context.o diff --git a/drivers/cam_jpeg/cam_jpeg_context.c b/drivers/cam_jpeg/cam_jpeg_context.c new file mode 100644 index 000000000000..e28aae21e7d9 --- /dev/null +++ b/drivers/cam_jpeg/cam_jpeg_context.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_mem_mgr.h" +#include "cam_jpeg_context.h" +#include "cam_context_utils.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" + +static const char jpeg_dev_name[] = "jpeg"; + +static int cam_jpeg_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info) +{ + + struct cam_context *ctx = (struct cam_context *)data; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_temp = NULL; + struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL; + int rc = 0; + int closest_port; + bool b_mem_found = false; + + + if (!ctx) { + CAM_ERR(CAM_JPEG, "Invalid ctx"); + return -EINVAL; + } + + CAM_INFO(CAM_JPEG, "iommu fault for jpeg ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + pf_dbg_entry = &(req->pf_data); + closest_port = -1; + CAM_INFO(CAM_JPEG, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &b_mem_found); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to dump pf info"); + + if (b_mem_found) + CAM_ERR(CAM_JPEG, "Found page fault in req %lld %d", + req->request_id, rc); + } + return rc; +} + +static int __cam_jpeg_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_JPEG, "Unable to Acquire device %d", rc); + else + ctx->state = CAM_CTX_ACQUIRED; + + return rc; +} + +static int __cam_jpeg_ctx_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_JPEG, "Unable to release device %d", rc); + + ctx->state = CAM_CTX_AVAILABLE; + + return rc; +} + +static int __cam_jpeg_ctx_flush_dev_in_acquired(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to flush device"); + + return rc; +} + +static int __cam_jpeg_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + return cam_context_prepare_dev_to_hw(ctx, cmd); +} + +static int __cam_jpeg_ctx_handle_buf_done_in_acquired(void *ctx, + uint32_t evt_id, void *done) +{ + return cam_context_buf_done_from_hw(ctx, done, evt_id); +} + +static int __cam_jpeg_ctx_stop_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed in Stop dev, rc=%d", rc); + return rc; + } + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_jpeg_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = { }, + .crm_ops = { }, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_jpeg_ctx_acquire_dev_in_available, + }, + .crm_ops = { }, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_jpeg_ctx_release_dev_in_acquired, + .config_dev = __cam_jpeg_ctx_config_dev_in_acquired, + .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, + .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, + }, + .crm_ops = { }, + .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, + .pagefault_ops = cam_jpeg_context_dump_active_request, + }, +}; + +int cam_jpeg_context_init(struct cam_jpeg_context *ctx, + struct cam_context *ctx_base, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) +{ + int rc; + int i; + + if (!ctx || !ctx_base) { + CAM_ERR(CAM_JPEG, "Invalid Context"); + rc = -EFAULT; + goto err; + } + + memset(ctx, 0, sizeof(*ctx)); + + ctx->base = ctx_base; + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) + ctx->req_base[i].req_priv = ctx; + + rc = cam_context_init(ctx_base, jpeg_dev_name, CAM_JPEG, ctx_id, + NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_JPEG, "Camera Context Base init failed"); + goto err; + } + + ctx_base->state_machine = cam_jpeg_ctx_state_machine; + ctx_base->ctx_priv = ctx; + +err: + return rc; +} + +int cam_jpeg_context_deinit(struct cam_jpeg_context *ctx) +{ + if (!ctx || !ctx->base) { + CAM_ERR(CAM_JPEG, "Invalid params: %pK", ctx); + return -EINVAL; + } + + cam_context_deinit(ctx->base); + + memset(ctx, 0, sizeof(*ctx)); + + return 0; +} diff --git a/drivers/cam_jpeg/cam_jpeg_context.h b/drivers/cam_jpeg/cam_jpeg_context.h new file mode 100644 index 000000000000..739dc6fd4525 --- /dev/null +++ b/drivers/cam_jpeg/cam_jpeg_context.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_CONTEXT_H_ +#define _CAM_JPEG_CONTEXT_H_ + +#include + +#include "cam_context.h" +#include "cam_jpeg_hw_mgr_intf.h" + +#define CAM_JPEG_HW_EVENT_MAX 20 + +/** + * struct cam_jpeg_context - Jpeg context + * @base: Base jpeg cam context object + * @req_base: Common request structure + */ +struct cam_jpeg_context { + struct cam_context *base; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; +}; + +/* cam jpeg context irq handling function type */ +typedef int (*cam_jpeg_hw_event_cb_func)( + struct cam_jpeg_context *ctx_jpeg, + void *evt_data); + +/** + * struct cam_jpeg_ctx_irq_ops - Function table for handling IRQ callbacks + * + * @irq_ops: Array of handle function pointers. + * + */ +struct cam_jpeg_ctx_irq_ops { + cam_jpeg_hw_event_cb_func irq_ops[CAM_JPEG_HW_EVENT_MAX]; +}; + +/** + * cam_jpeg_context_init() + * + * @brief: Initialization function for the JPEG context + * + * @ctx: JPEG context obj to be initialized + * @ctx_base: Context base from cam_context + * @hw_intf: JPEG hw manager interface + * @ctx_id: ID for this context + * + */ +int cam_jpeg_context_init(struct cam_jpeg_context *ctx, + struct cam_context *ctx_base, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); + +/** + * cam_jpeg_context_deinit() + * + * @brief: Deinitialize function for the JPEG context + * + * @ctx: JPEG context obj to be deinitialized + * + */ +int cam_jpeg_context_deinit(struct cam_jpeg_context *ctx); + +#endif /* __CAM_JPEG_CONTEXT_H__ */ diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c new file mode 100644 index 000000000000..0a68ce997283 --- /dev/null +++ b/drivers/cam_jpeg/cam_jpeg_dev.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "cam_node.h" +#include "cam_hw_mgr_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_jpeg_dev.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +#define CAM_JPEG_DEV_NAME "cam-jpeg" + +static struct cam_jpeg_dev g_jpeg_dev; + +static void cam_jpeg_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_JPEG, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static const struct of_device_id cam_jpeg_dt_match[] = { + { + .compatible = "qcom,cam-jpeg" + }, + { } +}; + +static int cam_jpeg_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + + mutex_lock(&g_jpeg_dev.jpeg_mutex); + g_jpeg_dev.open_cnt++; + mutex_unlock(&g_jpeg_dev.jpeg_mutex); + + return 0; +} + +static int cam_jpeg_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_node *node = v4l2_get_subdevdata(sd); + + + mutex_lock(&g_jpeg_dev.jpeg_mutex); + if (g_jpeg_dev.open_cnt <= 0) { + CAM_DBG(CAM_JPEG, "JPEG subdev is already closed"); + rc = -EINVAL; + goto end; + } + + g_jpeg_dev.open_cnt--; + + if (!node) { + CAM_ERR(CAM_JPEG, "Node ptr is NULL"); + rc = -EINVAL; + goto end; + } + + if (g_jpeg_dev.open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&g_jpeg_dev.jpeg_mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_jpeg_subdev_internal_ops = { + .close = cam_jpeg_subdev_close, + .open = cam_jpeg_subdev_open, +}; + +static int cam_jpeg_dev_remove(struct platform_device *pdev) +{ + int rc; + int i; + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_jpeg_context_deinit(&g_jpeg_dev.ctx_jpeg[i]); + if (rc) + CAM_ERR(CAM_JPEG, "JPEG context %d deinit failed %d", + i, rc); + } + + rc = cam_subdev_remove(&g_jpeg_dev.sd); + if (rc) + CAM_ERR(CAM_JPEG, "Unregister failed %d", rc); + + return rc; +} + +static int cam_jpeg_dev_probe(struct platform_device *pdev) +{ + int rc; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + int iommu_hdl = -1; + + g_jpeg_dev.sd.internal_ops = &cam_jpeg_subdev_internal_ops; + rc = cam_subdev_probe(&g_jpeg_dev.sd, pdev, CAM_JPEG_DEV_NAME, + CAM_JPEG_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_JPEG, "JPEG cam_subdev_probe failed %d", rc); + goto err; + } + node = (struct cam_node *)g_jpeg_dev.sd.token; + + rc = cam_jpeg_hw_mgr_init(pdev->dev.of_node, + (uint64_t *)&hw_mgr_intf, &iommu_hdl); + if (rc) { + CAM_ERR(CAM_JPEG, "Can not initialize JPEG HWmanager %d", rc); + goto unregister; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_jpeg_context_init(&g_jpeg_dev.ctx_jpeg[i], + &g_jpeg_dev.ctx[i], + &node->hw_mgr_intf, + i); + if (rc) { + CAM_ERR(CAM_JPEG, "JPEG context init failed %d %d", + i, rc); + goto ctx_init_fail; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_jpeg_dev.ctx, CAM_CTX_MAX, + CAM_JPEG_DEV_NAME); + if (rc) { + CAM_ERR(CAM_JPEG, "JPEG node init failed %d", rc); + goto ctx_init_fail; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_jpeg_dev_iommu_fault_handler, node); + + mutex_init(&g_jpeg_dev.jpeg_mutex); + + CAM_INFO(CAM_JPEG, "Camera JPEG probe complete"); + + return rc; + +ctx_init_fail: + for (--i; i >= 0; i--) + if (cam_jpeg_context_deinit(&g_jpeg_dev.ctx_jpeg[i])) + CAM_ERR(CAM_JPEG, "deinit fail %d %d", i, rc); +unregister: + if (cam_subdev_remove(&g_jpeg_dev.sd)) + CAM_ERR(CAM_JPEG, "remove fail %d", rc); +err: + return rc; +} + +static struct platform_driver jpeg_driver = { + .probe = cam_jpeg_dev_probe, + .remove = cam_jpeg_dev_remove, + .driver = { + .name = "cam_jpeg", + .owner = THIS_MODULE, + .of_match_table = cam_jpeg_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_jpeg_dev_init_module(void) +{ + return platform_driver_register(&jpeg_driver); +} + +static void __exit cam_jpeg_dev_exit_module(void) +{ + platform_driver_unregister(&jpeg_driver); +} + +module_init(cam_jpeg_dev_init_module); +module_exit(cam_jpeg_dev_exit_module); +MODULE_DESCRIPTION("MSM JPEG driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_jpeg/cam_jpeg_dev.h b/drivers/cam_jpeg/cam_jpeg_dev.h new file mode 100644 index 000000000000..4961527de1a7 --- /dev/null +++ b/drivers/cam_jpeg/cam_jpeg_dev.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_DEV_H_ +#define _CAM_JPEG_DEV_H_ + +#include "cam_subdev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_context.h" +#include "cam_jpeg_context.h" + +/** + * struct cam_jpeg_dev - Camera JPEG V4l2 device node + * + * @sd: Commone camera subdevice node + * @node: Pointer to jpeg subdevice + * @ctx: JPEG base context storage + * @ctx_jpeg: JPEG private context storage + * @jpeg_mutex: Jpeg dev mutex + * @open_cnt: Open device count + */ +struct cam_jpeg_dev { + struct cam_subdev sd; + struct cam_node *node; + struct cam_context ctx[CAM_CTX_MAX]; + struct cam_jpeg_context ctx_jpeg[CAM_CTX_MAX]; + struct mutex jpeg_mutex; + int32_t open_cnt; +}; +#endif /* __CAM_JPEG_DEV_H__ */ diff --git a/drivers/cam_jpeg/jpeg_hw/Makefile b/drivers/cam_jpeg/jpeg_hw/Makefile new file mode 100644 index 000000000000..f189bd13a244 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/ + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_enc_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_dma_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg_hw_mgr.o diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c new file mode 100644 index 000000000000..b395bc396c70 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -0,0 +1,1602 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_packet_util.h" +#include "cam_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_jpeg_hw_mgr.h" +#include "cam_smmu_api.h" +#include "cam_mem_mgr.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "cam_cdm_intf_api.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" + +#define CAM_JPEG_HW_ENTRIES_MAX 20 +#define CAM_JPEG_CHBASE 0 +#define CAM_JPEG_CFG 1 +#define CAM_JPEG_PARAM 2 + +static struct cam_jpeg_hw_mgr g_jpeg_hw_mgr; + +static int32_t cam_jpeg_hw_mgr_cb(uint32_t irq_status, + int32_t result_size, void *data); +static int cam_jpeg_mgr_process_cmd(void *priv, void *data); + +static int cam_jpeg_mgr_process_irq(void *priv, void *data) +{ + int rc = 0; + int mem_hdl = 0; + struct cam_jpeg_process_irq_work_data_t *task_data; + struct cam_jpeg_hw_mgr *hw_mgr; + int32_t i; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + struct cam_hw_done_event_data buf_data; + struct cam_jpeg_set_irq_cb irq_cb; + uintptr_t dev_type = 0; + uintptr_t kaddr; + uint32_t *cmd_buf_kaddr; + size_t cmd_buf_len; + struct cam_jpeg_config_inout_param_info *p_params; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + struct crm_workq_task *task; + struct cam_jpeg_process_frame_work_data_t *wq_task_data; + + if (!data || !priv) { + CAM_ERR(CAM_JPEG, "Invalid data"); + return -EINVAL; + } + + task_data = data; + hw_mgr = &g_jpeg_hw_mgr; + + ctx_data = (struct cam_jpeg_hw_ctx_data *)task_data->data; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + mutex_lock(&g_jpeg_hw_mgr.hw_mgr_mutex); + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + + if (hw_mgr->device_in_use[dev_type][0] == false || + p_cfg_req == NULL) { + CAM_ERR(CAM_JPEG, "irq for old request %d", rc); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + return -EINVAL; + } + + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = NULL; + irq_cb.b_set_cb = false; + if (!hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + CAM_ERR(CAM_JPEG, "process_cmd null "); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + return -EINVAL; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) { + CAM_ERR(CAM_JPEG, "CMD_SET_IRQ_CB failed %d", rc); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + return rc; + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.deinit( + hw_mgr->devices[dev_type][0]->hw_priv, NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to Deinit %lu HW", dev_type); + } + + hw_mgr->device_in_use[dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + + task = cam_req_mgr_workq_get_task( + g_jpeg_hw_mgr.work_process_frame); + if (!task) { + CAM_ERR(CAM_JPEG, "no empty task"); + return -EINVAL; + } + + wq_task_data = (struct cam_jpeg_process_frame_work_data_t *) + task->payload; + if (!task_data) { + CAM_ERR(CAM_JPEG, "task_data is NULL"); + return -EINVAL; + } + wq_task_data->data = (void *)dev_type; + wq_task_data->request_id = 0; + wq_task_data->type = CAM_JPEG_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_jpeg_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &g_jpeg_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) { + CAM_ERR(CAM_JPEG, "could not enque task %d", rc); + return rc; + } + + mem_hdl = + p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].handle; + rc = cam_mem_get_cpu_buf(mem_hdl, &kaddr, &cmd_buf_len); + if (rc) { + CAM_ERR(CAM_JPEG, "unable to get info for cmd buf: %x %d", + hw_mgr->iommu_hdl, rc); + return rc; + } + + cmd_buf_kaddr = (uint32_t *)kaddr; + + cmd_buf_kaddr = + (cmd_buf_kaddr + + (p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset + / sizeof(uint32_t))); + + p_params = (struct cam_jpeg_config_inout_param_info *)cmd_buf_kaddr; + + p_params->output_size = task_data->result_size; + CAM_DBG(CAM_JPEG, "Encoded Size %d", task_data->result_size); + + buf_data.num_handles = + p_cfg_req->hw_cfg_args.num_out_map_entries; + for (i = 0; i < buf_data.num_handles; i++) { + buf_data.resource_handle[i] = + p_cfg_req->hw_cfg_args.out_map_entries[i].resource_handle; + } + buf_data.request_id = + PTR_TO_U64(p_cfg_req->hw_cfg_args.priv); + ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data); + + list_add_tail(&p_cfg_req->list, &hw_mgr->free_req_list); + return rc; +} + +static int cam_jpeg_hw_mgr_cb( + uint32_t irq_status, int32_t result_size, void *data) +{ + int32_t rc; + unsigned long flags; + struct cam_jpeg_hw_mgr *hw_mgr = &g_jpeg_hw_mgr; + struct crm_workq_task *task; + struct cam_jpeg_process_irq_work_data_t *task_data; + + spin_lock_irqsave(&hw_mgr->hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task( + g_jpeg_hw_mgr.work_process_irq_cb); + if (!task) { + CAM_ERR(CAM_JPEG, "no empty task"); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + return -ENOMEM; + } + + task_data = (struct cam_jpeg_process_irq_work_data_t *)task->payload; + task_data->data = data; + task_data->irq_status = irq_status; + task_data->result_size = result_size; + task_data->type = CAM_JPEG_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_jpeg_mgr_process_irq; + + rc = cam_req_mgr_workq_enqueue_task(task, &g_jpeg_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + + return rc; +} + +static int cam_jpeg_mgr_get_free_ctx(struct cam_jpeg_hw_mgr *hw_mgr) +{ + int i = 0; + int num_ctx = CAM_JPEG_CTX_MAX; + + for (i = 0; i < num_ctx; i++) { + mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex); + if (hw_mgr->ctx_data[i].in_use == false) { + hw_mgr->ctx_data[i].in_use = true; + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + break; + } + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + } + + return i; +} + + +static int cam_jpeg_mgr_release_ctx( + struct cam_jpeg_hw_mgr *hw_mgr, struct cam_jpeg_hw_ctx_data *ctx_data) +{ + if (!ctx_data) { + CAM_ERR(CAM_JPEG, "invalid ctx_data %pK", ctx_data); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is already un-used: %pK", ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + + ctx_data->in_use = false; + mutex_unlock(&ctx_data->ctx_mutex); + + return 0; +} + +static int cam_jpeg_insert_cdm_change_base( + struct cam_hw_config_args *config_args, + struct cam_jpeg_hw_ctx_data *ctx_data, + struct cam_jpeg_hw_mgr *hw_mgr) +{ + int rc = 0; + uint32_t dev_type; + struct cam_cdm_bl_request *cdm_cmd; + uint32_t size; + uint32_t mem_cam_base; + uintptr_t iova_addr; + uint32_t *ch_base_iova_addr; + size_t ch_base_len; + + rc = cam_mem_get_cpu_buf( + config_args->hw_update_entries[CAM_JPEG_CHBASE].handle, + &iova_addr, &ch_base_len); + if (rc) { + CAM_ERR(CAM_JPEG, + "unable to get src buf info for cmd buf: %d", rc); + return rc; + } + + if (config_args->hw_update_entries[CAM_JPEG_CHBASE].offset >= + ch_base_len) { + CAM_ERR(CAM_JPEG, "Not enough buf"); + return -EINVAL; + } + CAM_DBG(CAM_JPEG, "iova %pK len %zu offset %d", + (void *)iova_addr, ch_base_len, + config_args->hw_update_entries[CAM_JPEG_CHBASE].offset); + ch_base_iova_addr = (uint32_t *)iova_addr; + ch_base_iova_addr = (ch_base_iova_addr + + (config_args->hw_update_entries[CAM_JPEG_CHBASE].offset / + sizeof(uint32_t))); + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + mem_cam_base = hw_mgr->cdm_reg_map[dev_type][0]->mem_cam_base; + size = + hw_mgr->cdm_info[dev_type][0].cdm_ops->cdm_required_size_changebase(); + hw_mgr->cdm_info[dev_type][0].cdm_ops->cdm_write_changebase( + ch_base_iova_addr, mem_cam_base); + + cdm_cmd = ctx_data->cdm_cmd; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].bl_addr.mem_handle = + config_args->hw_update_entries[CAM_JPEG_CHBASE].handle; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].offset = + config_args->hw_update_entries[CAM_JPEG_CHBASE].offset; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = size * sizeof(uint32_t); + cdm_cmd->cmd_arrary_count++; + + ch_base_iova_addr += size; + *ch_base_iova_addr = 0; + ch_base_iova_addr += size; + *ch_base_iova_addr = 0; + + return rc; +} + +static int cam_jpeg_mgr_process_cmd(void *priv, void *data) +{ + int rc; + int i = 0; + struct cam_jpeg_hw_mgr *hw_mgr = priv; + struct cam_hw_update_entry *cmd; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_hw_config_args *config_args = NULL; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + uintptr_t request_id = 0; + struct cam_jpeg_process_frame_work_data_t *task_data = + (struct cam_jpeg_process_frame_work_data_t *)data; + uint32_t dev_type; + struct cam_jpeg_set_irq_cb irq_cb; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + struct cam_hw_done_event_data buf_data; + struct cam_hw_config_args *hw_cfg_args = NULL; + + if (!hw_mgr || !task_data) { + CAM_ERR(CAM_JPEG, "Invalid arguments %pK %pK", + hw_mgr, task_data); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + if (list_empty(&hw_mgr->hw_config_req_list)) { + CAM_DBG(CAM_JPEG, "no available request"); + rc = -EFAULT; + goto end; + } + + p_cfg_req = list_first_entry(&hw_mgr->hw_config_req_list, + struct cam_jpeg_hw_cfg_req, list); + if (!p_cfg_req) { + CAM_ERR(CAM_JPEG, "no request"); + rc = -EFAULT; + goto end; + } + + if (false == hw_mgr->device_in_use[p_cfg_req->dev_type][0]) { + hw_mgr->device_in_use[p_cfg_req->dev_type][0] = true; + hw_mgr->dev_hw_cfg_args[p_cfg_req->dev_type][0] = p_cfg_req; + list_del_init(&p_cfg_req->list); + } else { + CAM_DBG(CAM_JPEG, "Not dequeing, just return"); + rc = -EFAULT; + goto end; + } + + config_args = (struct cam_hw_config_args *)&p_cfg_req->hw_cfg_args; + request_id = task_data->request_id; + if (request_id != (uintptr_t)config_args->priv) { + CAM_DBG(CAM_JPEG, "not a recent req %zd %zd", + request_id, (uintptr_t)config_args->priv); + } + + if (!config_args->num_hw_update_entries) { + CAM_ERR(CAM_JPEG, "No hw update enteries are available"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -EINVAL; + goto end_unusedev; + } + + ctx_data = (struct cam_jpeg_hw_ctx_data *)config_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -EINVAL; + goto end_unusedev; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + if (dev_type != p_cfg_req->dev_type) + CAM_WARN(CAM_JPEG, "dev types not same something wrong"); + + if (!hw_mgr->devices[dev_type][0]->hw_ops.init) { + CAM_ERR(CAM_JPEG, "hw op init null "); + rc = -EFAULT; + goto end; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.init( + hw_mgr->devices[dev_type][0]->hw_priv, + ctx_data, + sizeof(ctx_data)); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to Init %d HW", dev_type); + goto end; + } + + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = (void *)ctx_data; + irq_cb.b_set_cb = true; + if (!hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + CAM_ERR(CAM_JPEG, "op process_cmd null "); + rc = -EFAULT; + goto end_callcb; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) { + CAM_ERR(CAM_JPEG, "SET_IRQ_CB failed %d", rc); + goto end_callcb; + } + + if (!hw_mgr->devices[dev_type][0]->hw_ops.reset) { + CAM_ERR(CAM_JPEG, "op reset null "); + rc = -EFAULT; + goto end_callcb; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.reset( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg hw reset failed %d", rc); + goto end_callcb; + } + + cdm_cmd = ctx_data->cdm_cmd; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = false; + cdm_cmd->userdata = NULL; + cdm_cmd->cookie = 0; + cdm_cmd->cmd_arrary_count = 0; + + rc = cam_jpeg_insert_cdm_change_base(config_args, + ctx_data, hw_mgr); + if (rc) { + CAM_ERR(CAM_JPEG, "insert change base failed %d", rc); + goto end_callcb; + } + + CAM_DBG(CAM_JPEG, "num hw up %d", config_args->num_hw_update_entries); + for (i = CAM_JPEG_CFG; i < (config_args->num_hw_update_entries - 1); + i++) { + cmd = (config_args->hw_update_entries + i); + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].bl_addr.mem_handle + = cmd->handle; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].offset = + cmd->offset; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = + cmd->len; + CAM_DBG(CAM_JPEG, "i %d entry h %d o %d l %d", + i, cmd->handle, cmd->offset, cmd->len); + cdm_cmd->cmd_arrary_count++; + } + + rc = cam_cdm_submit_bls( + hw_mgr->cdm_info[dev_type][0].cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to apply the configs %d", rc); + goto end_callcb; + } + + if (!hw_mgr->devices[dev_type][0]->hw_ops.start) { + CAM_ERR(CAM_JPEG, "op start null "); + rc = -EINVAL; + goto end_callcb; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.start( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to start hw %d", + rc); + goto end_callcb; + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; + +end_callcb: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + if (p_cfg_req) { + hw_cfg_args = &p_cfg_req->hw_cfg_args; + buf_data.num_handles = + hw_cfg_args->num_out_map_entries; + for (i = 0; i < buf_data.num_handles; i++) { + buf_data.resource_handle[i] = + hw_cfg_args->out_map_entries[i].resource_handle; + } + buf_data.request_id = + (uintptr_t)p_cfg_req->hw_cfg_args.priv; + ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data); + } +end_unusedev: + mutex_lock(&hw_mgr->hw_mgr_mutex); + hw_mgr->device_in_use[p_cfg_req->dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[p_cfg_req->dev_type][0] = NULL; + +end: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_jpeg_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) +{ + int rc; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_config_args *config_args = config_hw_args; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + uintptr_t request_id = 0; + struct cam_hw_update_entry *hw_update_entries; + struct crm_workq_task *task; + struct cam_jpeg_process_frame_work_data_t *task_data; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + + if (!hw_mgr || !config_args) { + CAM_ERR(CAM_JPEG, "Invalid arguments %pK %pK", + hw_mgr, config_args); + return -EINVAL; + } + + if (!config_args->num_hw_update_entries) { + CAM_ERR(CAM_JPEG, "No hw update enteries are available"); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + ctx_data = (struct cam_jpeg_hw_ctx_data *)config_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + if (list_empty(&hw_mgr->free_req_list)) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_JPEG, "list empty"); + return -ENOMEM; + } + + p_cfg_req = list_first_entry(&hw_mgr->free_req_list, + struct cam_jpeg_hw_cfg_req, list); + list_del_init(&p_cfg_req->list); + + /* Update Currently Processing Config Request */ + p_cfg_req->hw_cfg_args = *config_args; + p_cfg_req->dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + request_id = (uintptr_t)config_args->priv; + p_cfg_req->req_id = request_id; + hw_update_entries = config_args->hw_update_entries; + CAM_DBG(CAM_JPEG, "ctx_data = %pK req_id = %lld %zd", + ctx_data, request_id, (uintptr_t)config_args->priv); + task = cam_req_mgr_workq_get_task(g_jpeg_hw_mgr.work_process_frame); + if (!task) { + CAM_ERR(CAM_JPEG, "no empty task"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -ENOMEM; + goto err_after_dq_free_list; + } + + + task_data = (struct cam_jpeg_process_frame_work_data_t *) + task->payload; + if (!task_data) { + CAM_ERR(CAM_JPEG, "task_data is NULL"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -EINVAL; + goto err_after_dq_free_list; + } + CAM_DBG(CAM_JPEG, "cfge %pK num %d", + p_cfg_req->hw_cfg_args.hw_update_entries, + p_cfg_req->hw_cfg_args.num_hw_update_entries); + + list_add_tail(&p_cfg_req->list, &hw_mgr->hw_config_req_list); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + task_data->data = (void *)(uintptr_t)p_cfg_req->dev_type; + task_data->request_id = request_id; + task_data->type = CAM_JPEG_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_jpeg_mgr_process_cmd; + + rc = cam_req_mgr_workq_enqueue_task(task, &g_jpeg_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) { + CAM_ERR(CAM_JPEG, "failed to enqueue task %d", rc); + goto err_after_get_task; + } + + return rc; + +err_after_get_task: + list_del_init(&p_cfg_req->list); +err_after_dq_free_list: + list_add_tail(&p_cfg_req->list, &hw_mgr->free_req_list); + + return rc; +} + +static void cam_jpeg_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + uint64_t iova_addr; + size_t src_buf_size; + int i; + int j; + int rc = 0; + int32_t mmu_hdl; + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_JPEG, + "Found PF at port: %d mem %x fd: %x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_JPEG, "port: %d f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, "get src buf address fail"); + continue; + } + if (iova_addr >> 32) { + CAM_ERR(CAM_JPEG, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_JPEG, + "pln %d w %d h %d size %d addr 0x%x offset 0x%x memh %x", + j, io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + (int32_t)src_buf_size, + (unsigned int)iova_addr, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + + iova_addr += io_cfg[i].offsets[j]; + } + } +} + +static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc, i, j, k; + struct cam_hw_prepare_update_args *prepare_args = + prepare_hw_update_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + struct cam_packet *packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + struct cam_kmd_buf_info kmd_buf; + + if (!prepare_args || !hw_mgr) { + CAM_ERR(CAM_JPEG, "Invalid args %pK %pK", + prepare_args, hw_mgr); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_data = (struct cam_jpeg_hw_ctx_data *)prepare_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + packet = prepare_args->packet; + if (!packet) { + CAM_ERR(CAM_JPEG, "received packet is NULL"); + return -EINVAL; + } + + if (((packet->header.op_code & 0xff) != CAM_JPEG_OPCODE_ENC_UPDATE) && + ((packet->header.op_code + & 0xff) != CAM_JPEG_OPCODE_DMA_UPDATE)) { + CAM_ERR(CAM_JPEG, "Invalid Opcode in pkt: %d", + packet->header.op_code & 0xff); + return -EINVAL; + } + + rc = cam_packet_util_validate_packet(packet, prepare_args->remain_len); + if (rc) { + CAM_ERR(CAM_JPEG, "invalid packet %d", rc); + return rc; + } + + if ((packet->num_cmd_buf > 5) || !packet->num_patches || + !packet->num_io_configs) { + CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u", + packet->num_cmd_buf, + packet->num_patches); + return -EINVAL; + } + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *)&packet->payload + + (packet->cmd_buf_offset / 4)); + CAM_DBG(CAM_JPEG, "packet = %pK cmd_desc = %pK size = %lu", + (void *)packet, (void *)cmd_desc, + sizeof(struct cam_cmd_buf_desc)); + + rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, -1); + if (rc) { + CAM_ERR(CAM_JPEG, "Patch processing failed %d", rc); + return rc; + } + + io_cfg_ptr = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + CAM_DBG(CAM_JPEG, "packet = %pK io_cfg_ptr = %pK size = %lu", + (void *)packet, (void *)io_cfg_ptr, + sizeof(struct cam_buf_io_cfg)); + prepare_args->pf_data->packet = packet; + + prepare_args->num_out_map_entries = 0; + + for (i = 0, j = 0, k = 0; i < packet->num_io_configs; i++) { + if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) { + prepare_args->in_map_entries[j].resource_handle = + io_cfg_ptr[i].resource_type; + prepare_args->in_map_entries[j++].sync_id = + io_cfg_ptr[i].fence; + prepare_args->num_in_map_entries++; + } else { + prepare_args->in_map_entries[k].resource_handle = + io_cfg_ptr[i].resource_type; + prepare_args->out_map_entries[k++].sync_id = + io_cfg_ptr[i].fence; + prepare_args->num_out_map_entries++; + } + CAM_DBG(CAM_JPEG, "dir[%d]: %u, fence: %u", + i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); + } + + + j = prepare_args->num_hw_update_entries; + rc = cam_packet_util_get_kmd_buffer(packet, &kmd_buf); + if (rc) { + CAM_ERR(CAM_JPEG, "get kmd buf failed %d", rc); + return rc; + } + /* fill kmd buf info into 1st hw update entry */ + prepare_args->hw_update_entries[j].len = + (uint32_t)kmd_buf.used_bytes; + prepare_args->hw_update_entries[j].handle = + (uint32_t)kmd_buf.handle; + prepare_args->hw_update_entries[j].offset = + (uint32_t)kmd_buf.offset; + j++; + + for (i = 0; i < packet->num_cmd_buf; i++, j++) { + prepare_args->hw_update_entries[j].len = + (uint32_t)cmd_desc[i].length; + prepare_args->hw_update_entries[j].handle = + (uint32_t)cmd_desc[i].mem_handle; + prepare_args->hw_update_entries[j].offset = + (uint32_t)cmd_desc[i].offset; + } + prepare_args->num_hw_update_entries = j; + prepare_args->priv = (void *)(uintptr_t)packet->header.request_id; + + CAM_DBG(CAM_JPEG, "will wait on input sync sync_id %d", + prepare_args->in_map_entries[0].sync_id); + + return rc; +} + +static void cam_jpeg_mgr_stop_deinit_dev(struct cam_jpeg_hw_mgr *hw_mgr, + struct cam_jpeg_hw_cfg_req *p_cfg_req, uint32_t dev_type) +{ + int rc = 0; + struct cam_jpeg_set_irq_cb irq_cb; + + /* stop reset Unregister CB and deinit */ + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = NULL; + irq_cb.b_set_cb = false; + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_JPEG, "SET_IRQ_CB fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "process_cmd null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "stop fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "op stop null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.deinit( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to Deinit %d HW %d", + dev_type, rc); + } else { + CAM_ERR(CAM_JPEG, "op deinit null %d", dev_type); + } + + hw_mgr->device_in_use[dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; +} + +static int cam_jpeg_mgr_flush(void *hw_mgr_priv, + struct cam_jpeg_hw_ctx_data *ctx_data) +{ + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL; + + CAM_DBG(CAM_JPEG, "E: JPEG flush ctx"); + + if (!hw_mgr || !ctx_data) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (hw_mgr->device_in_use[dev_type][0] == true && + p_cfg_req != NULL) { + if ((struct cam_jpeg_hw_ctx_data *) + p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) { + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); + } + } + + list_for_each_entry_safe(cfg_req, req_temp, + &hw_mgr->hw_config_req_list, list) { + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) + continue; + + list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); + } + + CAM_DBG(CAM_JPEG, "X: JPEG flush ctx"); + + return 0; +} + +static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, + struct cam_jpeg_hw_ctx_data *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_cfg_req *cfg_req = NULL; + struct cam_jpeg_hw_cfg_req *req_temp = NULL; + long request_id = 0; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + bool b_req_found = false; + + CAM_DBG(CAM_JPEG, "E: JPEG flush req"); + + if (!hw_mgr || !ctx_data || !flush_args) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + if (flush_args->num_req_pending) + return 0; + + request_id = (uintptr_t)flush_args->flush_req_active[0]; + + if (!flush_args->num_req_active) + return 0; + + if (request_id <= 0) { + CAM_ERR(CAM_JPEG, "Invalid red id %ld", request_id); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (hw_mgr->device_in_use[dev_type][0] == true && + p_cfg_req != NULL) { + if (((struct cam_jpeg_hw_ctx_data *) + p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) && + (p_cfg_req->req_id == request_id)) { + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); + b_req_found = true; + } + } + + list_for_each_entry_safe(cfg_req, req_temp, + &hw_mgr->hw_config_req_list, list) { + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) + continue; + + if (cfg_req->req_id != request_id) + continue; + + list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); + b_req_found = true; + break; + } + + if (!b_req_found) { + CAM_ERR(CAM_JPEG, "req not found %ld", request_id); + return -EINVAL; + } + + CAM_DBG(CAM_JPEG, "X: JPEG flush req"); + return 0; +} + +static int cam_jpeg_mgr_hw_flush(void *hw_mgr_priv, void *flush_hw_args) +{ + int rc = 0; + struct cam_hw_flush_args *flush_args = flush_hw_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + + if (!hw_mgr || !flush_args || !flush_args->ctxt_to_hw_map) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + mutex_lock(&hw_mgr->hw_mgr_mutex); + + ctx_data = (struct cam_jpeg_hw_ctx_data *)flush_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + if ((flush_args->flush_type >= CAM_FLUSH_TYPE_MAX) || + (flush_args->flush_type < CAM_FLUSH_TYPE_REQ)) { + CAM_ERR(CAM_JPEG, "Invalid flush type: %d", + flush_args->flush_type); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_ALL: + rc = cam_jpeg_mgr_flush(hw_mgr_priv, ctx_data); + if ((rc)) + CAM_ERR(CAM_JPEG, "Flush failed %d", rc); + break; + case CAM_FLUSH_TYPE_REQ: + rc = cam_jpeg_mgr_flush_req(hw_mgr_priv, ctx_data, flush_args); + break; + default: + CAM_ERR(CAM_JPEG, "Invalid flush type: %d", + flush_args->flush_type); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_jpeg_mgr_hw_stop(void *hw_mgr_priv, void *stop_hw_args) +{ + int rc; + struct cam_hw_stop_args *stop_args = + (struct cam_hw_stop_args *)stop_hw_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + + if (!hw_mgr || !stop_args || !stop_args->ctxt_to_hw_map) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + mutex_lock(&hw_mgr->hw_mgr_mutex); + + ctx_data = (struct cam_jpeg_hw_ctx_data *)stop_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + rc = cam_jpeg_mgr_flush(hw_mgr_priv, ctx_data); + if ((rc)) + CAM_ERR(CAM_JPEG, "flush failed %d", rc); + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) +{ + int rc; + struct cam_hw_release_args *release_hw = release_hw_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + uint32_t dev_type; + + if (!hw_mgr || !release_hw || !release_hw->ctxt_to_hw_map) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + ctx_data = (struct cam_jpeg_hw_ctx_data *)release_hw->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 0) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_JPEG, "Error Unbalanced deinit"); + return -EFAULT; + } + + hw_mgr->cdm_info[dev_type][0].ref_cnt--; + if (!(hw_mgr->cdm_info[dev_type][0].ref_cnt)) { + if (cam_cdm_stream_off( + hw_mgr->cdm_info[dev_type][0].cdm_handle)) { + CAM_ERR(CAM_JPEG, "CDM stream off failed %d", + hw_mgr->cdm_info[dev_type][0].cdm_handle); + } + /* release cdm handle */ + cam_cdm_release(hw_mgr->cdm_info[dev_type][0].cdm_handle); + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + rc = cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data); + if (rc) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_JPEG, "JPEG release ctx failed"); + kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; + + return -EINVAL; + } + + kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; + CAM_DBG(CAM_JPEG, "handle %llu", ctx_data); + + return rc; +} + +static int cam_jpeg_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) +{ + int rc = 0; + int32_t ctx_id = 0; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + struct cam_hw_acquire_args *args = acquire_hw_args; + struct cam_jpeg_acquire_dev_info jpeg_dev_acquire_info; + struct cam_cdm_acquire_data cdm_acquire; + uint32_t dev_type; + uint32_t size = 0; + + if ((!hw_mgr_priv) || (!acquire_hw_args)) { + CAM_ERR(CAM_JPEG, "Invalid params: %pK %pK", hw_mgr_priv, + acquire_hw_args); + return -EINVAL; + } + + if (args->num_acq > 1) { + CAM_ERR(CAM_JPEG, + "number of resources are wrong: %u", + args->num_acq); + return -EINVAL; + } + + if (copy_from_user(&jpeg_dev_acquire_info, + (void __user *)args->acquire_info, + sizeof(jpeg_dev_acquire_info))) { + CAM_ERR(CAM_JPEG, "copy failed"); + return -EFAULT; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_id = cam_jpeg_mgr_get_free_ctx(hw_mgr); + if (ctx_id >= CAM_JPEG_CTX_MAX) { + CAM_ERR(CAM_JPEG, "No free ctx space in hw_mgr"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EFAULT; + } + + ctx_data = &hw_mgr->ctx_data[ctx_id]; + + ctx_data->cdm_cmd = + kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((CAM_JPEG_HW_ENTRIES_MAX - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!ctx_data->cdm_cmd) { + rc = -ENOMEM; + goto jpeg_release_ctx; + } + + mutex_lock(&ctx_data->ctx_mutex); + ctx_data->jpeg_dev_acquire_info = jpeg_dev_acquire_info; + mutex_unlock(&ctx_data->ctx_mutex); + + if (ctx_data->jpeg_dev_acquire_info.dev_type >= + CAM_JPEG_RES_TYPE_MAX) { + rc = -EINVAL; + goto acq_cdm_hdl_failed; + } + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + if (!hw_mgr->cdm_info[dev_type][0].ref_cnt) { + + if (dev_type == CAM_JPEG_RES_TYPE_ENC) { + memcpy(cdm_acquire.identifier, + "jpegenc", sizeof("jpegenc")); + } else { + memcpy(cdm_acquire.identifier, + "jpegdma", sizeof("jpegdma")); + } + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ctx_data; + if (hw_mgr->cdm_reg_map[dev_type][0]) { + cdm_acquire.base_array[0] = + hw_mgr->cdm_reg_map[dev_type][0]; + } + cdm_acquire.base_array_cnt = 1; + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = NULL; + + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to acquire the CDM HW %d", + rc); + rc = -EFAULT; + goto acq_cdm_hdl_failed; + } + hw_mgr->cdm_info[dev_type][0].cdm_handle = cdm_acquire.handle; + hw_mgr->cdm_info[dev_type][0].cdm_ops = cdm_acquire.ops; + hw_mgr->cdm_info[dev_type][0].ref_cnt++; + } else { + hw_mgr->cdm_info[dev_type][0].ref_cnt++; + } + + size = + hw_mgr->cdm_info[dev_type][0].cdm_ops->cdm_required_size_changebase(); + + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1) + if (cam_cdm_stream_on( + hw_mgr->cdm_info[dev_type][0].cdm_handle)) { + CAM_ERR(CAM_JPEG, "Can not start cdm (%d)!", + hw_mgr->cdm_info[dev_type][0].cdm_handle); + rc = -EFAULT; + goto start_cdm_hdl_failed; + } + + mutex_lock(&ctx_data->ctx_mutex); + ctx_data->context_priv = args->context_data; + + args->ctxt_to_hw_map = (void *)&(hw_mgr->ctx_data[ctx_id]); + + mutex_unlock(&ctx_data->ctx_mutex); + + hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb; + + + if (copy_to_user((void __user *)args->acquire_info, + &jpeg_dev_acquire_info, + sizeof(jpeg_dev_acquire_info))) { + rc = -EFAULT; + goto copy_to_user_failed; + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_JPEG, "success ctx_data= %pK", ctx_data); + + return rc; + +copy_to_user_failed: + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1) + cam_cdm_stream_off(hw_mgr->cdm_info[dev_type][0].cdm_handle); +start_cdm_hdl_failed: + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1) + cam_cdm_release(hw_mgr->cdm_info[dev_type][0].cdm_handle); + hw_mgr->cdm_info[dev_type][0].ref_cnt--; +acq_cdm_hdl_failed: + kfree(ctx_data->cdm_cmd); +jpeg_release_ctx: + cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_jpeg_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) +{ + int rc; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query_cap = hw_caps_args; + + if (!hw_mgr_priv || !hw_caps_args) { + CAM_ERR(CAM_JPEG, "Invalid params: %pK %pK", + hw_mgr_priv, hw_caps_args); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + if (copy_to_user(u64_to_user_ptr(query_cap->caps_handle), + &g_jpeg_hw_mgr.jpeg_caps, + sizeof(struct cam_jpeg_query_cap_cmd))) { + CAM_ERR(CAM_JPEG, "copy_to_user failed"); + rc = -EFAULT; + goto copy_error; + } + CAM_DBG(CAM_JPEG, "Success"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return 0; + +copy_error: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_jpeg_setup_workqs(void) +{ + int rc, i; + + rc = cam_req_mgr_workq_create( + "jpeg_command_queue", + CAM_JPEG_WORKQ_NUM_TASK, + &g_jpeg_hw_mgr.work_process_frame, + CRM_WORKQ_USAGE_NON_IRQ, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); + goto work_process_frame_failed; + } + + rc = cam_req_mgr_workq_create( + "jpeg_message_queue", + CAM_JPEG_WORKQ_NUM_TASK, + &g_jpeg_hw_mgr.work_process_irq_cb, + CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); + goto work_process_irq_cb_failed; + } + + g_jpeg_hw_mgr.process_frame_work_data = + kzalloc(sizeof(struct cam_jpeg_process_frame_work_data_t) * + CAM_JPEG_WORKQ_NUM_TASK, GFP_KERNEL); + if (!g_jpeg_hw_mgr.process_frame_work_data) { + rc = -ENOMEM; + goto work_process_frame_data_failed; + } + + g_jpeg_hw_mgr.process_irq_cb_work_data = + kzalloc(sizeof(struct cam_jpeg_process_irq_work_data_t) * + CAM_JPEG_WORKQ_NUM_TASK, GFP_KERNEL); + if (!g_jpeg_hw_mgr.process_irq_cb_work_data) { + rc = -ENOMEM; + goto work_process_irq_cb_data_failed; + } + + for (i = 0; i < CAM_JPEG_WORKQ_NUM_TASK; i++) + g_jpeg_hw_mgr.work_process_irq_cb->task.pool[i].payload = + &g_jpeg_hw_mgr.process_irq_cb_work_data[i]; + + for (i = 0; i < CAM_JPEG_WORKQ_NUM_TASK; i++) + g_jpeg_hw_mgr.work_process_frame->task.pool[i].payload = + &g_jpeg_hw_mgr.process_frame_work_data[i]; + + INIT_LIST_HEAD(&g_jpeg_hw_mgr.hw_config_req_list); + INIT_LIST_HEAD(&g_jpeg_hw_mgr.free_req_list); + for (i = 0; i < CAM_JPEG_HW_CFG_Q_MAX; i++) { + INIT_LIST_HEAD(&(g_jpeg_hw_mgr.req_list[i].list)); + list_add_tail(&(g_jpeg_hw_mgr.req_list[i].list), + &(g_jpeg_hw_mgr.free_req_list)); + } + + return rc; + +work_process_irq_cb_data_failed: + kfree(g_jpeg_hw_mgr.process_frame_work_data); +work_process_frame_data_failed: + cam_req_mgr_workq_destroy(&g_jpeg_hw_mgr.work_process_irq_cb); +work_process_irq_cb_failed: + cam_req_mgr_workq_destroy(&g_jpeg_hw_mgr.work_process_frame); +work_process_frame_failed: + + return rc; +} + +static int cam_jpeg_init_devices(struct device_node *of_node, + uint32_t *p_num_enc_dev, + uint32_t *p_num_dma_dev) +{ + int count, i, rc; + uint32_t num_dev; + uint32_t num_dma_dev; + const char *name = NULL; + struct device_node *child_node = NULL; + struct platform_device *child_pdev = NULL; + struct cam_hw_intf *child_dev_intf = NULL; + struct cam_hw_info *enc_hw = NULL; + struct cam_hw_info *dma_hw = NULL; + struct cam_hw_soc_info *enc_soc_info = NULL; + struct cam_hw_soc_info *dma_soc_info = NULL; + + if (!p_num_enc_dev || !p_num_dma_dev) { + rc = -EINVAL; + goto num_dev_failed; + } + count = of_property_count_strings(of_node, "compat-hw-name"); + if (!count) { + CAM_ERR(CAM_JPEG, + "no compat hw found in dev tree, count = %d", + count); + rc = -EINVAL; + goto num_dev_failed; + } + + rc = of_property_read_u32(of_node, "num-jpeg-enc", &num_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "read num enc devices failed %d", rc); + goto num_enc_failed; + } + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL); + if (!g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC]) { + rc = -ENOMEM; + CAM_ERR(CAM_JPEG, "getting number of dma dev nodes failed"); + goto num_enc_failed; + } + + rc = of_property_read_u32(of_node, "num-jpeg-dma", &num_dma_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "get num dma dev nodes failed %d", rc); + goto num_dma_failed; + } + + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dma_dev, GFP_KERNEL); + if (!g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA]) { + rc = -ENOMEM; + goto num_dma_failed; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "compat-hw-name", + i, &name); + if (rc) { + CAM_ERR(CAM_JPEG, "getting dev object name failed"); + goto compat_hw_name_failed; + } + + child_node = of_find_node_by_name(NULL, name); + if (!child_node) { + CAM_ERR(CAM_JPEG, + "error! Cannot find node in dtsi %s", name); + rc = -ENODEV; + goto compat_hw_name_failed; + } + + child_pdev = of_find_device_by_node(child_node); + if (!child_pdev) { + CAM_ERR(CAM_JPEG, "failed to find device on bus %s", + child_node->name); + rc = -ENODEV; + of_node_put(child_node); + goto compat_hw_name_failed; + } + + child_dev_intf = (struct cam_hw_intf *)platform_get_drvdata( + child_pdev); + if (!child_dev_intf) { + CAM_ERR(CAM_JPEG, "no child device"); + of_node_put(child_node); + rc = -ENODEV; + goto compat_hw_name_failed; + } + CAM_DBG(CAM_JPEG, "child_intf %pK type %d id %d", + child_dev_intf, + child_dev_intf->hw_type, + child_dev_intf->hw_idx); + + if ((child_dev_intf->hw_type == CAM_JPEG_DEV_ENC && + child_dev_intf->hw_idx >= num_dev) || + (child_dev_intf->hw_type == CAM_JPEG_DEV_DMA && + child_dev_intf->hw_idx >= num_dma_dev)) { + CAM_ERR(CAM_JPEG, "index out of range"); + rc = -ENODEV; + goto compat_hw_name_failed; + } + g_jpeg_hw_mgr.devices[child_dev_intf->hw_type] + [child_dev_intf->hw_idx] = child_dev_intf; + + of_node_put(child_node); + } + + enc_hw = (struct cam_hw_info *) + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC][0]->hw_priv; + enc_soc_info = &enc_hw->soc_info; + g_jpeg_hw_mgr.cdm_reg_map[CAM_JPEG_DEV_ENC][0] = + &enc_soc_info->reg_map[0]; + dma_hw = (struct cam_hw_info *) + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA][0]->hw_priv; + dma_soc_info = &dma_hw->soc_info; + g_jpeg_hw_mgr.cdm_reg_map[CAM_JPEG_DEV_DMA][0] = + &dma_soc_info->reg_map[0]; + + *p_num_enc_dev = num_dev; + *p_num_dma_dev = num_dma_dev; + + return rc; + +compat_hw_name_failed: + kfree(g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA]); +num_dma_failed: + kfree(g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC]); +num_enc_failed: +num_dev_failed: + + return rc; +} + +static int cam_jpeg_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_JPEG, "Invalid arguments"); + return -EINVAL; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_jpeg_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + break; + default: + CAM_ERR(CAM_JPEG, "Invalid cmd"); + } + + return rc; +} + +int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, + int *iommu_hdl) +{ + int i, rc; + uint32_t num_dev; + uint32_t num_dma_dev; + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_iommu_handle cdm_handles; + + hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl; + if (!of_node || !hw_mgr_intf) { + CAM_ERR(CAM_JPEG, "Invalid args of_node %pK hw_mgr %pK", + of_node, hw_mgr_intf); + return -EINVAL; + } + + memset(hw_mgr_hdl, 0x0, sizeof(struct cam_hw_mgr_intf)); + hw_mgr_intf->hw_mgr_priv = &g_jpeg_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_jpeg_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_jpeg_mgr_acquire_hw; + hw_mgr_intf->hw_release = cam_jpeg_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_jpeg_mgr_prepare_hw_update; + hw_mgr_intf->hw_config = cam_jpeg_mgr_config_hw; + hw_mgr_intf->hw_flush = cam_jpeg_mgr_hw_flush; + hw_mgr_intf->hw_stop = cam_jpeg_mgr_hw_stop; + hw_mgr_intf->hw_cmd = cam_jpeg_mgr_cmd; + + mutex_init(&g_jpeg_hw_mgr.hw_mgr_mutex); + spin_lock_init(&g_jpeg_hw_mgr.hw_mgr_lock); + + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) + mutex_init(&g_jpeg_hw_mgr.ctx_data[i].ctx_mutex); + + rc = cam_jpeg_init_devices(of_node, &num_dev, &num_dma_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg init devices %d", rc); + goto smmu_get_failed; + } + + rc = cam_smmu_get_handle("jpeg", &g_jpeg_hw_mgr.iommu_hdl); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg get iommu handle failed %d", rc); + goto smmu_get_failed; + } + + CAM_DBG(CAM_JPEG, "mmu handle :%d", g_jpeg_hw_mgr.iommu_hdl); + + rc = cam_cdm_get_iommu_handle("jpegenc", &cdm_handles); + if (rc) { + CAM_ERR(CAM_JPEG, "acquire cdm iommu handle Fail %d", rc); + g_jpeg_hw_mgr.cdm_iommu_hdl = -1; + g_jpeg_hw_mgr.cdm_iommu_hdl_secure = -1; + goto cdm_iommu_failed; + } + g_jpeg_hw_mgr.cdm_iommu_hdl = cdm_handles.non_secure; + g_jpeg_hw_mgr.cdm_iommu_hdl_secure = cdm_handles.secure; + + g_jpeg_hw_mgr.jpeg_caps.dev_iommu_handle.non_secure = + g_jpeg_hw_mgr.iommu_hdl; + g_jpeg_hw_mgr.jpeg_caps.dev_iommu_handle.secure = + g_jpeg_hw_mgr.iommu_sec_hdl; + g_jpeg_hw_mgr.jpeg_caps.cdm_iommu_handle.non_secure = + g_jpeg_hw_mgr.cdm_iommu_hdl; + g_jpeg_hw_mgr.jpeg_caps.cdm_iommu_handle.secure = + g_jpeg_hw_mgr.cdm_iommu_hdl_secure; + g_jpeg_hw_mgr.jpeg_caps.num_enc = num_dev; + g_jpeg_hw_mgr.jpeg_caps.num_dma = num_dma_dev; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.major = 4; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.minor = 2; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.incr = 0; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.reserved = 0; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.major = 4; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.minor = 2; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.incr = 0; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.reserved = 0; + + rc = cam_jpeg_setup_workqs(); + if (rc) { + CAM_ERR(CAM_JPEG, "setup work qs failed %d", rc); + goto cdm_iommu_failed; + } + + if (iommu_hdl) + *iommu_hdl = g_jpeg_hw_mgr.iommu_hdl; + + return rc; + +cdm_iommu_failed: + cam_smmu_destroy_handle(g_jpeg_hw_mgr.iommu_hdl); + g_jpeg_hw_mgr.iommu_hdl = 0; +smmu_get_failed: + mutex_destroy(&g_jpeg_hw_mgr.hw_mgr_mutex); + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) + mutex_destroy(&g_jpeg_hw_mgr.ctx_data[i].ctx_mutex); + + return rc; +} diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h new file mode 100644 index 000000000000..e482c11a82bd --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_HW_MGR_H +#define CAM_JPEG_HW_MGR_H + +#include +#include +#include + +#include "cam_jpeg_hw_intf.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" + +#define CAM_JPEG_WORKQ_NUM_TASK 30 +#define CAM_JPEG_WORKQ_TASK_CMD_TYPE 1 +#define CAM_JPEG_WORKQ_TASK_MSG_TYPE 2 +#define CAM_JPEG_HW_CFG_Q_MAX 50 + +/** + * struct cam_jpeg_process_frame_work_data_t + * + * @type: Task type + * @data: Pointer to command data + * @request_id: Request id + */ +struct cam_jpeg_process_frame_work_data_t { + uint32_t type; + void *data; + uintptr_t request_id; +}; + +/** + * struct cam_jpeg_process_irq_work_data_t + * + * @type: Task type + * @data: Pointer to message data + * @result_size: Result size of enc/dma + * @irq_status: IRQ status + */ +struct cam_jpeg_process_irq_work_data_t { + uint32_t type; + void *data; + int32_t result_size; + uint32_t irq_status; +}; + +/** + * struct cam_jpeg_hw_cdm_info_t + * + * @ref_cnt: Ref count of how many times device type is acquired + * @cdm_handle: Cdm handle + * @cdm_ops: Cdm ops struct + */ +struct cam_jpeg_hw_cdm_info_t { + int ref_cnt; + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; +}; + +/** + * struct cam_jpeg_hw_cfg_req_t + * + * @list_head: List head + * @hw_cfg_args: Hw config args + * @dev_type: Dev type for cfg request + * @req_id: Request Id + */ +struct cam_jpeg_hw_cfg_req { + struct list_head list; + struct cam_hw_config_args hw_cfg_args; + uint32_t dev_type; + uintptr_t req_id; +}; + +/** + * struct cam_jpeg_hw_ctx_data + * + * @context_priv: Context private data, cam_context from + * acquire. + * @ctx_mutex: Mutex for context + * @jpeg_dev_acquire_info: Acquire device info + * @ctxt_event_cb: Context callback function + * @in_use: Flag for context usage + * @wait_complete: Completion info + * @cdm_cmd: Cdm cmd submitted for that context. + */ +struct cam_jpeg_hw_ctx_data { + void *context_priv; + struct mutex ctx_mutex; + struct cam_jpeg_acquire_dev_info jpeg_dev_acquire_info; + cam_hw_event_cb_func ctxt_event_cb; + bool in_use; + struct completion wait_complete; + struct cam_cdm_bl_request *cdm_cmd; +}; + +/** + * struct cam_jpeg_hw_mgr + * @hw_mgr_mutex: Mutex for JPEG hardware manager + * @hw_mgr_lock: Spinlock for JPEG hardware manager + * @ctx_data: Context data + * @jpeg_caps: JPEG capabilities + * @iommu_hdl: Non secure IOMMU handle + * @iommu_sec_hdl: Secure IOMMU handle + * @work_process_frame: Work queue for hw config requests + * @work_process_irq_cb: Work queue for processing IRQs. + * @process_frame_work_data: Work data pool for hw config + * requests + * @process_irq_cb_work_data: Work data pool for irq requests + * @cdm_iommu_hdl: Iommu handle received from cdm + * @cdm_iommu_hdl_secure: Secure iommu handle received from cdm + * @devices: Core hw Devices of JPEG hardware manager + * @cdm_info: Cdm info for each core device. + * @cdm_reg_map: Regmap of each device for cdm. + * @device_in_use: Flag device being used for an active request + * @dev_hw_cfg_args: Current cfg request per core dev + * @hw_config_req_list: Pending hw update requests list + * @free_req_list: Free nodes for above list + * @req_list: Nodes of hw update list + */ +struct cam_jpeg_hw_mgr { + struct mutex hw_mgr_mutex; + spinlock_t hw_mgr_lock; + struct cam_jpeg_hw_ctx_data ctx_data[CAM_JPEG_CTX_MAX]; + struct cam_jpeg_query_cap_cmd jpeg_caps; + int32_t iommu_hdl; + int32_t iommu_sec_hdl; + struct cam_req_mgr_core_workq *work_process_frame; + struct cam_req_mgr_core_workq *work_process_irq_cb; + struct cam_jpeg_process_frame_work_data_t *process_frame_work_data; + struct cam_jpeg_process_irq_work_data_t *process_irq_cb_work_data; + int cdm_iommu_hdl; + int cdm_iommu_hdl_secure; + + struct cam_hw_intf **devices[CAM_JPEG_DEV_TYPE_MAX]; + struct cam_jpeg_hw_cdm_info_t cdm_info[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + struct cam_soc_reg_map *cdm_reg_map[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + uint32_t device_in_use[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + struct cam_jpeg_hw_cfg_req *dev_hw_cfg_args[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + + struct list_head hw_config_req_list; + struct list_head free_req_list; + struct cam_jpeg_hw_cfg_req req_list[CAM_JPEG_HW_CFG_Q_MAX]; +}; + +#endif /* CAM_JPEG_HW_MGR_H */ diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h new file mode 100644 index 000000000000..1b93547fdf25 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_HW_INTF_H +#define CAM_JPEG_HW_INTF_H + +#include "cam_cpas_api.h" + +#define CAM_JPEG_CTX_MAX 8 +#define CAM_JPEG_DEV_PER_TYPE_MAX 1 + +#define CAM_JPEG_CMD_BUF_MAX_SIZE 128 +#define CAM_JPEG_MSG_BUF_MAX_SIZE CAM_JPEG_CMD_BUF_MAX_SIZE + +#define JPEG_VOTE 640000000 + +enum cam_jpeg_hw_type { + CAM_JPEG_DEV_ENC, + CAM_JPEG_DEV_DMA, +}; + +struct cam_jpeg_set_irq_cb { + int32_t (*jpeg_hw_mgr_cb)(uint32_t irq_status, + int32_t result_size, void *data); + void *data; + uint32_t b_set_cb; +}; + +enum cam_jpeg_cmd_type { + CAM_JPEG_CMD_CDM_CFG, + CAM_JPEG_CMD_SET_IRQ_CB, + CAM_JPEG_CMD_MAX, +}; + +#endif diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h new file mode 100644 index 000000000000..30c51f7cfcfd --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_HW_MGR_INTF_H +#define CAM_JPEG_HW_MGR_INTF_H + +#include +#include +#include + +int cam_jpeg_hw_mgr_init(struct device_node *of_node, + uint64_t *hw_mgr_hdl, int *iommu_hdl); + +#endif /* CAM_JPEG_HW_MGR_INTF_H */ diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile new file mode 100644 index 000000000000..f0162f98833a --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_dma_dev.o jpeg_dma_core.o jpeg_dma_soc.o diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c new file mode 100644 index 000000000000..31b116cc7698 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "jpeg_dma_core.h" +#include "jpeg_dma_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +int cam_jpeg_dma_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (++core_info->ref_count > 1) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ib_bw = JPEG_VOTE; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ib_bw = JPEG_VOTE; + + + rc = cam_cpas_start(core_info->cpas_handle, + &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_JPEG, "cpass start failed: %d", rc); + goto cpas_failed; + } + + rc = cam_jpeg_dma_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc); + goto soc_failed; + } + + mutex_unlock(&core_info->core_mutex); + + return 0; + +soc_failed: + cam_cpas_stop(core_info->cpas_handle); +cpas_failed: + --core_info->ref_count; + mutex_unlock(&core_info->core_mutex); + + return rc; +} + +int cam_jpeg_dma_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (--core_info->ref_count > 0) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + if (core_info->ref_count < 0) { + CAM_ERR(CAM_JPEG, "ref cnt %d", core_info->ref_count); + core_info->ref_count = 0; + mutex_unlock(&core_info->core_mutex); + return -EFAULT; + } + + rc = cam_jpeg_dma_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "soc enable failed %d", rc); + + rc = cam_cpas_stop(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas stop failed: %d", rc); + + mutex_unlock(&core_info->core_mutex); + + return 0; +} + +int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = device_priv; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_JPEG_CMD_MAX) { + CAM_ERR(CAM_JPEG, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + + switch (cmd_type) { + case CAM_JPEG_CMD_SET_IRQ_CB: + { + struct cam_jpeg_set_irq_cb *irq_cb = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_JPEG, "cmd args NULL"); + return -EINVAL; + } + if (irq_cb->b_set_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb = + irq_cb->jpeg_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + } else { + core_info->irq_cb.jpeg_hw_mgr_cb = NULL; + core_info->irq_cb.data = NULL; + } + rc = 0; + break; + } + default: + rc = -EINVAL; + break; + } + + return rc; +} + +irqreturn_t cam_jpeg_dma_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h new file mode 100644 index 000000000000..dc3a1c13fe82 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_DMA_CORE_H +#define CAM_JPEG_DMA_CORE_H + +#include +#include +#include +#include + +#include "cam_jpeg_hw_intf.h" + +struct cam_jpeg_dma_device_hw_info { + uint32_t reserved; +}; + +enum cam_jpeg_dma_core_state { + CAM_JPEG_DMA_CORE_NOT_READY, + CAM_JPEG_DMA_CORE_READY, + CAM_JPEG_DMA_CORE_RESETTING, + CAM_JPEG_DMA_CORE_STATE_MAX, +}; + +struct cam_jpeg_dma_device_core_info { + enum cam_jpeg_dma_core_state core_state; + struct cam_jpeg_dma_device_hw_info *jpeg_dma_hw_info; + uint32_t cpas_handle; + struct cam_jpeg_set_irq_cb irq_cb; + int32_t ref_count; + struct mutex core_mutex; +}; + +int cam_jpeg_dma_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_dma_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_jpeg_dma_irq(int irq_num, void *data); + +#endif /* CAM_JPEG_DMA_CORE_H */ diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c new file mode 100644 index 000000000000..ce82c5e799c5 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "jpeg_dma_core.h" +#include "jpeg_dma_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static struct cam_jpeg_dma_device_hw_info cam_jpeg_dma_hw_info = { + .reserved = 0, +}; +EXPORT_SYMBOL(cam_jpeg_dma_hw_info); + +static int cam_jpeg_dma_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_jpeg_dma_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = soc_info->dev; + memcpy(cpas_register_params.identifier, "jpeg-dma", + sizeof("jpeg-dma")); + cpas_register_params.cam_cpas_client_cb = NULL; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc) { + CAM_ERR(CAM_JPEG, "cpas_register failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +static int cam_jpeg_dma_unregister_cpas( + struct cam_jpeg_dma_device_core_info *core_info) +{ + int rc; + + rc = cam_cpas_unregister_client(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas unregister failed: %d", rc); + core_info->cpas_handle = 0; + + return rc; +} + +static int cam_jpeg_dma_remove(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_dma_dev = NULL; + struct cam_hw_intf *jpeg_dma_dev_intf = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + int rc; + + jpeg_dma_dev_intf = platform_get_drvdata(pdev); + if (!jpeg_dma_dev_intf) { + CAM_ERR(CAM_JPEG, "error No data in pdev"); + return -EINVAL; + } + + jpeg_dma_dev = jpeg_dma_dev_intf->hw_priv; + if (!jpeg_dma_dev) { + CAM_ERR(CAM_JPEG, "error HW data is NULL"); + rc = -ENODEV; + goto free_jpeg_hw_intf; + } + + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + if (!core_info) { + CAM_ERR(CAM_JPEG, "error core data NULL"); + goto deinit_soc; + } + + rc = cam_jpeg_dma_unregister_cpas(core_info); + if (rc) + CAM_ERR(CAM_JPEG, " unreg failed to reg cpas %d", rc); + + mutex_destroy(&core_info->core_mutex); + kfree(core_info); + +deinit_soc: + rc = cam_soc_util_release_platform_resource(&jpeg_dma_dev->soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&jpeg_dma_dev->hw_mutex); + kfree(jpeg_dma_dev); + +free_jpeg_hw_intf: + kfree(jpeg_dma_dev_intf); + return rc; +} + +static int cam_jpeg_dma_probe(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_dma_dev = NULL; + struct cam_hw_intf *jpeg_dma_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + struct cam_jpeg_dma_device_hw_info *hw_info = NULL; + int rc; + + jpeg_dma_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!jpeg_dma_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &jpeg_dma_dev_intf->hw_idx); + + jpeg_dma_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!jpeg_dma_dev) { + rc = -ENOMEM; + goto error_alloc_dev; + } + jpeg_dma_dev->soc_info.pdev = pdev; + jpeg_dma_dev->soc_info.dev = &pdev->dev; + jpeg_dma_dev->soc_info.dev_name = pdev->name; + jpeg_dma_dev_intf->hw_priv = jpeg_dma_dev; + jpeg_dma_dev_intf->hw_ops.init = cam_jpeg_dma_init_hw; + jpeg_dma_dev_intf->hw_ops.deinit = cam_jpeg_dma_deinit_hw; + jpeg_dma_dev_intf->hw_ops.process_cmd = cam_jpeg_dma_process_cmd; + jpeg_dma_dev_intf->hw_type = CAM_JPEG_DEV_DMA; + + platform_set_drvdata(pdev, jpeg_dma_dev_intf); + jpeg_dma_dev->core_info = + kzalloc(sizeof(struct cam_jpeg_dma_device_core_info), + GFP_KERNEL); + if (!jpeg_dma_dev->core_info) { + rc = -ENOMEM; + goto error_alloc_core; + } + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_JPEG, " No jpeg_dma hardware info"); + rc = -EINVAL; + goto error_match_dev; + } + hw_info = (struct cam_jpeg_dma_device_hw_info *)match_dev->data; + core_info->jpeg_dma_hw_info = hw_info; + core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY; + mutex_init(&core_info->core_mutex); + + rc = cam_jpeg_dma_init_soc_resources(&jpeg_dma_dev->soc_info, + cam_jpeg_dma_irq, + jpeg_dma_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "failed to init_soc %d", rc); + goto error_init_soc; + } + + rc = cam_jpeg_dma_register_cpas(&jpeg_dma_dev->soc_info, + core_info, jpeg_dma_dev_intf->hw_idx); + if (rc) { + CAM_ERR(CAM_JPEG, " failed to reg cpas %d", rc); + goto error_reg_cpas; + } + jpeg_dma_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&jpeg_dma_dev->hw_mutex); + spin_lock_init(&jpeg_dma_dev->hw_lock); + init_completion(&jpeg_dma_dev->hw_complete); + + CAM_DBG(CAM_JPEG, " hwidx %d", jpeg_dma_dev_intf->hw_idx); + + return rc; + +error_reg_cpas: + rc = cam_soc_util_release_platform_resource(&jpeg_dma_dev->soc_info); +error_init_soc: + mutex_destroy(&core_info->core_mutex); +error_match_dev: + kfree(jpeg_dma_dev->core_info); +error_alloc_core: + kfree(jpeg_dma_dev); +error_alloc_dev: + kfree(jpeg_dma_dev_intf); + return rc; +} + +static const struct of_device_id cam_jpeg_dma_dt_match[] = { + { + .compatible = "qcom,cam_jpeg_dma", + .data = &cam_jpeg_dma_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_jpeg_dma_dt_match); + +static struct platform_driver cam_jpeg_dma_driver = { + .probe = cam_jpeg_dma_probe, + .remove = cam_jpeg_dma_remove, + .driver = { + .name = "cam-jpeg-dma", + .owner = THIS_MODULE, + .of_match_table = cam_jpeg_dma_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_jpeg_dma_init_module(void) +{ + return platform_driver_register(&cam_jpeg_dma_driver); +} + +static void __exit cam_jpeg_dma_exit_module(void) +{ + platform_driver_unregister(&cam_jpeg_dma_driver); +} + +module_init(cam_jpeg_dma_init_module); +module_exit(cam_jpeg_dma_exit_module); +MODULE_DESCRIPTION("CAM JPEG_DMA driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c new file mode 100644 index 000000000000..9dda8f284c35 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "jpeg_dma_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +int cam_jpeg_dma_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_dma_irq_handler, void *irq_data) +{ + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_request_platform_resource(soc_info, + jpeg_dma_irq_handler, + irq_data); + if (rc) + CAM_ERR(CAM_JPEG, "init soc failed %d", rc); + + return rc; +} + +int cam_jpeg_dma_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) + CAM_ERR(CAM_JPEG, "enable platform failed %d", rc); + + return rc; +} + +int cam_jpeg_dma_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_JPEG, "disable platform failed %d", rc); + + return rc; +} diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h new file mode 100644 index 000000000000..a0c07489ee77 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_DMA_SOC_H_ +#define _CAM_JPEG_DMA_SOC_H_ + +#include "cam_soc_util.h" + +int cam_jpeg_dma_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_dma_irq_handler, void *irq_data); + +int cam_jpeg_dma_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_jpeg_dma_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_JPEG_DMA_SOC_H_*/ diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile new file mode 100644 index 000000000000..159c54bbed0c --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_enc_dev.o jpeg_enc_core.o jpeg_enc_soc.o diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h new file mode 100644 index 000000000000..79b0805d0348 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_ENC_HW_INFO_TITAN170_H +#define CAM_JPEG_ENC_HW_INFO_TITAN170_H + +#define CAM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 +#define CAM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 + +#define CAM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000 +#define CAM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a + +#define CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_MASK 0x8000000 +#define CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_SHIFT 0x0000001b + +#define CAM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800 +#define CAM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b + +#define CAM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26) +#define CAM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29) + +#define CAM_JPEG_HW_MASK_COMP_FRAMEDONE \ + CAM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK +#define CAM_JPEG_HW_MASK_COMP_RESET_ACK \ + CAM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK +#define CAM_JPEG_HW_MASK_COMP_ERR \ + (CAM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \ + CAM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK) + +static struct cam_jpeg_enc_device_hw_info cam_jpeg_enc_hw_info = { + .reg_offset = { + .hw_version = 0x0, + .int_clr = 0x1c, + .int_status = 0x20, + .int_mask = 0x18, + .hw_cmd = 0x10, + .reset_cmd = 0x8, + .encode_size = 0x180, + }, + .reg_val = { + .int_clr_clearall = 0xFFFFFFFF, + .int_mask_disable_all = 0x00000000, + .int_mask_enable_all = 0xFFFFFFFF, + .hw_cmd_start = 0x00000001, + .reset_cmd = 0x00032093, + .hw_cmd_stop = 0x00000002, + }, + .int_status = { + .framedone = CAM_JPEG_HW_MASK_COMP_FRAMEDONE, + .resetdone = CAM_JPEG_HW_MASK_COMP_RESET_ACK, + .iserror = CAM_JPEG_HW_MASK_COMP_ERR, + .stopdone = CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_MASK, + } +}; + +#endif /* CAM_JPEG_ENC_HW_INFO_TITAN170_H */ diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c new file mode 100644 index 000000000000..0b7bb7386553 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "jpeg_enc_core.h" +#include "jpeg_enc_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +#define CAM_JPEG_HW_IRQ_IS_FRAME_DONE(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.framedone) +#define CAM_JPEG_HW_IRQ_IS_RESET_ACK(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.resetdone) +#define CAM_JPEG_HW_IRQ_IS_ERR(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.iserror) +#define CAM_JPEG_HW_IRQ_IS_STOP_DONE(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.stopdone) + +#define CAM_JPEG_ENC_RESET_TIMEOUT msecs_to_jiffies(500) + +int cam_jpeg_enc_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (++core_info->ref_count > 1) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ib_bw = JPEG_VOTE; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ib_bw = JPEG_VOTE; + + + rc = cam_cpas_start(core_info->cpas_handle, + &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_JPEG, "cpass start failed: %d", rc); + goto cpas_failed; + } + + rc = cam_jpeg_enc_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc); + goto soc_failed; + } + + mutex_unlock(&core_info->core_mutex); + + return 0; + +soc_failed: + cam_cpas_stop(core_info->cpas_handle); +cpas_failed: + --core_info->ref_count; + mutex_unlock(&core_info->core_mutex); + + return rc; +} + +int cam_jpeg_enc_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (--core_info->ref_count > 0) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + if (core_info->ref_count < 0) { + CAM_ERR(CAM_JPEG, "ref cnt %d", core_info->ref_count); + core_info->ref_count = 0; + mutex_unlock(&core_info->core_mutex); + return -EFAULT; + } + + rc = cam_jpeg_enc_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "soc disable failed %d", rc); + + rc = cam_cpas_stop(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas stop failed: %d", rc); + + mutex_unlock(&core_info->core_mutex); + + return 0; +} + +irqreturn_t cam_jpeg_enc_irq(int irq_num, void *data) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + uint32_t irq_status = 0; + uint32_t encoded_size = 0; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return IRQ_HANDLED; + } + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + irq_status = cam_io_r_mb(mem_base + + core_info->jpeg_enc_hw_info->reg_offset.int_status); + + cam_io_w_mb(irq_status, + soc_info->reg_map[0].mem_base + + core_info->jpeg_enc_hw_info->reg_offset.int_clr); + + CAM_DBG(CAM_JPEG, "irq_num %d irq_status = %x , core_state %d", + irq_num, irq_status, core_info->core_state); + + if (CAM_JPEG_HW_IRQ_IS_FRAME_DONE(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_READY) { + encoded_size = cam_io_r_mb(mem_base + + core_info->jpeg_enc_hw_info->reg_offset.encode_size); + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + encoded_size, + core_info->irq_cb.data); + } else { + CAM_ERR(CAM_JPEG, "unexpected done, no cb"); + } + } else { + CAM_ERR(CAM_JPEG, "unexpected done irq"); + } + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + spin_unlock(&jpeg_enc_dev->hw_lock); + } + if (CAM_JPEG_HW_IRQ_IS_RESET_ACK(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) { + core_info->core_state = CAM_JPEG_ENC_CORE_READY; + complete(&jpeg_enc_dev->hw_complete); + } else { + CAM_ERR(CAM_JPEG, "unexpected reset irq"); + } + spin_unlock(&jpeg_enc_dev->hw_lock); + } + if (CAM_JPEG_HW_IRQ_IS_STOP_DONE(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + complete(&jpeg_enc_dev->hw_complete); + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + -1, + core_info->irq_cb.data); + } + } else { + CAM_ERR(CAM_JPEG, "unexpected abort irq"); + } + spin_unlock(&jpeg_enc_dev->hw_lock); + } + /* Unexpected/unintended HW interrupt */ + if (CAM_JPEG_HW_IRQ_IS_ERR(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + CAM_ERR_RATE_LIMIT(CAM_JPEG, + "error irq_num %d irq_status = %x , core_state %d", + irq_num, irq_status, core_info->core_state); + + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + -1, + core_info->irq_cb.data); + } + spin_unlock(&jpeg_enc_dev->hw_lock); + } + + return IRQ_HANDLED; +} + +int cam_jpeg_enc_reset_hw(void *data, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + unsigned long rem_jiffies; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + /* maskdisable.clrirq.maskenable.resetcmd */ + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + mutex_lock(&core_info->core_mutex); + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) { + CAM_ERR(CAM_JPEG, "alrady resetting"); + spin_unlock(&jpeg_enc_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return 0; + } + + reinit_completion(&jpeg_enc_dev->hw_complete); + core_info->core_state = CAM_JPEG_ENC_CORE_RESETTING; + spin_unlock(&jpeg_enc_dev->hw_lock); + + cam_io_w_mb(hw_info->reg_val.int_mask_disable_all, + mem_base + hw_info->reg_offset.int_mask); + cam_io_w_mb(hw_info->reg_val.int_clr_clearall, + mem_base + hw_info->reg_offset.int_clr); + cam_io_w_mb(hw_info->reg_val.int_mask_enable_all, + mem_base + hw_info->reg_offset.int_mask); + cam_io_w_mb(hw_info->reg_val.reset_cmd, + mem_base + hw_info->reg_offset.reset_cmd); + + rem_jiffies = wait_for_completion_timeout(&jpeg_enc_dev->hw_complete, + CAM_JPEG_ENC_RESET_TIMEOUT); + if (!rem_jiffies) { + CAM_ERR(CAM_JPEG, "error Reset Timeout"); + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + } + + mutex_unlock(&core_info->core_mutex); + return 0; +} + +int cam_jpeg_enc_start_hw(void *data, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) { + CAM_ERR(CAM_JPEG, "Error not ready"); + return -EINVAL; + } + + cam_io_w_mb(hw_info->reg_val.hw_cmd_start, + mem_base + hw_info->reg_offset.hw_cmd); + + return 0; +} + +int cam_jpeg_enc_stop_hw(void *data, + void *stop_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + unsigned long rem_jiffies; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + mutex_lock(&core_info->core_mutex); + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { + CAM_ERR(CAM_JPEG, "alrady stopping"); + spin_unlock(&jpeg_enc_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return 0; + } + + reinit_completion(&jpeg_enc_dev->hw_complete); + core_info->core_state = CAM_JPEG_ENC_CORE_ABORTING; + spin_unlock(&jpeg_enc_dev->hw_lock); + + cam_io_w_mb(hw_info->reg_val.hw_cmd_stop, + mem_base + hw_info->reg_offset.hw_cmd); + + rem_jiffies = wait_for_completion_timeout(&jpeg_enc_dev->hw_complete, + CAM_JPEG_ENC_RESET_TIMEOUT); + if (!rem_jiffies) { + CAM_ERR(CAM_JPEG, "error Reset Timeout"); + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + } + + mutex_unlock(&core_info->core_mutex); + return 0; +} + +int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = device_priv; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_JPEG_CMD_MAX) { + CAM_ERR(CAM_JPEG, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + + switch (cmd_type) { + case CAM_JPEG_CMD_SET_IRQ_CB: + { + struct cam_jpeg_set_irq_cb *irq_cb = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_JPEG, "cmd args NULL"); + return -EINVAL; + } + if (irq_cb->b_set_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb = + irq_cb->jpeg_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + } else { + core_info->irq_cb.jpeg_hw_mgr_cb = NULL; + core_info->irq_cb.data = NULL; + } + rc = 0; + break; + } + default: + rc = -EINVAL; + break; + } + if (rc) + CAM_ERR(CAM_JPEG, "error cmdtype %d rc = %d", cmd_type, rc); + return rc; +} diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h new file mode 100644 index 000000000000..df9341c90c77 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_ENC_CORE_H +#define CAM_JPEG_ENC_CORE_H + +#include +#include +#include +#include + +#include "cam_jpeg_hw_intf.h" + +struct cam_jpeg_enc_reg_offsets { + uint32_t hw_version; + uint32_t int_status; + uint32_t int_clr; + uint32_t int_mask; + uint32_t hw_cmd; + uint32_t reset_cmd; + uint32_t encode_size; +}; + +struct cam_jpeg_enc_regval { + uint32_t int_clr_clearall; + uint32_t int_mask_disable_all; + uint32_t int_mask_enable_all; + uint32_t hw_cmd_start; + uint32_t reset_cmd; + uint32_t hw_cmd_stop; +}; + +struct cam_jpeg_enc_int_status { + uint32_t framedone; + uint32_t resetdone; + uint32_t iserror; + uint32_t stopdone; +}; + +struct cam_jpeg_enc_device_hw_info { + struct cam_jpeg_enc_reg_offsets reg_offset; + struct cam_jpeg_enc_regval reg_val; + struct cam_jpeg_enc_int_status int_status; +}; + +enum cam_jpeg_enc_core_state { + CAM_JPEG_ENC_CORE_NOT_READY, + CAM_JPEG_ENC_CORE_READY, + CAM_JPEG_ENC_CORE_RESETTING, + CAM_JPEG_ENC_CORE_ABORTING, + CAM_JPEG_ENC_CORE_STATE_MAX, +}; + +struct cam_jpeg_enc_device_core_info { + enum cam_jpeg_enc_core_state core_state; + struct cam_jpeg_enc_device_hw_info *jpeg_enc_hw_info; + uint32_t cpas_handle; + struct cam_jpeg_set_irq_cb irq_cb; + int32_t ref_count; + struct mutex core_mutex; +}; + +int cam_jpeg_enc_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_enc_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_enc_start_hw(void *device_priv, + void *start_hw_args, uint32_t arg_size); +int cam_jpeg_enc_stop_hw(void *device_priv, + void *stop_hw_args, uint32_t arg_size); +int cam_jpeg_enc_reset_hw(void *device_priv, + void *reset_hw_args, uint32_t arg_size); +int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_jpeg_enc_irq(int irq_num, void *data); + +#endif /* CAM_JPEG_ENC_CORE_H */ diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c new file mode 100644 index 000000000000..8eb8ec367850 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "jpeg_enc_core.h" +#include "jpeg_enc_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "cam_jpeg_enc_hw_info_ver_4_2_0.h" + +static int cam_jpeg_enc_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_jpeg_enc_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = soc_info->dev; + memcpy(cpas_register_params.identifier, "jpeg-enc", + sizeof("jpeg-enc")); + cpas_register_params.cam_cpas_client_cb = NULL; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc) { + CAM_ERR(CAM_JPEG, "cpas_register failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +static int cam_jpeg_enc_unregister_cpas( + struct cam_jpeg_enc_device_core_info *core_info) +{ + int rc; + + rc = cam_cpas_unregister_client(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas unregister failed: %d", rc); + core_info->cpas_handle = 0; + + return rc; +} + +static int cam_jpeg_enc_remove(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_enc_dev = NULL; + struct cam_hw_intf *jpeg_enc_dev_intf = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + int rc; + + jpeg_enc_dev_intf = platform_get_drvdata(pdev); + if (!jpeg_enc_dev_intf) { + CAM_ERR(CAM_JPEG, "error No data in pdev"); + return -EINVAL; + } + + jpeg_enc_dev = jpeg_enc_dev_intf->hw_priv; + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "error HW data is NULL"); + rc = -ENODEV; + goto free_jpeg_hw_intf; + } + + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + if (!core_info) { + CAM_ERR(CAM_JPEG, "error core data NULL"); + goto deinit_soc; + } + + rc = cam_jpeg_enc_unregister_cpas(core_info); + if (rc) + CAM_ERR(CAM_JPEG, " unreg failed to reg cpas %d", rc); + + mutex_destroy(&core_info->core_mutex); + kfree(core_info); + +deinit_soc: + rc = cam_soc_util_release_platform_resource(&jpeg_enc_dev->soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&jpeg_enc_dev->hw_mutex); + kfree(jpeg_enc_dev); + +free_jpeg_hw_intf: + kfree(jpeg_enc_dev_intf); + return rc; +} + +static int cam_jpeg_enc_probe(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_enc_dev = NULL; + struct cam_hw_intf *jpeg_enc_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + int rc; + + jpeg_enc_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!jpeg_enc_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &jpeg_enc_dev_intf->hw_idx); + + jpeg_enc_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!jpeg_enc_dev) { + rc = -ENOMEM; + goto error_alloc_dev; + } + jpeg_enc_dev->soc_info.pdev = pdev; + jpeg_enc_dev->soc_info.dev = &pdev->dev; + jpeg_enc_dev->soc_info.dev_name = pdev->name; + jpeg_enc_dev_intf->hw_priv = jpeg_enc_dev; + jpeg_enc_dev_intf->hw_ops.init = cam_jpeg_enc_init_hw; + jpeg_enc_dev_intf->hw_ops.deinit = cam_jpeg_enc_deinit_hw; + jpeg_enc_dev_intf->hw_ops.start = cam_jpeg_enc_start_hw; + jpeg_enc_dev_intf->hw_ops.stop = cam_jpeg_enc_stop_hw; + jpeg_enc_dev_intf->hw_ops.reset = cam_jpeg_enc_reset_hw; + jpeg_enc_dev_intf->hw_ops.process_cmd = cam_jpeg_enc_process_cmd; + jpeg_enc_dev_intf->hw_type = CAM_JPEG_DEV_ENC; + + platform_set_drvdata(pdev, jpeg_enc_dev_intf); + jpeg_enc_dev->core_info = + kzalloc(sizeof(struct cam_jpeg_enc_device_core_info), + GFP_KERNEL); + if (!jpeg_enc_dev->core_info) { + rc = -ENOMEM; + goto error_alloc_core; + } + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_JPEG, " No jpeg_enc hardware info"); + rc = -EINVAL; + goto error_match_dev; + } + hw_info = (struct cam_jpeg_enc_device_hw_info *)match_dev->data; + core_info->jpeg_enc_hw_info = hw_info; + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + mutex_init(&core_info->core_mutex); + + rc = cam_jpeg_enc_init_soc_resources(&jpeg_enc_dev->soc_info, + cam_jpeg_enc_irq, + jpeg_enc_dev); + if (rc) { + CAM_ERR(CAM_JPEG, " failed to init_soc %d", rc); + goto error_init_soc; + } + + rc = cam_jpeg_enc_register_cpas(&jpeg_enc_dev->soc_info, + core_info, jpeg_enc_dev_intf->hw_idx); + if (rc) { + CAM_ERR(CAM_JPEG, " failed to reg cpas %d", rc); + goto error_reg_cpas; + } + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&jpeg_enc_dev->hw_mutex); + spin_lock_init(&jpeg_enc_dev->hw_lock); + init_completion(&jpeg_enc_dev->hw_complete); + + return rc; + +error_reg_cpas: + cam_soc_util_release_platform_resource(&jpeg_enc_dev->soc_info); +error_init_soc: + mutex_destroy(&core_info->core_mutex); +error_match_dev: + kfree(jpeg_enc_dev->core_info); +error_alloc_core: + kfree(jpeg_enc_dev); +error_alloc_dev: + kfree(jpeg_enc_dev_intf); + + return rc; +} + +static const struct of_device_id cam_jpeg_enc_dt_match[] = { + { + .compatible = "qcom,cam_jpeg_enc", + .data = &cam_jpeg_enc_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_jpeg_enc_dt_match); + +static struct platform_driver cam_jpeg_enc_driver = { + .probe = cam_jpeg_enc_probe, + .remove = cam_jpeg_enc_remove, + .driver = { + .name = "cam-jpeg-enc", + .owner = THIS_MODULE, + .of_match_table = cam_jpeg_enc_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_jpeg_enc_init_module(void) +{ + return platform_driver_register(&cam_jpeg_enc_driver); +} + +static void __exit cam_jpeg_enc_exit_module(void) +{ + platform_driver_unregister(&cam_jpeg_enc_driver); +} + +module_init(cam_jpeg_enc_init_module); +module_exit(cam_jpeg_enc_exit_module); +MODULE_DESCRIPTION("CAM JPEG_ENC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c new file mode 100644 index 000000000000..4a5d9e0a9b60 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "jpeg_enc_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +int cam_jpeg_enc_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_enc_irq_handler, void *irq_data) +{ + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_request_platform_resource(soc_info, + jpeg_enc_irq_handler, + irq_data); + if (rc) + CAM_ERR(CAM_JPEG, "init soc failed %d", rc); + + return rc; +} + +int cam_jpeg_enc_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) + CAM_ERR(CAM_JPEG, "enable platform failed %d", rc); + + return rc; +} + +int cam_jpeg_enc_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_JPEG, "disable platform failed %d", rc); + + return rc; +} diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h new file mode 100644 index 000000000000..e0fb0103de75 --- /dev/null +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_ENC_SOC_H_ +#define _CAM_JPEG_ENC_SOC_H_ + +#include "cam_soc_util.h" + +int cam_jpeg_enc_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_enc_irq_handler, void *irq_data); + +int cam_jpeg_enc_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_jpeg_enc_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_JPEG_ENC_SOC_H_*/ diff --git a/drivers/cam_lrme/Makefile b/drivers/cam_lrme/Makefile new file mode 100644 index 000000000000..afc585ebf374 --- /dev/null +++ b/drivers/cam_lrme/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include/ + +obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_dev.o cam_lrme_context.o diff --git a/drivers/cam_lrme/cam_lrme_context.c b/drivers/cam_lrme/cam_lrme_context.c new file mode 100644 index 000000000000..3270d77af5fe --- /dev/null +++ b/drivers/cam_lrme/cam_lrme_context.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include + +#include "cam_debug_util.h" +#include "cam_lrme_context.h" + +static const char lrme_dev_name[] = "lrme"; + +static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc = 0; + uintptr_t ctxt_to_hw_map = (uintptr_t)ctx->ctxt_to_hw_map; + struct cam_lrme_context *lrme_ctx = ctx->ctx_priv; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to acquire"); + return rc; + } + + ctxt_to_hw_map |= (lrme_ctx->index << CAM_LRME_CTX_INDEX_SHIFT); + ctx->ctxt_to_hw_map = (void *)ctxt_to_hw_map; + + ctx->state = CAM_CTX_ACQUIRED; + + return rc; +} + +static int __cam_lrme_ctx_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to release"); + return rc; + } + + ctx->state = CAM_CTX_AVAILABLE; + + return rc; +} + +static int __cam_lrme_ctx_start_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_start_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to start"); + return rc; + } + + ctx->state = CAM_CTX_ACTIVATED; + + return rc; +} + +static int __cam_lrme_ctx_config_dev_in_activated(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to config"); + return rc; + } + + return rc; +} + +static int __cam_lrme_ctx_flush_dev_in_activated(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_LRME, "Failed to flush device"); + + return rc; +} +static int __cam_lrme_ctx_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to stop dev"); + return rc; + } + + ctx->state = CAM_CTX_ACQUIRED; + + return rc; +} + +static int __cam_lrme_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = __cam_lrme_ctx_stop_dev_in_activated(ctx, NULL); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to stop"); + return rc; + } + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to release"); + return rc; + } + + ctx->state = CAM_CTX_AVAILABLE; + + return rc; +} + +static int __cam_lrme_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc; + + CAM_DBG(CAM_LRME, "Enter"); + + rc = cam_context_buf_done_from_hw(context, evt_data, evt_id); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in buf done, rc=%d", rc); + return rc; + } + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_lrme_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .config_dev = __cam_lrme_ctx_config_dev_in_activated, + .release_dev = __cam_lrme_ctx_release_dev_in_acquired, + .start_dev = __cam_lrme_ctx_start_dev_in_acquired, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Ready */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Activate */ + { + .ioctl_ops = { + .config_dev = __cam_lrme_ctx_config_dev_in_activated, + .release_dev = __cam_lrme_ctx_release_dev_in_activated, + .stop_dev = __cam_lrme_ctx_stop_dev_in_activated, + .flush_dev = __cam_lrme_ctx_flush_dev_in_activated, + }, + .crm_ops = {}, + .irq_ops = __cam_lrme_ctx_handle_irq_in_activated, + }, +}; + +int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx, + struct cam_context *base_ctx, + struct cam_hw_mgr_intf *hw_intf, + uint32_t index) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter"); + + if (!base_ctx || !lrme_ctx) { + CAM_ERR(CAM_LRME, "Invalid input"); + return -EINVAL; + } + + memset(lrme_ctx, 0, sizeof(*lrme_ctx)); + + rc = cam_context_init(base_ctx, lrme_dev_name, CAM_LRME, index, + NULL, hw_intf, lrme_ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to init context"); + return rc; + } + lrme_ctx->base = base_ctx; + lrme_ctx->index = index; + base_ctx->ctx_priv = lrme_ctx; + base_ctx->state_machine = cam_lrme_ctx_state_machine; + + return rc; +} + +int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter"); + + if (!lrme_ctx) { + CAM_ERR(CAM_LRME, "No ctx to deinit"); + return -EINVAL; + } + + rc = cam_context_deinit(lrme_ctx->base); + + memset(lrme_ctx, 0, sizeof(*lrme_ctx)); + return rc; +} diff --git a/drivers/cam_lrme/cam_lrme_context.h b/drivers/cam_lrme/cam_lrme_context.h new file mode 100644 index 000000000000..8dfdc36501a9 --- /dev/null +++ b/drivers/cam_lrme/cam_lrme_context.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_CONTEXT_H_ +#define _CAM_LRME_CONTEXT_H_ + +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_interface.h" + +#define CAM_LRME_CTX_INDEX_SHIFT 32 + +/** + * struct cam_lrme_context + * + * @base : Base context pointer for this LRME context + * @req_base : List of base request for this LRME context + */ +struct cam_lrme_context { + struct cam_context *base; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + uint64_t index; +}; + +int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx, + struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf, + uint32_t index); +int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx); + +#endif /* _CAM_LRME_CONTEXT_H_ */ diff --git a/drivers/cam_lrme/cam_lrme_dev.c b/drivers/cam_lrme/cam_lrme_dev.c new file mode 100644 index 000000000000..7c09f2b435f5 --- /dev/null +++ b/drivers/cam_lrme/cam_lrme_dev.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_lrme_context.h" +#include "cam_lrme_hw_mgr.h" +#include "cam_lrme_hw_mgr_intf.h" + +#define CAM_LRME_DEV_NAME "cam-lrme" + +/** + * struct cam_lrme_dev + * + * @sd : Subdev information + * @ctx : List of base contexts + * @lrme_ctx : List of LRME contexts + * @lock : Mutex for LRME subdev + * @open_cnt : Open count of LRME subdev + */ +struct cam_lrme_dev { + struct cam_subdev sd; + struct cam_context ctx[CAM_CTX_MAX]; + struct cam_lrme_context lrme_ctx[CAM_CTX_MAX]; + struct mutex lock; + uint32_t open_cnt; +}; + +static struct cam_lrme_dev *g_lrme_dev; + +static int cam_lrme_dev_buf_done_cb(void *ctxt_to_hw_map, uint32_t evt_id, + void *evt_data) +{ + uint64_t index; + struct cam_context *ctx; + int rc; + + index = CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map); + CAM_DBG(CAM_LRME, "ctx index %llu, evt_id %u\n", index, evt_id); + ctx = &g_lrme_dev->ctx[index]; + rc = ctx->irq_cb_intf(ctx, evt_id, evt_data); + if (rc) + CAM_ERR(CAM_LRME, "irq callback failed"); + + return rc; +} + +static int cam_lrme_dev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_lrme_dev *lrme_dev = g_lrme_dev; + + if (!lrme_dev) { + CAM_ERR(CAM_LRME, + "LRME Dev not initialized, dev=%pK", lrme_dev); + return -ENODEV; + } + + mutex_lock(&lrme_dev->lock); + lrme_dev->open_cnt++; + mutex_unlock(&lrme_dev->lock); + + return 0; +} + +static int cam_lrme_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_lrme_dev *lrme_dev = g_lrme_dev; + struct cam_node *node = v4l2_get_subdevdata(sd); + + if (!lrme_dev) { + CAM_ERR(CAM_LRME, "Invalid args"); + return -ENODEV; + } + + mutex_lock(&lrme_dev->lock); + if (lrme_dev->open_cnt <= 0) { + CAM_DBG(CAM_LRME, "LRME subdev is already closed"); + rc = -EINVAL; + goto end; + } + + lrme_dev->open_cnt--; + if (!node) { + CAM_ERR(CAM_LRME, "Node is NULL"); + rc = -EINVAL; + goto end; + } + + if (lrme_dev->open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&lrme_dev->lock); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = { + .open = cam_lrme_dev_open, + .close = cam_lrme_dev_close, +}; + +static int cam_lrme_dev_probe(struct platform_device *pdev) +{ + int rc; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + + g_lrme_dev = kzalloc(sizeof(struct cam_lrme_dev), GFP_KERNEL); + if (!g_lrme_dev) { + CAM_ERR(CAM_LRME, "No memory"); + return -ENOMEM; + } + g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops; + + mutex_init(&g_lrme_dev->lock); + + rc = cam_subdev_probe(&g_lrme_dev->sd, pdev, CAM_LRME_DEV_NAME, + CAM_LRME_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_LRME, "LRME cam_subdev_probe failed"); + goto free_mem; + } + node = (struct cam_node *)g_lrme_dev->sd.token; + + rc = cam_lrme_hw_mgr_init(&hw_mgr_intf, cam_lrme_dev_buf_done_cb); + if (rc) { + CAM_ERR(CAM_LRME, "Can not initialized LRME HW manager"); + goto unregister; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_lrme_context_init(&g_lrme_dev->lrme_ctx[i], + &g_lrme_dev->ctx[i], + &node->hw_mgr_intf, i); + if (rc) { + CAM_ERR(CAM_LRME, "LRME context init failed"); + goto deinit_ctx; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_lrme_dev->ctx, CAM_CTX_MAX, + CAM_LRME_DEV_NAME); + if (rc) { + CAM_ERR(CAM_LRME, "LRME node init failed"); + goto deinit_ctx; + } + + CAM_DBG(CAM_LRME, "%s probe complete", g_lrme_dev->sd.name); + + return 0; + +deinit_ctx: + for (--i; i >= 0; i--) { + if (cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i])) + CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i); + } +unregister: + if (cam_subdev_remove(&g_lrme_dev->sd)) + CAM_ERR(CAM_LRME, "Failed in subdev remove"); +free_mem: + kfree(g_lrme_dev); + + return rc; +} + +static int cam_lrme_dev_remove(struct platform_device *pdev) +{ + int i; + int rc = 0; + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]); + if (rc) + CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i); + } + + rc = cam_lrme_hw_mgr_deinit(); + if (rc) + CAM_ERR(CAM_LRME, "Failed in hw mgr deinit, rc=%d", rc); + + rc = cam_subdev_remove(&g_lrme_dev->sd); + if (rc) + CAM_ERR(CAM_LRME, "Unregister failed"); + + mutex_destroy(&g_lrme_dev->lock); + kfree(g_lrme_dev); + g_lrme_dev = NULL; + + return rc; +} + +static const struct of_device_id cam_lrme_dt_match[] = { + { + .compatible = "qcom,cam-lrme" + }, + {} +}; + +static struct platform_driver cam_lrme_driver = { + .probe = cam_lrme_dev_probe, + .remove = cam_lrme_dev_remove, + .driver = { + .name = "cam_lrme", + .owner = THIS_MODULE, + .of_match_table = cam_lrme_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_lrme_dev_init_module(void) +{ + return platform_driver_register(&cam_lrme_driver); +} + +static void __exit cam_lrme_dev_exit_module(void) +{ + platform_driver_unregister(&cam_lrme_driver); +} + +module_init(cam_lrme_dev_init_module); +module_exit(cam_lrme_dev_exit_module); +MODULE_DESCRIPTION("MSM LRME driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_lrme/lrme_hw_mgr/Makefile b/drivers/cam_lrme/lrme_hw_mgr/Makefile new file mode 100644 index 000000000000..3387c3d0f062 --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -I$(srctree)/techpack/camera +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_mgr.o diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c new file mode 100644 index 000000000000..90b3f3fa442a --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -0,0 +1,1155 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_mem_mgr_api.h" +#include "cam_smmu_api.h" +#include "cam_packet_util.h" +#include "cam_lrme_context.h" +#include "cam_lrme_hw_intf.h" +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" +#include "cam_lrme_hw_mgr_intf.h" +#include "cam_lrme_hw_mgr.h" + +static struct cam_lrme_hw_mgr g_lrme_hw_mgr; + +static int cam_lrme_mgr_util_reserve_device(struct cam_lrme_hw_mgr *hw_mgr, + struct cam_lrme_acquire_args *lrme_acquire_args) +{ + int i, index = 0; + uint32_t min_ctx = UINT_MAX; + struct cam_lrme_device *hw_device = NULL; + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!hw_mgr->device_count) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_LRME, "No device is registered"); + return -EINVAL; + } + + for (i = 0; i < hw_mgr->device_count && i < CAM_LRME_HW_MAX; i++) { + hw_device = &hw_mgr->hw_device[i]; + if (!hw_device->num_context) { + index = i; + break; + } + if (hw_device->num_context < min_ctx) { + min_ctx = hw_device->num_context; + index = i; + } + } + + hw_device = &hw_mgr->hw_device[index]; + hw_device->num_context++; + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_LRME, "reserve device index %d", index); + + return index; +} + +static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr, + uint32_t device_index, struct cam_lrme_device **hw_device) +{ + if (!hw_mgr) { + CAM_ERR(CAM_LRME, "invalid params hw_mgr %pK", hw_mgr); + return -EINVAL; + } + + if (device_index >= CAM_LRME_HW_MAX) { + CAM_ERR(CAM_LRME, "Wrong device index %d", device_index); + return -EINVAL; + } + + *hw_device = &hw_mgr->hw_device[device_index]; + + return 0; +} + +static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + int i, rc; + + if (!packet) { + CAM_ERR(CAM_LRME, "Invalid args"); + return -EINVAL; + } + + CAM_DBG(CAM_LRME, "Packet request=%d, op_code=0x%x, size=%d, flags=%d", + packet->header.request_id, packet->header.op_code, + packet->header.size, packet->header.flags); + CAM_DBG(CAM_LRME, + "Packet cmdbuf(offset=%d, num=%d) io(offset=%d, num=%d)", + packet->cmd_buf_offset, packet->num_cmd_buf, + packet->io_configs_offset, packet->num_io_configs); + CAM_DBG(CAM_LRME, + "Packet Patch(offset=%d, num=%d) kmd(offset=%d, num=%d)", + packet->patch_offset, packet->num_patches, + packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); + + if (cam_packet_util_validate_packet(packet, remain_len)) { + CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d", + packet->kmd_cmd_buf_index, + packet->num_cmd_buf, packet->cmd_buf_offset, + packet->io_configs_offset, packet->header.size); + return -EINVAL; + } + + if (!packet->num_io_configs) { + CAM_ERR(CAM_LRME, "no io configs"); + return -EINVAL; + } + + cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)&packet->payload + + packet->cmd_buf_offset); + + for (i = 0; i < packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + CAM_DBG(CAM_LRME, + "CmdBuf[%d] hdl=%d, offset=%d, size=%d, len=%d, type=%d, meta_data=%d", + i, + cmd_desc[i].mem_handle, cmd_desc[i].offset, + cmd_desc[i].size, cmd_desc[i].length, cmd_desc[i].type, + cmd_desc[i].meta_data); + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) { + CAM_ERR(CAM_LRME, "Invalid cmd buffer %d", i); + return rc; + } + } + + return 0; +} + +static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + struct cam_lrme_hw_io_buffer *input_buf, + struct cam_lrme_hw_io_buffer *output_buf, uint32_t io_buf_size) +{ + int rc = -EINVAL; + uint32_t num_in_buf, num_out_buf, i, j, plane; + struct cam_buf_io_cfg *io_cfg; + uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + size_t size; + + num_in_buf = 0; + num_out_buf = 0; + io_cfg = (struct cam_buf_io_cfg *)((uint8_t *) + &prepare->packet->payload + + prepare->packet->io_configs_offset); + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_LRME, + "IOConfig[%d] : handle[%d] Dir[%d] Res[%d] Fence[%d], Format[%d]", + i, io_cfg[i].mem_handle[0], io_cfg[i].direction, + io_cfg[i].resource_type, + io_cfg[i].fence, io_cfg[i].format); + + memset(io_addr, 0, sizeof(io_addr)); + for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) { + if (!io_cfg[i].mem_handle[plane]) + break; + + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[plane], + iommu_hdl, &io_addr[plane], &size); + if (rc) { + CAM_ERR(CAM_LRME, "Cannot get io buf for %d %d", + plane, rc); + return -ENOMEM; + } + + if ((size_t)io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_LRME, "Invalid plane offset: %zu", + (size_t)io_cfg[i].offsets[plane]); + return -EINVAL; + } + + io_addr[plane] += io_cfg[i].offsets[plane]; + + CAM_DBG(CAM_LRME, "IO Address[%d][%d] : %llu", + io_cfg[i].direction, plane, io_addr[plane]); + } + + switch (io_cfg[i].direction) { + case CAM_BUF_INPUT: { + if (num_in_buf >= io_buf_size) { + CAM_ERR(CAM_LRME, + "Invalid number of buffers %d %d %d", + num_in_buf, num_out_buf, io_buf_size); + return -EINVAL; + } + prepare->in_map_entries[num_in_buf].resource_handle = + io_cfg[i].resource_type; + prepare->in_map_entries[num_in_buf].sync_id = + io_cfg[i].fence; + + input_buf[num_in_buf].valid = true; + for (j = 0; j < plane; j++) + input_buf[num_in_buf].io_addr[j] = io_addr[j]; + input_buf[num_in_buf].num_plane = plane; + input_buf[num_in_buf].io_cfg = &io_cfg[i]; + + num_in_buf++; + break; + } + case CAM_BUF_OUTPUT: { + if (num_out_buf >= io_buf_size) { + CAM_ERR(CAM_LRME, + "Invalid number of buffers %d %d %d", + num_in_buf, num_out_buf, io_buf_size); + return -EINVAL; + } + prepare->out_map_entries[num_out_buf].resource_handle = + io_cfg[i].resource_type; + prepare->out_map_entries[num_out_buf].sync_id = + io_cfg[i].fence; + + output_buf[num_out_buf].valid = true; + for (j = 0; j < plane; j++) + output_buf[num_out_buf].io_addr[j] = io_addr[j]; + output_buf[num_out_buf].num_plane = plane; + output_buf[num_out_buf].io_cfg = &io_cfg[i]; + + num_out_buf++; + break; + } + default: + CAM_ERR(CAM_LRME, "Unsupported io direction %d", + io_cfg[i].direction); + return -EINVAL; + } + } + prepare->num_in_map_entries = num_in_buf; + prepare->num_out_map_entries = num_out_buf; + + return 0; +} + +static int cam_lrme_mgr_util_prepare_hw_update_entries( + struct cam_lrme_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare, + struct cam_lrme_hw_cmd_config_args *config_args, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int i, rc = 0; + struct cam_lrme_device *hw_device = NULL; + uint32_t *kmd_buf_addr; + uint32_t num_entry; + uint32_t kmd_buf_max_size; + uint32_t kmd_buf_used_bytes = 0; + struct cam_hw_update_entry *hw_entry; + struct cam_cmd_buf_desc *cmd_desc = NULL; + + hw_device = config_args->hw_device; + if (!hw_device) { + CAM_ERR(CAM_LRME, "Invalid hw_device"); + return -EINVAL; + } + + kmd_buf_addr = (uint32_t *)((uint8_t *)kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes); + kmd_buf_max_size = kmd_buf_info->size - kmd_buf_info->used_bytes; + + config_args->cmd_buf_addr = kmd_buf_addr; + config_args->size = kmd_buf_max_size; + config_args->config_buf_size = 0; + + if (hw_device->hw_intf.hw_ops.process_cmd) { + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, + config_args, + sizeof(struct cam_lrme_hw_cmd_config_args)); + if (rc) { + CAM_ERR(CAM_LRME, + "Failed in CMD_PREPARE_HW_UPDATE %d", rc); + return rc; + } + } else { + CAM_ERR(CAM_LRME, "Can't find handle function"); + return -EINVAL; + } + + kmd_buf_used_bytes += config_args->config_buf_size; + + if (!kmd_buf_used_bytes || (kmd_buf_used_bytes > kmd_buf_max_size)) { + CAM_ERR(CAM_LRME, "Invalid kmd used bytes %d (%d)", + kmd_buf_used_bytes, kmd_buf_max_size); + return -ENOMEM; + } + + hw_entry = prepare->hw_update_entries; + num_entry = 0; + + if (config_args->config_buf_size) { + if ((num_entry + 1) >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_LRME, "Insufficient HW entries :%d %d", + num_entry, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_entry].handle = kmd_buf_info->handle; + hw_entry[num_entry].len = config_args->config_buf_size; + hw_entry[num_entry].offset = kmd_buf_info->offset; + + kmd_buf_info->used_bytes += config_args->config_buf_size; + kmd_buf_info->offset += config_args->config_buf_size; + num_entry++; + } + + cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *) + &prepare->packet->payload + prepare->packet->cmd_buf_offset); + + for (i = 0; i < prepare->packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if ((num_entry + 1) >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_LRME, "Exceed max num of entry"); + return -EINVAL; + } + + hw_entry[num_entry].handle = cmd_desc[i].mem_handle; + hw_entry[num_entry].len = cmd_desc[i].length; + hw_entry[num_entry].offset = cmd_desc[i].offset; + num_entry++; + } + prepare->num_hw_update_entries = num_entry; + + CAM_DBG(CAM_LRME, "FinalConfig : hw_entries=%d, Sync(in=%d, out=%d)", + prepare->num_hw_update_entries, prepare->num_in_map_entries, + prepare->num_out_map_entries); + + return rc; +} + +static void cam_lrme_mgr_util_put_frame_req( + struct list_head *src_list, + struct list_head *list, + spinlock_t *lock) +{ + spin_lock(lock); + list_add_tail(list, src_list); + spin_unlock(lock); +} + +static int cam_lrme_mgr_util_get_frame_req( + struct list_head *src_list, + struct cam_lrme_frame_request **frame_req, + spinlock_t *lock) +{ + int rc = 0; + struct cam_lrme_frame_request *req_ptr = NULL; + + spin_lock(lock); + if (!list_empty(src_list)) { + req_ptr = list_first_entry(src_list, + struct cam_lrme_frame_request, frame_list); + list_del_init(&req_ptr->frame_list); + } else { + rc = -ENOENT; + } + *frame_req = req_ptr; + spin_unlock(lock); + + return rc; +} + + +static int cam_lrme_mgr_util_submit_req(void *priv, void *data) +{ + struct cam_lrme_device *hw_device; + struct cam_lrme_hw_mgr *hw_mgr; + struct cam_lrme_frame_request *frame_req = NULL; + struct cam_lrme_hw_submit_args submit_args; + struct cam_lrme_mgr_work_data *work_data; + int rc; + int req_prio = 0; + + if (!priv) { + CAM_ERR(CAM_LRME, "worker doesn't have private data"); + return -EINVAL; + } + + hw_mgr = (struct cam_lrme_hw_mgr *)priv; + work_data = (struct cam_lrme_mgr_work_data *)data; + hw_device = work_data->hw_device; + + rc = cam_lrme_mgr_util_get_frame_req( + &hw_device->frame_pending_list_high, &frame_req, + &hw_device->high_req_lock); + + if (!frame_req) { + rc = cam_lrme_mgr_util_get_frame_req( + &hw_device->frame_pending_list_normal, &frame_req, + &hw_device->normal_req_lock); + if (frame_req) + req_prio = 1; + } + + if (!frame_req) { + CAM_DBG(CAM_LRME, "No pending request"); + return 0; + } + + if (hw_device->hw_intf.hw_ops.process_cmd) { + submit_args.hw_update_entries = frame_req->hw_update_entries; + submit_args.num_hw_update_entries = + frame_req->num_hw_update_entries; + submit_args.frame_req = frame_req; + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_SUBMIT, + &submit_args, sizeof(struct cam_lrme_hw_submit_args)); + + if (rc == -EBUSY) + CAM_DBG(CAM_LRME, "device busy"); + else if (rc) + CAM_ERR(CAM_LRME, "submit request failed rc %d", rc); + if (rc) { + req_prio == 0 ? spin_lock(&hw_device->high_req_lock) : + spin_lock(&hw_device->normal_req_lock); + list_add(&frame_req->frame_list, + (req_prio == 0 ? + &hw_device->frame_pending_list_high : + &hw_device->frame_pending_list_normal)); + req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) : + spin_unlock(&hw_device->normal_req_lock); + } + if (rc == -EBUSY) + rc = 0; + } else { + req_prio == 0 ? spin_lock(&hw_device->high_req_lock) : + spin_lock(&hw_device->normal_req_lock); + list_add(&frame_req->frame_list, + (req_prio == 0 ? + &hw_device->frame_pending_list_high : + &hw_device->frame_pending_list_normal)); + req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) : + spin_unlock(&hw_device->normal_req_lock); + rc = -EINVAL; + } + + CAM_DBG(CAM_LRME, "End of submit, rc %d", rc); + + return rc; +} + +static int cam_lrme_mgr_util_schedule_frame_req( + struct cam_lrme_hw_mgr *hw_mgr, struct cam_lrme_device *hw_device) +{ + int rc = 0; + struct crm_workq_task *task; + struct cam_lrme_mgr_work_data *work_data; + + task = cam_req_mgr_workq_get_task(hw_device->work); + if (!task) { + CAM_ERR(CAM_LRME, "Can not get task for worker"); + return -ENOMEM; + } + + work_data = (struct cam_lrme_mgr_work_data *)task->payload; + work_data->hw_device = hw_device; + + task->process_cb = cam_lrme_mgr_util_submit_req; + CAM_DBG(CAM_LRME, "enqueue submit task"); + rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0); + + return rc; +} + +static int cam_lrme_mgr_util_release(struct cam_lrme_hw_mgr *hw_mgr, + uint32_t device_index) +{ + int rc = 0; + struct cam_lrme_device *hw_device; + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + hw_device->num_context--; + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_lrme_mgr_cb(void *data, + struct cam_lrme_hw_cb_args *cb_args) +{ + struct cam_lrme_hw_mgr *hw_mgr = &g_lrme_hw_mgr; + int rc = 0; + bool frame_abort = true; + struct cam_lrme_frame_request *frame_req; + struct cam_lrme_device *hw_device; + + if (!data || !cb_args) { + CAM_ERR(CAM_LRME, "Invalid input args"); + return -EINVAL; + } + + hw_device = (struct cam_lrme_device *)data; + frame_req = cb_args->frame_req; + + if (cb_args->cb_type & CAM_LRME_CB_PUT_FRAME) { + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->frame_list); + cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req->frame_list, + &hw_mgr->free_req_lock); + cb_args->cb_type &= ~CAM_LRME_CB_PUT_FRAME; + frame_req = NULL; + } + + if (cb_args->cb_type & CAM_LRME_CB_COMP_REG_UPDATE) { + cb_args->cb_type &= ~CAM_LRME_CB_COMP_REG_UPDATE; + CAM_DBG(CAM_LRME, "Reg update"); + } + + if (!frame_req) + return rc; + + if (cb_args->cb_type & CAM_LRME_CB_BUF_DONE) { + cb_args->cb_type &= ~CAM_LRME_CB_BUF_DONE; + frame_abort = false; + } else if (cb_args->cb_type & CAM_LRME_CB_ERROR) { + cb_args->cb_type &= ~CAM_LRME_CB_ERROR; + frame_abort = true; + } else { + CAM_ERR(CAM_LRME, "Wrong cb type %d, req %lld", + cb_args->cb_type, frame_req->req_id); + return -EINVAL; + } + + if (hw_mgr->event_cb) { + struct cam_hw_done_event_data buf_data; + + buf_data.request_id = frame_req->req_id; + CAM_DBG(CAM_LRME, "frame req %llu, frame_abort %d", + frame_req->req_id, frame_abort); + rc = hw_mgr->event_cb(frame_req->ctxt_to_hw_map, + frame_abort, &buf_data); + } else { + CAM_ERR(CAM_LRME, "No cb function"); + } + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->frame_list); + cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req->frame_list, + &hw_mgr->free_req_lock); + + rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device); + + return rc; +} + +static int cam_lrme_mgr_get_caps(void *hw_mgr_priv, void *hw_get_caps_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *args = hw_get_caps_args; + + if (sizeof(struct cam_lrme_query_cap_cmd) != args->size) { + CAM_ERR(CAM_LRME, + "sizeof(struct cam_query_cap_cmd) = %zu, args->size = %d", + sizeof(struct cam_query_cap_cmd), args->size); + return -EFAULT; + } + + if (copy_to_user(u64_to_user_ptr(args->caps_handle), + &(hw_mgr->lrme_caps), + sizeof(struct cam_lrme_query_cap_cmd))) { + CAM_ERR(CAM_LRME, "copy to user failed"); + return -EFAULT; + } + + return rc; +} + +static int cam_lrme_mgr_hw_acquire(void *hw_mgr_priv, void *hw_acquire_args) +{ + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *args = + (struct cam_hw_acquire_args *)hw_acquire_args; + struct cam_lrme_acquire_args lrme_acquire_args; + uintptr_t device_index; + + if (!hw_mgr_priv || !args) { + CAM_ERR(CAM_LRME, + "Invalid input params hw_mgr_priv %pK, acquire_args %pK", + hw_mgr_priv, args); + return -EINVAL; + } + + if (copy_from_user(&lrme_acquire_args, + (void __user *)args->acquire_info, + sizeof(struct cam_lrme_acquire_args))) { + CAM_ERR(CAM_LRME, "Failed to copy acquire args from user"); + return -EFAULT; + } + + device_index = cam_lrme_mgr_util_reserve_device(hw_mgr, + &lrme_acquire_args); + CAM_DBG(CAM_LRME, "Get device id %llu", device_index); + + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Get wrong device id %lu", device_index); + return -EINVAL; + } + + /* device_index is the right 4 bit in ctxt_to_hw_map */ + args->ctxt_to_hw_map = (void *)device_index; + + return 0; +} + +static int cam_lrme_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_release_args *args = + (struct cam_hw_release_args *)hw_release_args; + uint64_t device_index; + + if (!hw_mgr_priv || !hw_release_args) { + CAM_ERR(CAM_LRME, "Invalid arguments %pK, %pK", + hw_mgr_priv, hw_release_args); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %llu", device_index); + return -EPERM; + } + + rc = cam_lrme_mgr_util_release(hw_mgr, device_index); + if (rc) + CAM_ERR(CAM_LRME, "Failed in release device, rc=%d", rc); + + return rc; +} + +static int cam_lrme_mgr_hw_flush(void *hw_mgr_priv, void *hw_flush_args) +{ int rc = 0, i; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_flush_args *args; + struct cam_lrme_device *hw_device; + struct cam_lrme_frame_request *frame_req = NULL, *req_to_flush = NULL; + struct cam_lrme_frame_request **req_list = NULL; + uint32_t device_index; + struct cam_lrme_hw_flush_args lrme_flush_args; + uint32_t priority; + + if (!hw_mgr_priv || !hw_flush_args) { + CAM_ERR(CAM_LRME, "Invalid args %pK %pK", + hw_mgr_priv, hw_flush_args); + return -EINVAL; + } + + args = (struct cam_hw_flush_args *)hw_flush_args; + device_index = ((uintptr_t)args->ctxt_to_hw_map & 0xF); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Error in getting device %d", rc); + goto end; + } + + req_list = (struct cam_lrme_frame_request **)args->flush_req_pending; + for (i = 0; i < args->num_req_pending; i++) { + frame_req = req_list[i]; + memset(frame_req, 0x0, sizeof(*frame_req)); + cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req->frame_list, &hw_mgr->free_req_lock); + } + + req_list = (struct cam_lrme_frame_request **)args->flush_req_active; + for (i = 0; i < args->num_req_active; i++) { + frame_req = req_list[i]; + priority = CAM_LRME_DECODE_PRIORITY(args->ctxt_to_hw_map); + spin_lock((priority == CAM_LRME_PRIORITY_HIGH) ? + &hw_device->high_req_lock : + &hw_device->normal_req_lock); + if (!list_empty(&frame_req->frame_list)) { + list_del_init(&frame_req->frame_list); + cam_lrme_mgr_util_put_frame_req( + &hw_mgr->frame_free_list, + &frame_req->frame_list, + &hw_mgr->free_req_lock); + } else + req_to_flush = frame_req; + spin_unlock((priority == CAM_LRME_PRIORITY_HIGH) ? + &hw_device->high_req_lock : + &hw_device->normal_req_lock); + } + if (!req_to_flush) + goto end; + if (hw_device->hw_intf.hw_ops.flush) { + lrme_flush_args.ctxt_to_hw_map = req_to_flush->ctxt_to_hw_map; + lrme_flush_args.flush_type = args->flush_type; + lrme_flush_args.req_to_flush = req_to_flush; + rc = hw_device->hw_intf.hw_ops.flush(hw_device->hw_intf.hw_priv, + &lrme_flush_args, + sizeof(lrme_flush_args)); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in HW Stop %d", rc); + goto end; + } + } else { + CAM_ERR(CAM_LRME, "No stop ops"); + goto end; + } + +end: + return rc; +} + + +static int cam_lrme_mgr_hw_start(void *hw_mgr_priv, void *hw_start_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_start_args *args = + (struct cam_hw_start_args *)hw_start_args; + struct cam_lrme_device *hw_device; + uint32_t device_index; + + if (!hw_mgr || !args) { + CAM_ERR(CAM_LRME, "Invalid input params"); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + CAM_DBG(CAM_LRME, "Start device index %d", device_index); + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw device"); + return rc; + } + + if (hw_device->hw_intf.hw_ops.start) { + rc = hw_device->hw_intf.hw_ops.start( + hw_device->hw_intf.hw_priv, NULL, 0); + } else { + CAM_ERR(CAM_LRME, "Invalid start function"); + return -EINVAL; + } + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_DUMP_REGISTER, + &g_lrme_hw_mgr.debugfs_entry.dump_register, + sizeof(bool)); + + return rc; +} + +static int cam_lrme_mgr_hw_stop(void *hw_mgr_priv, void *stop_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_stop_args *args = + (struct cam_hw_stop_args *)stop_args; + struct cam_lrme_device *hw_device; + uint32_t device_index; + + if (!hw_mgr_priv || !stop_args) { + CAM_ERR(CAM_LRME, "Invalid arguments"); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + CAM_DBG(CAM_LRME, "Stop device index %d", device_index); + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw device"); + return rc; + } + + if (hw_device->hw_intf.hw_ops.stop) { + rc = hw_device->hw_intf.hw_ops.stop( + hw_device->hw_intf.hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in HW stop %d", rc); + goto end; + } + } + +end: + return rc; +} + +static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv, + void *hw_prepare_update_args) +{ + int rc = 0, i; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_prepare_update_args *args = + (struct cam_hw_prepare_update_args *)hw_prepare_update_args; + struct cam_lrme_device *hw_device; + struct cam_kmd_buf_info kmd_buf; + struct cam_lrme_hw_cmd_config_args config_args; + struct cam_lrme_frame_request *frame_req = NULL; + uint32_t device_index; + + if (!hw_mgr_priv || !hw_prepare_update_args) { + CAM_ERR(CAM_LRME, "Invalid args %pK %pK", + hw_mgr_priv, hw_prepare_update_args); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Error in getting device %d", rc); + goto error; + } + + rc = cam_lrme_mgr_util_packet_validate(args->packet, args->remain_len); + if (rc) { + CAM_ERR(CAM_LRME, "Error in packet validation %d", rc); + goto error; + } + + rc = cam_packet_util_get_kmd_buffer(args->packet, &kmd_buf); + if (rc) { + CAM_ERR(CAM_LRME, "Error in get kmd buf buffer %d", rc); + goto error; + } + + CAM_DBG(CAM_LRME, + "KMD Buf : hdl=%d, cpu_addr=%pK, offset=%d, size=%d, used=%d", + kmd_buf.handle, kmd_buf.cpu_addr, kmd_buf.offset, + kmd_buf.size, kmd_buf.used_bytes); + + rc = cam_packet_util_process_patches(args->packet, + hw_mgr->device_iommu.non_secure, hw_mgr->device_iommu.secure); + if (rc) { + CAM_ERR(CAM_LRME, "Patch packet failed, rc=%d", rc); + return rc; + } + + memset(&config_args, 0, sizeof(config_args)); + config_args.hw_device = hw_device; + + rc = cam_lrme_mgr_util_prepare_io_buffer( + hw_mgr->device_iommu.non_secure, args, + config_args.input_buf, config_args.output_buf, + CAM_LRME_MAX_IO_BUFFER); + if (rc) { + CAM_ERR(CAM_LRME, "Error in prepare IO Buf %d", rc); + goto error; + } + /* Check port number */ + if (args->num_in_map_entries == 0 || args->num_out_map_entries == 0) { + CAM_ERR(CAM_LRME, "Error in port number in %d, out %d", + args->num_in_map_entries, args->num_out_map_entries); + rc = -EINVAL; + goto error; + } + + rc = cam_lrme_mgr_util_prepare_hw_update_entries(hw_mgr, args, + &config_args, &kmd_buf); + if (rc) { + CAM_ERR(CAM_LRME, "Error in hw update entries %d", rc); + goto error; + } + + rc = cam_lrme_mgr_util_get_frame_req(&hw_mgr->frame_free_list, + &frame_req, &hw_mgr->free_req_lock); + if (rc || !frame_req) { + CAM_ERR(CAM_LRME, "Can not get free frame request"); + goto error; + } + + frame_req->ctxt_to_hw_map = args->ctxt_to_hw_map; + frame_req->req_id = args->packet->header.request_id; + frame_req->hw_device = hw_device; + frame_req->num_hw_update_entries = args->num_hw_update_entries; + for (i = 0; i < args->num_hw_update_entries; i++) + frame_req->hw_update_entries[i] = args->hw_update_entries[i]; + + args->priv = frame_req; + + CAM_DBG(CAM_LRME, "FramePrepare : Frame[%lld]", frame_req->req_id); + + return 0; + +error: + return rc; +} + +static int cam_lrme_mgr_hw_config(void *hw_mgr_priv, + void *hw_config_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_config_args *args = + (struct cam_hw_config_args *)hw_config_args; + struct cam_lrme_frame_request *frame_req; + struct cam_lrme_device *hw_device = NULL; + enum cam_lrme_hw_mgr_ctx_priority priority; + + if (!hw_mgr_priv || !hw_config_args) { + CAM_ERR(CAM_LRME, "Invalid arguments, hw_mgr %pK, config %pK", + hw_mgr_priv, hw_config_args); + return -EINVAL; + } + + if (!args->num_hw_update_entries) { + CAM_ERR(CAM_LRME, "No hw update entries"); + return -EINVAL; + } + + frame_req = (struct cam_lrme_frame_request *)args->priv; + if (!frame_req) { + CAM_ERR(CAM_LRME, "No frame request"); + return -EINVAL; + } + + hw_device = frame_req->hw_device; + if (!hw_device) + return -EINVAL; + + priority = CAM_LRME_DECODE_PRIORITY(args->ctxt_to_hw_map); + if (priority == CAM_LRME_PRIORITY_HIGH) { + cam_lrme_mgr_util_put_frame_req( + &hw_device->frame_pending_list_high, + &frame_req->frame_list, &hw_device->high_req_lock); + } else { + cam_lrme_mgr_util_put_frame_req( + &hw_device->frame_pending_list_normal, + &frame_req->frame_list, &hw_device->normal_req_lock); + } + + CAM_DBG(CAM_LRME, "schedule req %llu", frame_req->req_id); + rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device); + + return rc; +} + +static int cam_lrme_mgr_create_debugfs_entry(void) +{ + int rc = 0; + + g_lrme_hw_mgr.debugfs_entry.dentry = + debugfs_create_dir("camera_lrme", NULL); + if (!g_lrme_hw_mgr.debugfs_entry.dentry) { + CAM_ERR(CAM_LRME, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("dump_register", + 0644, + g_lrme_hw_mgr.debugfs_entry.dentry, + &g_lrme_hw_mgr.debugfs_entry.dump_register)) { + CAM_ERR(CAM_LRME, "failed to create dump register entry"); + rc = -ENOMEM; + goto err; + } + + return rc; + +err: + debugfs_remove_recursive(g_lrme_hw_mgr.debugfs_entry.dentry); + g_lrme_hw_mgr.debugfs_entry.dentry = NULL; + return rc; +} + + +int cam_lrme_mgr_register_device( + struct cam_hw_intf *lrme_hw_intf, + struct cam_iommu_handle *device_iommu, + struct cam_iommu_handle *cdm_iommu) +{ + struct cam_lrme_device *hw_device; + char buf[128]; + int i, rc; + + hw_device = &g_lrme_hw_mgr.hw_device[lrme_hw_intf->hw_idx]; + + g_lrme_hw_mgr.device_iommu = *device_iommu; + g_lrme_hw_mgr.cdm_iommu = *cdm_iommu; + + memcpy(&hw_device->hw_intf, lrme_hw_intf, sizeof(struct cam_hw_intf)); + + spin_lock_init(&hw_device->high_req_lock); + spin_lock_init(&hw_device->normal_req_lock); + INIT_LIST_HEAD(&hw_device->frame_pending_list_high); + INIT_LIST_HEAD(&hw_device->frame_pending_list_normal); + + rc = snprintf(buf, sizeof(buf), "cam_lrme_device_submit_worker%d", + lrme_hw_intf->hw_idx); + CAM_DBG(CAM_LRME, "Create submit workq for %s", buf); + rc = cam_req_mgr_workq_create(buf, + CAM_LRME_WORKQ_NUM_TASK, + &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, + 0); + if (rc) { + CAM_ERR(CAM_LRME, + "Unable to create a worker, rc=%d", rc); + return rc; + } + + for (i = 0; i < CAM_LRME_WORKQ_NUM_TASK; i++) + hw_device->work->task.pool[i].payload = + &hw_device->work_data[i]; + + if (hw_device->hw_intf.hw_ops.process_cmd) { + struct cam_lrme_hw_cmd_set_cb cb_args; + + cb_args.cam_lrme_hw_mgr_cb = cam_lrme_mgr_cb; + cb_args.data = hw_device; + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_REGISTER_CB, + &cb_args, sizeof(cb_args)); + if (rc) { + CAM_ERR(CAM_LRME, "Register cb failed"); + goto destroy_workqueue; + } + CAM_DBG(CAM_LRME, "cb registered"); + } + + if (hw_device->hw_intf.hw_ops.get_hw_caps) { + rc = hw_device->hw_intf.hw_ops.get_hw_caps( + hw_device->hw_intf.hw_priv, &hw_device->hw_caps, + sizeof(hw_device->hw_caps)); + if (rc) + CAM_ERR(CAM_LRME, "Get caps failed"); + } else { + CAM_ERR(CAM_LRME, "No get_hw_caps function"); + goto destroy_workqueue; + } + g_lrme_hw_mgr.lrme_caps.dev_caps[lrme_hw_intf->hw_idx] = + hw_device->hw_caps; + g_lrme_hw_mgr.device_count++; + g_lrme_hw_mgr.lrme_caps.device_iommu = g_lrme_hw_mgr.device_iommu; + g_lrme_hw_mgr.lrme_caps.cdm_iommu = g_lrme_hw_mgr.cdm_iommu; + g_lrme_hw_mgr.lrme_caps.num_devices = g_lrme_hw_mgr.device_count; + + hw_device->valid = true; + + CAM_DBG(CAM_LRME, "device registration done"); + return 0; + +destroy_workqueue: + cam_req_mgr_workq_destroy(&hw_device->work); + + return rc; +} + +int cam_lrme_mgr_deregister_device(int device_index) +{ + struct cam_lrme_device *hw_device; + + hw_device = &g_lrme_hw_mgr.hw_device[device_index]; + cam_req_mgr_workq_destroy(&hw_device->work); + memset(hw_device, 0x0, sizeof(struct cam_lrme_device)); + g_lrme_hw_mgr.device_count--; + + return 0; +} + +int cam_lrme_hw_mgr_deinit(void) +{ + mutex_destroy(&g_lrme_hw_mgr.hw_mgr_mutex); + memset(&g_lrme_hw_mgr, 0x0, sizeof(g_lrme_hw_mgr)); + + return 0; +} + +int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, + cam_hw_event_cb_func cam_lrme_dev_buf_done_cb) +{ + int i, rc = 0; + struct cam_lrme_frame_request *frame_req; + + if (!hw_mgr_intf) + return -EINVAL; + + CAM_DBG(CAM_LRME, "device count %d", g_lrme_hw_mgr.device_count); + if (g_lrme_hw_mgr.device_count > CAM_LRME_HW_MAX) { + CAM_ERR(CAM_LRME, "Invalid count of devices"); + return -EINVAL; + } + + memset(hw_mgr_intf, 0, sizeof(*hw_mgr_intf)); + + mutex_init(&g_lrme_hw_mgr.hw_mgr_mutex); + spin_lock_init(&g_lrme_hw_mgr.free_req_lock); + INIT_LIST_HEAD(&g_lrme_hw_mgr.frame_free_list); + + /* Init hw mgr frame requests and add to free list */ + for (i = 0; i < CAM_CTX_REQ_MAX * CAM_CTX_MAX; i++) { + frame_req = &g_lrme_hw_mgr.frame_req[i]; + + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->frame_list); + + list_add_tail(&frame_req->frame_list, + &g_lrme_hw_mgr.frame_free_list); + } + + hw_mgr_intf->hw_mgr_priv = &g_lrme_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_lrme_mgr_get_caps; + hw_mgr_intf->hw_acquire = cam_lrme_mgr_hw_acquire; + hw_mgr_intf->hw_release = cam_lrme_mgr_hw_release; + hw_mgr_intf->hw_start = cam_lrme_mgr_hw_start; + hw_mgr_intf->hw_stop = cam_lrme_mgr_hw_stop; + hw_mgr_intf->hw_prepare_update = cam_lrme_mgr_hw_prepare_update; + hw_mgr_intf->hw_config = cam_lrme_mgr_hw_config; + hw_mgr_intf->hw_read = NULL; + hw_mgr_intf->hw_write = NULL; + hw_mgr_intf->hw_close = NULL; + hw_mgr_intf->hw_flush = cam_lrme_mgr_hw_flush; + + g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb; + + cam_lrme_mgr_create_debugfs_entry(); + + CAM_DBG(CAM_LRME, "Hw mgr init done"); + return rc; +} diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h new file mode 100644 index 000000000000..bc77e726d3e6 --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_MGR_H_ +#define _CAM_LRME_HW_MGR_H_ + +#include +#include + +#include +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_workq.h" +#include "cam_lrme_hw_intf.h" +#include "cam_context.h" + +#define CAM_LRME_HW_MAX 1 +#define CAM_LRME_WORKQ_NUM_TASK 10 + +#define CAM_LRME_DECODE_DEVICE_INDEX(ctxt_to_hw_map) \ + ((uintptr_t)ctxt_to_hw_map & 0xF) + +#define CAM_LRME_DECODE_PRIORITY(ctxt_to_hw_map) \ + (((uintptr_t)ctxt_to_hw_map & 0xF0) >> 4) + +#define CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map) \ + ((uint64_t)(uintptr_t)ctxt_to_hw_map >> CAM_LRME_CTX_INDEX_SHIFT) + +/** + * enum cam_lrme_hw_mgr_ctx_priority + * + * CAM_LRME_PRIORITY_HIGH : High priority client + * CAM_LRME_PRIORITY_NORMAL : Normal priority client + */ +enum cam_lrme_hw_mgr_ctx_priority { + CAM_LRME_PRIORITY_HIGH, + CAM_LRME_PRIORITY_NORMAL, +}; + +/** + * struct cam_lrme_mgr_work_data : HW Mgr work data + * + * @hw_device : Pointer to the hw device + */ +struct cam_lrme_mgr_work_data { + struct cam_lrme_device *hw_device; +}; + +/** + * struct cam_lrme_debugfs_entry : debugfs entry struct + * + * @dentry : entry of debugfs + * @dump_register : flag to dump registers + */ +struct cam_lrme_debugfs_entry { + struct dentry *dentry; + bool dump_register; +}; + +/** + * struct cam_lrme_device : LRME HW device + * + * @hw_caps : HW device's capabilities + * @hw_intf : HW device's interface information + * @num_context : Number of contexts using this device + * @valid : Whether this device is valid + * @work : HW device's work queue + * @work_data : HW device's work data + * @frame_pending_list_high : High priority request queue + * @frame_pending_list_normal : Normal priority request queue + * @high_req_lock : Spinlock of high priority queue + * @normal_req_lock : Spinlock of normal priority queue + */ +struct cam_lrme_device { + struct cam_lrme_dev_cap hw_caps; + struct cam_hw_intf hw_intf; + uint32_t num_context; + bool valid; + struct cam_req_mgr_core_workq *work; + struct cam_lrme_mgr_work_data work_data[CAM_LRME_WORKQ_NUM_TASK]; + struct list_head frame_pending_list_high; + struct list_head frame_pending_list_normal; + spinlock_t high_req_lock; + spinlock_t normal_req_lock; +}; + +/** + * struct cam_lrme_hw_mgr : LRME HW manager + * + * @device_count : Number of HW devices + * @frame_free_list : List of free frame request + * @hw_mgr_mutex : Mutex to protect HW manager data + * @free_req_lock :Spinlock to protect frame_free_list + * @hw_device : List of HW devices + * @device_iommu : Device iommu + * @cdm_iommu : cdm iommu + * @frame_req : List of frame request to use + * @lrme_caps : LRME capabilities + * @event_cb : IRQ callback function + * @debugfs_entry : debugfs entry to set debug prop + */ +struct cam_lrme_hw_mgr { + uint32_t device_count; + struct list_head frame_free_list; + struct mutex hw_mgr_mutex; + spinlock_t free_req_lock; + struct cam_lrme_device hw_device[CAM_LRME_HW_MAX]; + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_lrme_frame_request frame_req[CAM_CTX_REQ_MAX * CAM_CTX_MAX]; + struct cam_lrme_query_cap_cmd lrme_caps; + cam_hw_event_cb_func event_cb; + struct cam_lrme_debugfs_entry debugfs_entry; +}; + +int cam_lrme_mgr_register_device(struct cam_hw_intf *lrme_hw_intf, + struct cam_iommu_handle *device_iommu, + struct cam_iommu_handle *cdm_iommu); +int cam_lrme_mgr_deregister_device(int device_index); + +#endif /* _CAM_LRME_HW_MGR_H_ */ diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h new file mode 100644 index 000000000000..df6ea0eac798 --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_MGR_INTF_H_ +#define _CAM_LRME_HW_MGR_INTF_H_ + +#include + +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" + +int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, + cam_hw_event_cb_func cam_lrme_dev_buf_done_cb); +int cam_lrme_hw_mgr_deinit(void); + +#endif /* _CAM_LRME_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile new file mode 100644 index 000000000000..8df30c0f44de --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -I$(srctree)/techpack/camera0 +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_dev.o cam_lrme_hw_core.o cam_lrme_hw_soc.o diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c new file mode 100644 index 000000000000..b736708fa99d --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -0,0 +1,1274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" +#include "cam_smmu_api.h" + +static void cam_lrme_dump_registers(void __iomem *base) +{ + /* dump the clc registers */ + cam_io_dump(base, 0x60, (0xc0 - 0x60) / 0x4); + /* dump the fe and we registers */ + cam_io_dump(base, 0x200, (0x29c - 0x200) / 0x4); + cam_io_dump(base, 0x2f0, (0x330 - 0x2f0) / 0x4); + cam_io_dump(base, 0x500, (0x5b4 - 0x500) / 0x4); + cam_io_dump(base, 0x700, (0x778 - 0x700) / 0x4); + cam_io_dump(base, 0x800, (0x878 - 0x800) / 0x4); + /* dump lrme sw registers, interrupts */ + cam_io_dump(base, 0x900, (0x928 - 0x900) / 0x4); +} + +static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer, + uint32_t *index, uint32_t reg_offset, uint32_t reg_value) +{ + buffer[(*index)++] = reg_offset; + buffer[(*index)++] = reg_value; +} + +static void cam_lrme_hw_util_fill_fe_reg(struct cam_lrme_hw_io_buffer *io_buf, + uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd, + struct cam_lrme_hw_info *hw_info) +{ + uint32_t reg_val; + + /* 1. config buffer size */ + if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10) + reg_val = io_buf->io_cfg->planes[0].width * 2; + else + reg_val = io_buf->io_cfg->planes[0].width; + reg_val |= (io_buf->io_cfg->planes[0].height << 16); + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].rd_buffer_size, + reg_val); + + CAM_DBG(CAM_LRME, + "width %d", io_buf->io_cfg->planes[0].width); + CAM_DBG(CAM_LRME, + "height %d", io_buf->io_cfg->planes[0].height); + + /* 2. config image address */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].addr_image, + io_buf->io_addr[0]); + + CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]); + + /* 3. config stride */ + reg_val = io_buf->io_cfg->planes[0].plane_stride; + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].rd_stride, + reg_val); + + CAM_DBG(CAM_LRME, "plane_stride %d", + io_buf->io_cfg->planes[0].plane_stride); + + /* 4. enable client */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].core_cfg, 0x1); + + /* 5. unpack_cfg */ + if (io_buf->io_cfg->format == CAM_FORMAT_PD10) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, + 0x0); + else if (io_buf->io_cfg->format == CAM_FORMAT_Y_ONLY || + io_buf->io_cfg->format == CAM_FORMAT_PLAIN8 || + io_buf->io_cfg->format == CAM_FORMAT_NV12 || + io_buf->io_cfg->format == CAM_FORMAT_NV21) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, + 0x1); + else if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, + 0x22); + else + CAM_ERR(CAM_LRME, "Unsupported format %d", + io_buf->io_cfg->format); +} + +static void cam_lrme_hw_util_fill_we_reg(struct cam_lrme_hw_io_buffer *io_buf, + uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd, + struct cam_lrme_hw_info *hw_info) +{ + /* config client mode */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].cfg, + 0x1); + + /* image address */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].addr_image, + io_buf->io_addr[0]); + CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]); + + /* buffer width and height */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].buffer_width_cfg, + io_buf->io_cfg->planes[0].width); + CAM_DBG(CAM_LRME, "width %d", io_buf->io_cfg->planes[0].width); + + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].buffer_height_cfg, + io_buf->io_cfg->planes[0].height); + CAM_DBG(CAM_LRME, "height %d", io_buf->io_cfg->planes[0].height); + + /* packer cfg */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].packer_cfg, + (index == 0) ? 0x1 : 0x5); + + /* client stride */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].wr_stride, + io_buf->io_cfg->planes[0].plane_stride); + CAM_DBG(CAM_LRME, "plane_stride %d", + io_buf->io_cfg->planes[0].plane_stride); +} + + +static int cam_lrme_hw_util_process_config_hw(struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_cmd_config_args *config_args) +{ + int i; + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_cdm_info *hw_cdm_info; + uint32_t *cmd_buf_addr = config_args->cmd_buf_addr; + uint32_t reg_val_pair[CAM_LRME_MAX_REG_PAIR_NUM]; + struct cam_lrme_hw_io_buffer *io_buf; + struct cam_lrme_hw_info *hw_info = + ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info; + uint32_t num_cmd = 0; + uint32_t size; + uint32_t mem_base, available_size = config_args->size; + uint32_t output_res_mask = 0, input_res_mask = 0; + + + if (!cmd_buf_addr) { + CAM_ERR(CAM_LRME, "Invalid input args"); + return -EINVAL; + } + + hw_cdm_info = + ((struct cam_lrme_core *)lrme_hw->core_info)->hw_cdm_info; + + for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) { + io_buf = &config_args->input_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_INPUT) { + CAM_ERR(CAM_LRME, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + CAM_DBG(CAM_LRME, + "resource_type %d", io_buf->io_cfg->resource_type); + + switch (io_buf->io_cfg->resource_type) { + case CAM_LRME_IO_TYPE_TAR: + cam_lrme_hw_util_fill_fe_reg(io_buf, 0, reg_val_pair, + &num_cmd, hw_info); + + input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_TAR; + break; + case CAM_LRME_IO_TYPE_REF: + cam_lrme_hw_util_fill_fe_reg(io_buf, 1, reg_val_pair, + &num_cmd, hw_info); + + input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_REF; + break; + default: + CAM_ERR(CAM_LRME, "wrong resource_type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++) + if (!((input_res_mask >> i) & 0x1)) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, + hw_info->bus_rd_reg.bus_client_reg[i].core_cfg, + 0x0); + + for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) { + io_buf = &config_args->output_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) { + CAM_ERR(CAM_LRME, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + + CAM_DBG(CAM_LRME, "resource_type %d", + io_buf->io_cfg->resource_type); + switch (io_buf->io_cfg->resource_type) { + case CAM_LRME_IO_TYPE_DS2: + cam_lrme_hw_util_fill_we_reg(io_buf, 0, reg_val_pair, + &num_cmd, hw_info); + + output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_DS2; + break; + case CAM_LRME_IO_TYPE_RES: + cam_lrme_hw_util_fill_we_reg(io_buf, 1, reg_val_pair, + &num_cmd, hw_info); + + output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_RES; + break; + + default: + CAM_ERR(CAM_LRME, "wrong resource_type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++) + if (!((output_res_mask >> i) & 0x1)) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, + hw_info->bus_wr_reg.bus_client_reg[i].cfg, 0x0); + + if (output_res_mask) { + /* write composite mask */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, + hw_info->bus_wr_reg.common_reg.composite_mask_0, + output_res_mask); + } + + size = hw_cdm_info->cdm_ops->cdm_required_size_changebase(); + if ((size * 4) > available_size) { + CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d", + available_size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, CAM_LRME_BASE_IDX); + + hw_cdm_info->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base); + cmd_buf_addr += size; + available_size -= (size * 4); + + size = hw_cdm_info->cdm_ops->cdm_required_size_reg_random( + num_cmd / 2); + + if ((size * 4) > available_size) { + CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d", + available_size, size); + return -ENOMEM; + } + + hw_cdm_info->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmd / 2, + reg_val_pair); + cmd_buf_addr += size; + available_size -= (size * 4); + + config_args->config_buf_size = + config_args->size - available_size; + + return 0; +} + +static int cam_lrme_hw_util_submit_go(struct cam_hw_info *lrme_hw) +{ + struct cam_lrme_core *lrme_core; + struct cam_hw_soc_info *soc_info; + struct cam_lrme_hw_info *hw_info; + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + hw_info = lrme_core->hw_info; + soc_info = &lrme_hw->soc_info; + + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.cmd); + + return 0; +} + +static int cam_lrme_hw_util_reset(struct cam_hw_info *lrme_hw, + uint32_t reset_type) +{ + struct cam_lrme_core *lrme_core; + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_hw_info *hw_info; + long time_left; + + lrme_core = lrme_hw->core_info; + hw_info = lrme_core->hw_info; + + switch (reset_type) { + case CAM_LRME_HW_RESET_TYPE_HW_RESET: + reinit_completion(&lrme_core->reset_complete); + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_rst_cmd); + time_left = wait_for_completion_timeout( + &lrme_core->reset_complete, + msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT)); + if (time_left <= 0) { + CAM_ERR(CAM_LRME, + "HW reset wait failed time_left=%ld", + time_left); + return -ETIMEDOUT; + } + break; + case CAM_LRME_HW_RESET_TYPE_SW_RESET: + cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.sw_reset); + cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.sw_reset); + reinit_completion(&lrme_core->reset_complete); + cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_rst_cmd); + time_left = wait_for_completion_timeout( + &lrme_core->reset_complete, + msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT)); + if (time_left <= 0) { + CAM_ERR(CAM_LRME, + "SW reset wait failed time_left=%ld", + time_left); + return -ETIMEDOUT; + } + break; + } + + return 0; +} + +int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw, + struct cam_lrme_dev_cap *hw_caps) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_hw_info *hw_info = + ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info; + uint32_t reg_value; + + if (!hw_info) { + CAM_ERR(CAM_LRME, "Invalid hw info data"); + return -EINVAL; + } + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->clc_reg.clc_hw_version); + hw_caps->clc_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->clc_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->clc_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.hw_version); + hw_caps->bus_rd_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->bus_rd_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->bus_rd_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.hw_version); + hw_caps->bus_wr_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->bus_wr_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->bus_wr_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_hw_version); + hw_caps->top_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->top_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->top_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_titan_version); + hw_caps->top_titan_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->top_titan_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->top_titan_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + return 0; +} + +static int cam_lrme_hw_util_submit_req(struct cam_lrme_core *lrme_core, + struct cam_lrme_frame_request *frame_req) +{ + struct cam_lrme_cdm_info *hw_cdm_info = + lrme_core->hw_cdm_info; + struct cam_cdm_bl_request *cdm_cmd = hw_cdm_info->cdm_cmd; + struct cam_hw_update_entry *cmd; + int i, rc = 0; + + if (frame_req->num_hw_update_entries > 0) { + cdm_cmd->cmd_arrary_count = frame_req->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = false; + cdm_cmd->userdata = NULL; + cdm_cmd->cookie = 0; + + for (i = 0; i <= frame_req->num_hw_update_entries; i++) { + cmd = (frame_req->hw_update_entries + i); + cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i].offset = cmd->offset; + cdm_cmd->cmd[i].len = cmd->len; + } + + rc = cam_cdm_submit_bls(hw_cdm_info->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to submit cdm commands"); + return -EINVAL; + } + } else { + CAM_ERR(CAM_LRME, "No hw update entry"); + rc = -EINVAL; + } + + return rc; +} + +static int cam_lrme_hw_util_flush_ctx(struct cam_hw_info *lrme_hw, + void *ctxt_to_hw_map) +{ + int rc = -ENODEV; + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_hw_cb_args cb_args; + struct cam_lrme_frame_request *req_proc, *req_submit; + struct cam_lrme_hw_submit_args submit_args; + + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) { + CAM_ERR(CAM_LRME, "reset failed"); + return rc; + } + + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + req_proc = lrme_core->req_proc; + req_submit = lrme_core->req_submit; + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + + if (req_submit && req_submit->ctxt_to_hw_map == ctxt_to_hw_map) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_submit; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_submit) { + submit_args.frame_req = req_submit; + submit_args.hw_update_entries = req_submit->hw_update_entries; + submit_args.num_hw_update_entries = + req_submit->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_submit); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_submit; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + if (req_proc && req_proc->ctxt_to_hw_map == ctxt_to_hw_map) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_proc; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_proc) { + submit_args.frame_req = req_proc; + submit_args.hw_update_entries = req_proc->hw_update_entries; + submit_args.num_hw_update_entries = + req_proc->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_proc); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_proc; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + return rc; +} + +static int cam_lrme_hw_util_flush_req(struct cam_hw_info *lrme_hw, + struct cam_lrme_frame_request *req_to_flush) +{ + int rc = -ENODEV; + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_hw_cb_args cb_args; + struct cam_lrme_frame_request *req_proc, *req_submit; + struct cam_lrme_hw_submit_args submit_args; + + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) { + CAM_ERR(CAM_LRME, "reset failed"); + return rc; + } + + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + req_proc = lrme_core->req_proc; + req_submit = lrme_core->req_submit; + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + + if (req_submit && req_submit == req_to_flush) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_submit; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_submit) { + submit_args.frame_req = req_submit; + submit_args.hw_update_entries = req_submit->hw_update_entries; + submit_args.num_hw_update_entries = + req_submit->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_submit); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_submit; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + if (req_proc && req_proc == req_to_flush) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_proc; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_proc) { + submit_args.frame_req = req_proc; + submit_args.hw_update_entries = req_proc->hw_update_entries; + submit_args.num_hw_update_entries = + req_proc->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_proc); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_proc; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + return rc; +} + + +static int cam_lrme_hw_util_process_err(struct cam_hw_info *lrme_hw) +{ + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_frame_request *req_proc, *req_submit; + struct cam_lrme_hw_cb_args cb_args; + int rc; + + req_proc = lrme_core->req_proc; + req_submit = lrme_core->req_submit; + cb_args.cb_type = CAM_LRME_CB_ERROR; + + if ((lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) && + (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING) && + (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PROC_PEND)) { + CAM_ERR(CAM_LRME, "Get error irq in wrong state %d", + lrme_core->state); + } + + cam_lrme_dump_registers(lrme_hw->soc_info.reg_map[0].mem_base); + + CAM_ERR_RATE_LIMIT(CAM_LRME, "Start recovery"); + lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY; + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) + CAM_ERR(CAM_LRME, "Failed to reset"); + + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + if (!rc) + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + + cb_args.frame_req = req_proc; + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data, + &cb_args); + + cb_args.frame_req = req_submit; + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data, + &cb_args); + + return rc; +} + +static int cam_lrme_hw_util_process_reg_update( + struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args) +{ + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + int rc = 0; + + cb_args->cb_type |= CAM_LRME_CB_COMP_REG_UPDATE; + if (lrme_core->state == CAM_LRME_CORE_STATE_REQ_PENDING) { + lrme_core->state = CAM_LRME_CORE_STATE_PROCESSING; + } else { + CAM_ERR(CAM_LRME, "Reg update in wrong state %d", + lrme_core->state); + rc = cam_lrme_hw_util_process_err(lrme_hw); + if (rc) + CAM_ERR(CAM_LRME, "Failed to reset"); + return -EINVAL; + } + + lrme_core->req_proc = lrme_core->req_submit; + lrme_core->req_submit = NULL; + + if (lrme_core->dump_flag) + cam_lrme_dump_registers(lrme_hw->soc_info.reg_map[0].mem_base); + + return 0; +} + +static int cam_lrme_hw_util_process_idle( + struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args) +{ + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + int rc = 0; + + cb_args->cb_type |= CAM_LRME_CB_BUF_DONE; + switch (lrme_core->state) { + case CAM_LRME_CORE_STATE_REQ_PROC_PEND: + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + break; + + case CAM_LRME_CORE_STATE_PROCESSING: + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + break; + + default: + CAM_ERR(CAM_LRME, "Idle in wrong state %d", + lrme_core->state); + rc = cam_lrme_hw_util_process_err(lrme_hw); + return rc; + } + cb_args->frame_req = lrme_core->req_proc; + lrme_core->req_proc = NULL; + + return 0; +} + +void cam_lrme_set_irq(struct cam_hw_info *lrme_hw, + enum cam_lrme_irq_set set) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_hw_info *hw_info = lrme_core->hw_info; + + switch (set) { + case CAM_LRME_IRQ_ENABLE: + cam_io_w_mb(0xFFFF, + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_mask); + cam_io_w_mb(0xFFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_0); + cam_io_w_mb(0xFFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_1); + cam_io_w_mb(0xFFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_mask); + break; + + case CAM_LRME_IRQ_DISABLE: + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_mask); + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_0); + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_1); + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_mask); + break; + } +} + + +int cam_lrme_hw_process_irq(void *priv, void *data) +{ + struct cam_lrme_hw_work_data *work_data; + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + int rc = 0; + uint32_t top_irq_status, fe_irq_status; + uint32_t *we_irq_status; + struct cam_lrme_hw_cb_args cb_args; + + if (!data || !priv) { + CAM_ERR(CAM_LRME, "Invalid data %pK %pK", data, priv); + return -EINVAL; + } + + memset(&cb_args, 0, sizeof(struct cam_lrme_hw_cb_args)); + lrme_hw = (struct cam_hw_info *)priv; + work_data = (struct cam_lrme_hw_work_data *)data; + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + top_irq_status = work_data->top_irq_status; + fe_irq_status = work_data->fe_irq_status; + we_irq_status = work_data->we_irq_status; + + CAM_DBG(CAM_LRME, + "top status %x, fe status %x, we status0 %x, we status1 %x", + top_irq_status, fe_irq_status, we_irq_status[0], + we_irq_status[1]); + CAM_DBG(CAM_LRME, "Current state %d", lrme_core->state); + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_DBG(CAM_LRME, "LRME HW is in off state"); + goto end; + } + + if (top_irq_status & (1 << 3)) { + CAM_DBG(CAM_LRME, "Error"); + rc = cam_lrme_hw_util_process_err(lrme_hw); + if (rc) + CAM_ERR(CAM_LRME, "Process error failed"); + goto end; + } + + if (we_irq_status[0] & (1 << 1)) { + CAM_DBG(CAM_LRME, "reg update"); + rc = cam_lrme_hw_util_process_reg_update(lrme_hw, &cb_args); + if (rc) { + CAM_ERR(CAM_LRME, "Process reg_update failed"); + goto end; + } + } + + if (top_irq_status & (1 << 4)) { + CAM_DBG(CAM_LRME, "IDLE"); + if (!lrme_core->req_proc) { + CAM_DBG(CAM_LRME, "No frame request to process idle"); + goto end; + } + rc = cam_lrme_hw_util_process_idle(lrme_hw, &cb_args); + if (rc) { + CAM_ERR(CAM_LRME, "Process idle failed"); + goto end; + } + } + + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) { + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else { + CAM_ERR(CAM_LRME, "No hw mgr cb"); + rc = -EINVAL; + } + +end: + mutex_unlock(&lrme_hw->hw_mutex); + return rc; +} + +int cam_lrme_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + int rc = 0; + struct cam_lrme_core *lrme_core; + + if (!lrme_hw) { + CAM_ERR(CAM_LRME, + "Invalid input params, lrme_hw %pK", + lrme_hw); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->open_count > 0) { + lrme_hw->open_count++; + CAM_DBG(CAM_LRME, "This device is activated before"); + goto unlock; + } + + rc = cam_lrme_soc_enable_resources(lrme_hw); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to enable soc resources"); + goto unlock; + } + + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to reset hw"); + goto disable_soc; + } + + if (lrme_core->hw_cdm_info) { + struct cam_lrme_cdm_info *hw_cdm_info = + lrme_core->hw_cdm_info; + + rc = cam_cdm_stream_on(hw_cdm_info->cdm_handle); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to stream on cdm"); + goto disable_soc; + } + } + + lrme_hw->hw_state = CAM_HW_STATE_POWER_UP; + lrme_hw->open_count++; + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + + CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); + mutex_unlock(&lrme_hw->hw_mutex); + return rc; + +disable_soc: + if (cam_lrme_soc_disable_resources(lrme_hw)) + CAM_ERR(CAM_LRME, "Error in disable soc resources"); +unlock: + CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); + mutex_unlock(&lrme_hw->hw_mutex); + return rc; +} + +int cam_lrme_hw_stop(void *hw_priv, void *hw_stop_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + int rc = 0; + struct cam_lrme_core *lrme_core; + + if (!lrme_hw) { + CAM_ERR(CAM_LRME, "Invalid argument"); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->open_count == 0 || + lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_ERR(CAM_LRME, "Error Unbalanced stop"); + return -EINVAL; + } + lrme_hw->open_count--; + + CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); + + if (lrme_hw->open_count) + goto unlock; + + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + + if (lrme_core->hw_cdm_info) { + struct cam_lrme_cdm_info *hw_cdm_info = + lrme_core->hw_cdm_info; + + rc = cam_cdm_stream_off(hw_cdm_info->cdm_handle); + if (rc) { + CAM_ERR(CAM_LRME, + "Failed in CDM StreamOff, handle=0x%x, rc=%d", + hw_cdm_info->cdm_handle, rc); + goto unlock; + } + } + + rc = cam_lrme_soc_disable_resources(lrme_hw); + if (rc) + CAM_ERR(CAM_LRME, "Failed in Disable SOC, rc=%d", rc); + + lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + if (lrme_core->state == CAM_LRME_CORE_STATE_IDLE) { + lrme_core->state = CAM_LRME_CORE_STATE_INIT; + } else { + CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state); + rc = -EINVAL; + } + +unlock: + mutex_unlock(&lrme_hw->hw_mutex); + return rc; +} + +int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, + uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + struct cam_lrme_core *lrme_core; + struct cam_lrme_hw_submit_args *args = + (struct cam_lrme_hw_submit_args *)hw_submit_args; + int rc = 0; + struct cam_lrme_frame_request *frame_req; + + + if (!hw_priv || !hw_submit_args) { + CAM_ERR(CAM_LRME, "Invalid input"); + return -EINVAL; + } + + if (sizeof(struct cam_lrme_hw_submit_args) != arg_size) { + CAM_ERR(CAM_LRME, + "size of args %zu, arg_size %d", + sizeof(struct cam_lrme_hw_submit_args), arg_size); + return -EINVAL; + } + + frame_req = args->frame_req; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->open_count == 0) { + CAM_ERR(CAM_LRME, "HW is not open"); + mutex_unlock(&lrme_hw->hw_mutex); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + if (lrme_core->state != CAM_LRME_CORE_STATE_IDLE && + lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "device busy, can not submit, state %d", + lrme_core->state); + return -EBUSY; + } + + if (lrme_core->req_submit != NULL) { + CAM_ERR(CAM_LRME, "req_submit is not NULL"); + return -EBUSY; + } + + rc = cam_lrme_hw_util_submit_req(lrme_core, frame_req); + if (rc) { + CAM_ERR(CAM_LRME, "Submit req failed"); + goto error; + } + + switch (lrme_core->state) { + case CAM_LRME_CORE_STATE_PROCESSING: + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND; + break; + + case CAM_LRME_CORE_STATE_IDLE: + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + break; + + default: + CAM_ERR(CAM_LRME, "Wrong hw state"); + rc = -EINVAL; + goto error; + } + + lrme_core->req_submit = frame_req; + + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "Release lock, submit done for req %llu", + frame_req->req_id); + + return 0; + +error: + mutex_unlock(&lrme_hw->hw_mutex); + + return rc; + +} + +int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = hw_priv; + struct cam_lrme_core *lrme_core; + struct cam_lrme_hw_reset_args *lrme_reset_args = reset_core_args; + int rc; + + if (!hw_priv) { + CAM_ERR(CAM_LRME, "Invalid input args"); + return -EINVAL; + } + + if (!reset_core_args || + sizeof(struct cam_lrme_hw_reset_args) != arg_size) { + CAM_ERR(CAM_LRME, "Invalid reset args"); + return -EINVAL; + } + + lrme_core = lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + if (lrme_core->state == CAM_LRME_CORE_STATE_RECOVERY) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_ERR(CAM_LRME, "Reset not allowed in %d state", + lrme_core->state); + return -EINVAL; + } + + lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY; + + rc = cam_lrme_hw_util_reset(lrme_hw, lrme_reset_args->reset_type); + if (rc) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_ERR(CAM_FD, "Failed to reset"); + return rc; + } + + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + + mutex_unlock(&lrme_hw->hw_mutex); + + return 0; +} + +int cam_lrme_hw_flush(void *hw_priv, void *hw_flush_args, uint32_t arg_size) +{ + struct cam_lrme_core *lrme_core = NULL; + struct cam_hw_info *lrme_hw = hw_priv; + struct cam_lrme_hw_flush_args *flush_args = + (struct cam_lrme_hw_flush_args *)hw_flush_args; + int rc = -ENODEV; + + if (!hw_priv) { + CAM_ERR(CAM_LRME, "Invalid arguments %pK", hw_priv); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING && + lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING && + lrme_core->state != CAM_LRME_CORE_STATE_REQ_PROC_PEND) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "Flush is not needed in %d state", + lrme_core->state); + return 0; + } + + if (!lrme_core->req_proc && !lrme_core->req_submit) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "no req in device"); + return 0; + } + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_ALL: + if ((!lrme_core->req_submit || + lrme_core->req_submit->ctxt_to_hw_map != + flush_args->ctxt_to_hw_map) && + (!lrme_core->req_proc || + lrme_core->req_proc->ctxt_to_hw_map != + flush_args->ctxt_to_hw_map)) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "hw running on different ctx"); + return 0; + } + rc = cam_lrme_hw_util_flush_ctx(lrme_hw, + flush_args->ctxt_to_hw_map); + if (rc) + CAM_ERR(CAM_LRME, "Flush all failed"); + break; + + case CAM_FLUSH_TYPE_REQ: + if ((!lrme_core->req_submit || + lrme_core->req_submit != flush_args->req_to_flush) && + (!lrme_core->req_proc || + lrme_core->req_proc != flush_args->req_to_flush)) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "hw running on different ctx"); + return 0; + } + rc = cam_lrme_hw_util_flush_req(lrme_hw, + flush_args->req_to_flush); + if (rc) + CAM_ERR(CAM_LRME, "Flush req failed"); + break; + + default: + CAM_ERR(CAM_LRME, "Unsupported flush type"); + break; + } + + mutex_unlock(&lrme_hw->hw_mutex); + + return rc; +} + +int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + struct cam_lrme_dev_cap *lrme_hw_caps = + (struct cam_lrme_dev_cap *)get_hw_cap_args; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_LRME, "Invalid input pointers %pK %pK", + hw_priv, get_hw_cap_args); + return -EINVAL; + } + + lrme_hw = (struct cam_hw_info *)hw_priv; + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + *lrme_hw_caps = lrme_core->hw_caps; + + return 0; +} + +irqreturn_t cam_lrme_hw_irq(int irq_num, void *data) +{ + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + struct cam_hw_soc_info *soc_info; + struct cam_lrme_hw_info *hw_info; + struct crm_workq_task *task; + struct cam_lrme_hw_work_data *work_data; + uint32_t top_irq_status, fe_irq_status, we_irq_status0, we_irq_status1; + int rc; + + if (!data) { + CAM_ERR(CAM_LRME, "Invalid data in IRQ callback"); + return IRQ_NONE; + } + + lrme_hw = (struct cam_hw_info *)data; + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + soc_info = &lrme_hw->soc_info; + hw_info = lrme_core->hw_info; + + top_irq_status = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_status); + CAM_DBG(CAM_LRME, "top_irq_status %x", top_irq_status); + cam_io_w_mb(top_irq_status, + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_clear); + top_irq_status &= CAM_LRME_TOP_IRQ_MASK; + + fe_irq_status = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_status); + CAM_DBG(CAM_LRME, "fe_irq_status %x", fe_irq_status); + cam_io_w_mb(fe_irq_status, + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_clear); + fe_irq_status &= CAM_LRME_FE_IRQ_MASK; + + we_irq_status0 = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_status_0); + CAM_DBG(CAM_LRME, "we_irq_status[0] %x", we_irq_status0); + cam_io_w_mb(we_irq_status0, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_clear_0); + we_irq_status0 &= CAM_LRME_WE_IRQ_MASK_0; + + we_irq_status1 = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_status_1); + CAM_DBG(CAM_LRME, "we_irq_status[1] %x", we_irq_status1); + cam_io_w_mb(we_irq_status1, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_clear_1); + we_irq_status1 &= CAM_LRME_WE_IRQ_MASK_1; + + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_cmd); + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_cmd); + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_cmd); + + if (top_irq_status & 0x1) { + complete(&lrme_core->reset_complete); + top_irq_status &= (~0x1); + } + + if (top_irq_status || fe_irq_status || + we_irq_status0 || we_irq_status1) { + task = cam_req_mgr_workq_get_task(lrme_core->work); + if (!task) { + CAM_ERR(CAM_LRME, "no empty task available"); + return IRQ_NONE; + } + work_data = (struct cam_lrme_hw_work_data *)task->payload; + work_data->top_irq_status = top_irq_status; + work_data->fe_irq_status = fe_irq_status; + work_data->we_irq_status[0] = we_irq_status0; + work_data->we_irq_status[1] = we_irq_status1; + task->process_cb = cam_lrme_hw_process_irq; + rc = cam_req_mgr_workq_enqueue_task(task, data, + CRM_TASK_PRIORITY_0); + if (rc) + CAM_ERR(CAM_LRME, + "Failed in enqueue work task, rc=%d", rc); + } + + return IRQ_HANDLED; +} + +int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + int rc = 0; + + switch (cmd_type) { + case CAM_LRME_HW_CMD_PREPARE_HW_UPDATE: { + struct cam_lrme_hw_cmd_config_args *config_args; + + config_args = (struct cam_lrme_hw_cmd_config_args *)cmd_args; + rc = cam_lrme_hw_util_process_config_hw(lrme_hw, config_args); + break; + } + + case CAM_LRME_HW_CMD_REGISTER_CB: { + struct cam_lrme_hw_cmd_set_cb *cb_args; + struct cam_lrme_device *hw_device; + struct cam_lrme_core *lrme_core = + (struct cam_lrme_core *)lrme_hw->core_info; + cb_args = (struct cam_lrme_hw_cmd_set_cb *)cmd_args; + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb = + cb_args->cam_lrme_hw_mgr_cb; + lrme_core->hw_mgr_cb.data = cb_args->data; + hw_device = cb_args->data; + rc = 0; + break; + } + + case CAM_LRME_HW_CMD_SUBMIT: { + struct cam_lrme_hw_submit_args *submit_args; + + submit_args = (struct cam_lrme_hw_submit_args *)cmd_args; + rc = cam_lrme_hw_submit_req(hw_priv, + submit_args, arg_size); + break; + } + + case CAM_LRME_HW_CMD_DUMP_REGISTER: { + struct cam_lrme_core *lrme_core = + (struct cam_lrme_core *)lrme_hw->core_info; + lrme_core->dump_flag = *(bool *)cmd_args; + CAM_DBG(CAM_LRME, "dump_flag %d", lrme_core->dump_flag); + break; + } + + default: + break; + } + + return rc; +} diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h new file mode 100644 index 000000000000..accb5a8b5827 --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h @@ -0,0 +1,451 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_CORE_H_ +#define _CAM_LRME_HW_CORE_H_ + +#include +#include +#include +#include +#include + +#include "cam_common_util.h" +#include "cam_debug_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_lrme_hw_intf.h" +#include "cam_lrme_hw_soc.h" +#include "cam_req_mgr_workq.h" + +#define CAM_LRME_HW_RESET_TIMEOUT 3000 + +#define CAM_LRME_BUS_RD_MAX_CLIENTS 2 +#define CAM_LRME_BUS_WR_MAX_CLIENTS 2 + +#define CAM_LRME_HW_WORKQ_NUM_TASK 30 + +#define CAM_LRME_TOP_IRQ_MASK 0x19 +#define CAM_LRME_WE_IRQ_MASK_0 0x2 +#define CAM_LRME_WE_IRQ_MASK_1 0x0 +#define CAM_LRME_FE_IRQ_MASK 0x0 + +#define CAM_LRME_MAX_REG_PAIR_NUM 60 + +/** + * enum cam_lrme_irq_set + * + * @CAM_LRME_IRQ_ENABLE : Enable irqs + * @CAM_LRME_IRQ_DISABLE : Disable irqs + */ +enum cam_lrme_irq_set { + CAM_LRME_IRQ_ENABLE, + CAM_LRME_IRQ_DISABLE, +}; + +/** + * struct cam_lrme_cdm_info : information used to submit cdm command + * + * @cdm_handle : CDM handle for this device + * @cdm_ops : CDM ops + * @cdm_cmd : CDM command pointer + */ +struct cam_lrme_cdm_info { + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; + struct cam_cdm_bl_request *cdm_cmd; +}; + +/** + * struct cam_lrme_hw_work_data : Work data for HW work queue + * + * @top_irq_status : Top registers irq status + * @fe_irq_status : FE engine irq status + * @we_irq_status : WE engine irq status + */ +struct cam_lrme_hw_work_data { + uint32_t top_irq_status; + uint32_t fe_irq_status; + uint32_t we_irq_status[2]; +}; + +/** + * enum cam_lrme_core_state : LRME core states + * + * @CAM_LRME_CORE_STATE_UNINIT : LRME is in uninit state + * @CAM_LRME_CORE_STATE_INIT : LRME is in init state after probe + * @ CAM_LRME_CORE_STATE_IDLE : LRME is in idle state. Hardware is in + * this state when no frame is processing + * or waiting for this core. + * @CAM_LRME_CORE_STATE_REQ_PENDING : LRME is in pending state. One frame is + * waiting for processing + * @CAM_LRME_CORE_STATE_PROCESSING : LRME is in processing state. HW manager + * can submit one more frame to HW + * @CAM_LRME_CORE_STATE_REQ_PROC_PEND : Indicate two frames are inside HW. + * @CAM_LRME_CORE_STATE_RECOVERY : Indicate core is in the process of reset + * @CAM_LRME_CORE_STATE_MAX : upper limit of states + */ +enum cam_lrme_core_state { + CAM_LRME_CORE_STATE_UNINIT, + CAM_LRME_CORE_STATE_INIT, + CAM_LRME_CORE_STATE_IDLE, + CAM_LRME_CORE_STATE_REQ_PENDING, + CAM_LRME_CORE_STATE_PROCESSING, + CAM_LRME_CORE_STATE_REQ_PROC_PEND, + CAM_LRME_CORE_STATE_RECOVERY, + CAM_LRME_CORE_STATE_MAX, +}; + +/** + * struct cam_lrme_core : LRME HW core information + * + * @hw_info : Pointer to base HW information structure + * @device_iommu : Device iommu handle + * @cdm_iommu : CDM iommu handle + * @hw_caps : Hardware capabilities + * @state : Hardware state + * @reset_complete : Reset completion + * @work : Hardware workqueue to handle irq events + * @work_data : Work data used by hardware workqueue + * @hw_mgr_cb : Hw manager callback + * @req_proc : Pointer to the processing frame request + * @req_submit : Pointer to the frame request waiting for processing + * @hw_cdm_info : CDM information used by this device + * @hw_idx : Hardware index + */ +struct cam_lrme_core { + struct cam_lrme_hw_info *hw_info; + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_lrme_dev_cap hw_caps; + enum cam_lrme_core_state state; + struct completion reset_complete; + struct cam_req_mgr_core_workq *work; + struct cam_lrme_hw_work_data work_data[CAM_LRME_HW_WORKQ_NUM_TASK]; + struct cam_lrme_hw_cmd_set_cb hw_mgr_cb; + struct cam_lrme_frame_request *req_proc; + struct cam_lrme_frame_request *req_submit; + struct cam_lrme_cdm_info *hw_cdm_info; + uint32_t hw_idx; + bool dump_flag; +}; + +/** + * struct cam_lrme_bus_rd_reg_common : Offsets of FE common registers + * + * @hw_version : Offset of hw_version register + * @hw_capability : Offset of hw_capability register + * @sw_reset : Offset of sw_reset register + * @cgc_override : Offset of cgc_override register + * @irq_mask : Offset of irq_mask register + * @irq_clear : Offset of irq_clear register + * @irq_cmd : Offset of irq_cmd register + * @irq_status : Offset of irq_status register + * @cmd : Offset of cmd register + * @irq_set : Offset of irq_set register + * @misr_reset : Offset of misr_reset register + * @security_cfg : Offset of security_cfg register + * @pwr_iso_cfg : Offset of pwr_iso_cfg register + * @pwr_iso_seed : Offset of pwr_iso_seed register + * @test_bus_ctrl : Offset of test_bus_ctrl register + * @spare : Offset of spare register + */ +struct cam_lrme_bus_rd_reg_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_override; + uint32_t irq_mask; + uint32_t irq_clear; + uint32_t irq_cmd; + uint32_t irq_status; + uint32_t cmd; + uint32_t irq_set; + uint32_t misr_reset; + uint32_t security_cfg; + uint32_t pwr_iso_cfg; + uint32_t pwr_iso_seed; + uint32_t test_bus_ctrl; + uint32_t spare; +}; + +/** + * struct cam_lrme_bus_wr_reg_common : Offset of WE common registers + * @hw_version : Offset of hw_version register + * @hw_capability : Offset of hw_capability register + * @sw_reset : Offset of sw_reset register + * @cgc_override : Offset of cgc_override register + * @misr_reset : Offset of misr_reset register + * @pwr_iso_cfg : Offset of pwr_iso_cfg register + * @test_bus_ctrl : Offset of test_bus_ctrl register + * @composite_mask_0 : Offset of composite_mask_0 register + * @irq_mask_0 : Offset of irq_mask_0 register + * @irq_mask_1 : Offset of irq_mask_1 register + * @irq_clear_0 : Offset of irq_clear_0 register + * @irq_clear_1 : Offset of irq_clear_1 register + * @irq_status_0 : Offset of irq_status_0 register + * @irq_status_1 : Offset of irq_status_1 register + * @irq_cmd : Offset of irq_cmd register + * @irq_set_0 : Offset of irq_set_0 register + * @irq_set_1 : Offset of irq_set_1 register + * @addr_fifo_status : Offset of addr_fifo_status register + * @frame_header_cfg0 : Offset of frame_header_cfg0 register + * @frame_header_cfg1 : Offset of frame_header_cfg1 register + * @spare : Offset of spare register + */ +struct cam_lrme_bus_wr_reg_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_override; + uint32_t misr_reset; + uint32_t pwr_iso_cfg; + uint32_t test_bus_ctrl; + uint32_t composite_mask_0; + uint32_t irq_mask_0; + uint32_t irq_mask_1; + uint32_t irq_clear_0; + uint32_t irq_clear_1; + uint32_t irq_status_0; + uint32_t irq_status_1; + uint32_t irq_cmd; + uint32_t irq_set_0; + uint32_t irq_set_1; + uint32_t addr_fifo_status; + uint32_t frame_header_cfg0; + uint32_t frame_header_cfg1; + uint32_t spare; +}; + +/** + * struct cam_lrme_bus_rd_bus_client : Offset of FE registers + * + * @core_cfg : Offset of core_cfg register + * @ccif_meta_data : Offset of ccif_meta_data register + * @addr_image : Offset of addr_image register + * @rd_buffer_size : Offset of rd_buffer_size register + * @rd_stride : Offset of rd_stride register + * @unpack_cfg_0 : Offset of unpack_cfg_0 register + * @latency_buff_allocation : Offset of latency_buff_allocation register + * @burst_limit_cfg : Offset of burst_limit_cfg register + * @misr_cfg_0 : Offset of misr_cfg_0 register + * @misr_cfg_1 : Offset of misr_cfg_1 register + * @misr_rd_val : Offset of misr_rd_val register + * @debug_status_cfg : Offset of debug_status_cfg register + * @debug_status_0 : Offset of debug_status_0 register + * @debug_status_1 : Offset of debug_status_1 register + */ +struct cam_lrme_bus_rd_bus_client { + uint32_t core_cfg; + uint32_t ccif_meta_data; + uint32_t addr_image; + uint32_t rd_buffer_size; + uint32_t rd_stride; + uint32_t unpack_cfg_0; + uint32_t latency_buff_allocation; + uint32_t burst_limit_cfg; + uint32_t misr_cfg_0; + uint32_t misr_cfg_1; + uint32_t misr_rd_val; + uint32_t debug_status_cfg; + uint32_t debug_status_0; + uint32_t debug_status_1; +}; + +/** + * struct cam_lrme_bus_wr_bus_client : Offset of WE registers + * + * @status_0 : Offset of status_0 register + * @status_1 : Offset of status_1 register + * @cfg : Offset of cfg register + * @addr_frame_header : Offset of addr_frame_header register + * @frame_header_cfg : Offset of frame_header_cfg register + * @addr_image : Offset of addr_image register + * @addr_image_offset : Offset of addr_image_offset register + * @buffer_width_cfg : Offset of buffer_width_cfg register + * @buffer_height_cfg : Offset of buffer_height_cfg register + * @packer_cfg : Offset of packer_cfg register + * @wr_stride : Offset of wr_stride register + * @irq_subsample_cfg_period : Offset of irq_subsample_cfg_period register + * @irq_subsample_cfg_pattern : Offset of irq_subsample_cfg_pattern register + * @burst_limit_cfg : Offset of burst_limit_cfg register + * @misr_cfg : Offset of misr_cfg register + * @misr_rd_word_sel : Offset of misr_rd_word_sel register + * @misr_val : Offset of misr_val register + * @debug_status_cfg : Offset of debug_status_cfg register + * @debug_status_0 : Offset of debug_status_0 register + * @debug_status_1 : Offset of debug_status_1 register + */ +struct cam_lrme_bus_wr_bus_client { + uint32_t status_0; + uint32_t status_1; + uint32_t cfg; + uint32_t addr_frame_header; + uint32_t frame_header_cfg; + uint32_t addr_image; + uint32_t addr_image_offset; + uint32_t buffer_width_cfg; + uint32_t buffer_height_cfg; + uint32_t packer_cfg; + uint32_t wr_stride; + uint32_t irq_subsample_cfg_period; + uint32_t irq_subsample_cfg_pattern; + uint32_t burst_limit_cfg; + uint32_t misr_cfg; + uint32_t misr_rd_word_sel; + uint32_t misr_val; + uint32_t debug_status_cfg; + uint32_t debug_status_0; + uint32_t debug_status_1; +}; + +/** + * struct cam_lrme_bus_rd_hw_info : FE registers information + * + * @common_reg : FE common register + * @bus_client_reg : List of FE bus registers information + */ +struct cam_lrme_bus_rd_hw_info { + struct cam_lrme_bus_rd_reg_common common_reg; + struct cam_lrme_bus_rd_bus_client + bus_client_reg[CAM_LRME_BUS_RD_MAX_CLIENTS]; +}; + +/** + * struct cam_lrme_bus_wr_hw_info : WE engine registers information + * + * @common_reg : WE common register + * @bus_client_reg : List of WE bus registers information + */ +struct cam_lrme_bus_wr_hw_info { + struct cam_lrme_bus_wr_reg_common common_reg; + struct cam_lrme_bus_wr_bus_client + bus_client_reg[CAM_LRME_BUS_WR_MAX_CLIENTS]; +}; + +/** + * struct cam_lrme_clc_reg : Offset of clc registers + * + * @clc_hw_version : Offset of clc_hw_version register + * @clc_hw_status : Offset of clc_hw_status register + * @clc_hw_status_dbg : Offset of clc_hw_status_dbg register + * @clc_module_cfg : Offset of clc_module_cfg register + * @clc_moduleformat : Offset of clc_moduleformat register + * @clc_rangestep : Offset of clc_rangestep register + * @clc_offset : Offset of clc_offset register + * @clc_maxallowedsad : Offset of clc_maxallowedsad register + * @clc_minallowedtarmad : Offset of clc_minallowedtarmad register + * @clc_meaningfulsaddiff : Offset of clc_meaningfulsaddiff register + * @clc_minsaddiffdenom : Offset of clc_minsaddiffdenom register + * @clc_robustnessmeasuredistmap_0 : Offset of measuredistmap_0 register + * @clc_robustnessmeasuredistmap_1 : Offset of measuredistmap_1 register + * @clc_robustnessmeasuredistmap_2 : Offset of measuredistmap_2 register + * @clc_robustnessmeasuredistmap_3 : Offset of measuredistmap_3 register + * @clc_robustnessmeasuredistmap_4 : Offset of measuredistmap_4 register + * @clc_robustnessmeasuredistmap_5 : Offset of measuredistmap_5 register + * @clc_robustnessmeasuredistmap_6 : Offset of measuredistmap_6 register + * @clc_robustnessmeasuredistmap_7 : Offset of measuredistmap_7 register + * @clc_ds_crop_horizontal : Offset of clc_ds_crop_horizontal register + * @clc_ds_crop_vertical : Offset of clc_ds_crop_vertical register + * @clc_tar_pd_unpacker : Offset of clc_tar_pd_unpacker register + * @clc_ref_pd_unpacker : Offset of clc_ref_pd_unpacker register + * @clc_sw_override : Offset of clc_sw_override register + * @clc_tar_height : Offset of clc_tar_height register + * @clc_test_bus_ctrl : Offset of clc_test_bus_ctrl register + * @clc_spare : Offset of clc_spare register + */ +struct cam_lrme_clc_reg { + uint32_t clc_hw_version; + uint32_t clc_hw_status; + uint32_t clc_hw_status_dbg; + uint32_t clc_module_cfg; + uint32_t clc_moduleformat; + uint32_t clc_rangestep; + uint32_t clc_offset; + uint32_t clc_maxallowedsad; + uint32_t clc_minallowedtarmad; + uint32_t clc_meaningfulsaddiff; + uint32_t clc_minsaddiffdenom; + uint32_t clc_robustnessmeasuredistmap_0; + uint32_t clc_robustnessmeasuredistmap_1; + uint32_t clc_robustnessmeasuredistmap_2; + uint32_t clc_robustnessmeasuredistmap_3; + uint32_t clc_robustnessmeasuredistmap_4; + uint32_t clc_robustnessmeasuredistmap_5; + uint32_t clc_robustnessmeasuredistmap_6; + uint32_t clc_robustnessmeasuredistmap_7; + uint32_t clc_ds_crop_horizontal; + uint32_t clc_ds_crop_vertical; + uint32_t clc_tar_pd_unpacker; + uint32_t clc_ref_pd_unpacker; + uint32_t clc_sw_override; + uint32_t clc_tar_height; + uint32_t clc_ref_height; + uint32_t clc_test_bus_ctrl; + uint32_t clc_spare; +}; + +/** + * struct cam_lrme_titan_reg : Offset of LRME top registers + * + * @top_hw_version : Offset of top_hw_version register + * @top_titan_version : Offset of top_titan_version register + * @top_rst_cmd : Offset of top_rst_cmd register + * @top_core_clk_cfg : Offset of top_core_clk_cfg register + * @top_irq_status : Offset of top_irq_status register + * @top_irq_mask : Offset of top_irq_mask register + * @top_irq_clear : Offset of top_irq_clear register + * @top_irq_set : Offset of top_irq_set register + * @top_irq_cmd : Offset of top_irq_cmd register + * @top_violation_status : Offset of top_violation_status register + * @top_spare : Offset of top_spare register + */ +struct cam_lrme_titan_reg { + uint32_t top_hw_version; + uint32_t top_titan_version; + uint32_t top_rst_cmd; + uint32_t top_core_clk_cfg; + uint32_t top_irq_status; + uint32_t top_irq_mask; + uint32_t top_irq_clear; + uint32_t top_irq_set; + uint32_t top_irq_cmd; + uint32_t top_violation_status; + uint32_t top_spare; +}; + +/** + * struct cam_lrme_hw_info : LRME registers information + * + * @clc_reg : LRME CLC registers + * @bus_rd_reg : LRME FE registers + * @bus_wr_reg : LRME WE registers + * @titan_reg : LRME top reisters + */ +struct cam_lrme_hw_info { + struct cam_lrme_clc_reg clc_reg; + struct cam_lrme_bus_rd_hw_info bus_rd_reg; + struct cam_lrme_bus_wr_hw_info bus_wr_reg; + struct cam_lrme_titan_reg titan_reg; +}; + +int cam_lrme_hw_process_irq(void *priv, void *data); +int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, + uint32_t arg_size); +int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size); +int cam_lrme_hw_stop(void *hw_priv, void *stop_args, uint32_t arg_size); +int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size); +irqreturn_t cam_lrme_hw_irq(int irq_num, void *data); +int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw, + struct cam_lrme_dev_cap *hw_caps); +int cam_lrme_hw_start(void *hw_priv, void *hw_init_args, uint32_t arg_size); +int cam_lrme_hw_flush(void *hw_priv, void *hw_flush_args, uint32_t arg_size); +void cam_lrme_set_irq(struct cam_hw_info *lrme_hw, enum cam_lrme_irq_set set); + +#endif /* _CAM_LRME_HW_CORE_H_ */ diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c new file mode 100644 index 000000000000..20828f629b4d --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_subdev.h" +#include "cam_lrme_hw_intf.h" +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" +#include "cam_lrme_hw_reg.h" +#include "cam_req_mgr_workq.h" +#include "cam_lrme_hw_mgr.h" +#include "cam_mem_mgr_api.h" +#include "cam_smmu_api.h" + +static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core, + struct cam_hw_info *lrme_hw) +{ + int rc, i; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_cdm_acquire_data cdm_acquire; + struct cam_lrme_cdm_info *hw_cdm_info; + + hw_cdm_info = kzalloc(sizeof(struct cam_lrme_cdm_info), + GFP_KERNEL); + if (!hw_cdm_info) { + CAM_ERR(CAM_LRME, "No memory for hw_cdm_info"); + return -ENOMEM; + } + + cdm_cmd = kzalloc((sizeof(struct cam_cdm_bl_request) + + ((CAM_LRME_MAX_HW_ENTRIES - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!cdm_cmd) { + CAM_ERR(CAM_LRME, "No memory for cdm_cmd"); + kfree(hw_cdm_info); + return -ENOMEM; + } + + memset(&cdm_acquire, 0, sizeof(cdm_acquire)); + strlcpy(cdm_acquire.identifier, "lrmecdm", sizeof("lrmecdm")); + cdm_acquire.cell_index = lrme_hw->soc_info.index; + cdm_acquire.handle = 0; + cdm_acquire.userdata = hw_cdm_info; + cdm_acquire.cam_cdm_callback = NULL; + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.base_array_cnt = lrme_hw->soc_info.num_reg_map; + for (i = 0; i < lrme_hw->soc_info.num_reg_map; i++) + cdm_acquire.base_array[i] = &lrme_hw->soc_info.reg_map[i]; + + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_LRME, "Can't acquire cdm"); + goto error; + } + + hw_cdm_info->cdm_cmd = cdm_cmd; + hw_cdm_info->cdm_ops = cdm_acquire.ops; + hw_cdm_info->cdm_handle = cdm_acquire.handle; + + lrme_core->hw_cdm_info = hw_cdm_info; + CAM_DBG(CAM_LRME, "cdm acquire done"); + + return 0; +error: + kfree(cdm_cmd); + kfree(hw_cdm_info); + return rc; +} + +static int cam_lrme_hw_dev_probe(struct platform_device *pdev) +{ + struct cam_hw_info *lrme_hw; + struct cam_hw_intf lrme_hw_intf; + struct cam_lrme_core *lrme_core; + const struct of_device_id *match_dev = NULL; + struct cam_lrme_hw_info *hw_info; + int rc, i; + + lrme_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!lrme_hw) { + CAM_ERR(CAM_LRME, "No memory to create lrme_hw"); + return -ENOMEM; + } + + lrme_core = kzalloc(sizeof(struct cam_lrme_core), GFP_KERNEL); + if (!lrme_core) { + CAM_ERR(CAM_LRME, "No memory to create lrme_core"); + kfree(lrme_hw); + return -ENOMEM; + } + + lrme_hw->core_info = lrme_core; + lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + lrme_hw->soc_info.pdev = pdev; + lrme_hw->soc_info.dev = &pdev->dev; + lrme_hw->soc_info.dev_name = pdev->name; + lrme_hw->open_count = 0; + lrme_core->state = CAM_LRME_CORE_STATE_INIT; + + mutex_init(&lrme_hw->hw_mutex); + spin_lock_init(&lrme_hw->hw_lock); + init_completion(&lrme_hw->hw_complete); + init_completion(&lrme_core->reset_complete); + + rc = cam_req_mgr_workq_create("cam_lrme_hw_worker", + CAM_LRME_HW_WORKQ_NUM_TASK, + &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc); + goto free_memory; + } + + for (i = 0; i < CAM_LRME_HW_WORKQ_NUM_TASK; i++) + lrme_core->work->task.pool[i].payload = + &lrme_core->work_data[i]; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev || !match_dev->data) { + CAM_ERR(CAM_LRME, "No Of_match data, %pK", match_dev); + rc = -EINVAL; + goto destroy_workqueue; + } + hw_info = (struct cam_lrme_hw_info *)match_dev->data; + lrme_core->hw_info = hw_info; + + rc = cam_lrme_soc_init_resources(&lrme_hw->soc_info, + cam_lrme_hw_irq, lrme_hw); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to init soc, rc=%d", rc); + goto destroy_workqueue; + } + + rc = cam_lrme_hw_dev_util_cdm_acquire(lrme_core, lrme_hw); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to acquire cdm"); + goto deinit_platform_res; + } + + rc = cam_smmu_get_handle("lrme", &lrme_core->device_iommu.non_secure); + if (rc) { + CAM_ERR(CAM_LRME, "Get iommu handle failed"); + goto release_cdm; + } + + rc = cam_lrme_hw_start(lrme_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc); + goto detach_smmu; + } + + rc = cam_lrme_hw_util_get_caps(lrme_hw, &lrme_core->hw_caps); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw caps, rc=%d", rc); + if (cam_lrme_hw_stop(lrme_hw, NULL, 0)) + CAM_ERR(CAM_LRME, "Failed in hw deinit"); + goto detach_smmu; + } + + rc = cam_lrme_hw_stop(lrme_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc); + goto detach_smmu; + } + + lrme_core->hw_idx = lrme_hw->soc_info.index; + lrme_hw_intf.hw_priv = lrme_hw; + lrme_hw_intf.hw_idx = lrme_hw->soc_info.index; + lrme_hw_intf.hw_ops.get_hw_caps = cam_lrme_hw_get_caps; + lrme_hw_intf.hw_ops.init = NULL; + lrme_hw_intf.hw_ops.deinit = NULL; + lrme_hw_intf.hw_ops.reset = cam_lrme_hw_reset; + lrme_hw_intf.hw_ops.reserve = NULL; + lrme_hw_intf.hw_ops.release = NULL; + lrme_hw_intf.hw_ops.start = cam_lrme_hw_start; + lrme_hw_intf.hw_ops.stop = cam_lrme_hw_stop; + lrme_hw_intf.hw_ops.read = NULL; + lrme_hw_intf.hw_ops.write = NULL; + lrme_hw_intf.hw_ops.process_cmd = cam_lrme_hw_process_cmd; + lrme_hw_intf.hw_ops.flush = cam_lrme_hw_flush; + lrme_hw_intf.hw_type = CAM_HW_LRME; + + rc = cam_cdm_get_iommu_handle("lrmecdm", &lrme_core->cdm_iommu); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to acquire the CDM iommu handles"); + goto detach_smmu; + } + + rc = cam_lrme_mgr_register_device(&lrme_hw_intf, + &lrme_core->device_iommu, + &lrme_core->cdm_iommu); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to register device"); + goto detach_smmu; + } + + platform_set_drvdata(pdev, lrme_hw); + CAM_DBG(CAM_LRME, "LRME-%d probe successful", lrme_hw_intf.hw_idx); + + return rc; + +detach_smmu: + cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure); +release_cdm: + cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle); + kfree(lrme_core->hw_cdm_info->cdm_cmd); + kfree(lrme_core->hw_cdm_info); +deinit_platform_res: + if (cam_lrme_soc_deinit_resources(&lrme_hw->soc_info)) + CAM_ERR(CAM_LRME, "Failed in soc deinit"); + mutex_destroy(&lrme_hw->hw_mutex); +destroy_workqueue: + cam_req_mgr_workq_destroy(&lrme_core->work); +free_memory: + mutex_destroy(&lrme_hw->hw_mutex); + kfree(lrme_hw); + kfree(lrme_core); + + return rc; +} + +static int cam_lrme_hw_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + + lrme_hw = platform_get_drvdata(pdev); + if (!lrme_hw) { + CAM_ERR(CAM_LRME, "Invalid lrme_hw from fd_hw_intf"); + rc = -ENODEV; + goto deinit_platform_res; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + if (!lrme_core) { + CAM_ERR(CAM_LRME, "Invalid lrme_core from fd_hw"); + rc = -EINVAL; + goto deinit_platform_res; + } + + cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure); + cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle); + cam_lrme_mgr_deregister_device(lrme_core->hw_idx); + + kfree(lrme_core->hw_cdm_info->cdm_cmd); + kfree(lrme_core->hw_cdm_info); + kfree(lrme_core); + +deinit_platform_res: + rc = cam_lrme_soc_deinit_resources(&lrme_hw->soc_info); + if (rc) + CAM_ERR(CAM_LRME, "Error in LRME soc deinit, rc=%d", rc); + + mutex_destroy(&lrme_hw->hw_mutex); + kfree(lrme_hw); + + return rc; +} + +static const struct of_device_id cam_lrme_hw_dt_match[] = { + { + .compatible = "qcom,lrme", + .data = &cam_lrme10_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_lrme_hw_dt_match); + +static struct platform_driver cam_lrme_hw_driver = { + .probe = cam_lrme_hw_dev_probe, + .remove = cam_lrme_hw_dev_remove, + .driver = { + .name = "cam_lrme_hw", + .owner = THIS_MODULE, + .of_match_table = cam_lrme_hw_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_lrme_hw_init_module(void) +{ + return platform_driver_register(&cam_lrme_hw_driver); +} + +static void __exit cam_lrme_hw_exit_module(void) +{ + platform_driver_unregister(&cam_lrme_hw_driver); +} + +module_init(cam_lrme_hw_init_module); +module_exit(cam_lrme_hw_exit_module); +MODULE_DESCRIPTION("CAM LRME HW driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h new file mode 100644 index 000000000000..b74d53700419 --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_INTF_H_ +#define _CAM_LRME_HW_INTF_H_ + +#include +#include +#include +#include +#include +#include + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_subdev.h" +#include "cam_cpas_api.h" +#include "cam_hw_mgr_intf.h" +#include "cam_debug_util.h" + + +#define CAM_LRME_MAX_IO_BUFFER 2 +#define CAM_LRME_MAX_HW_ENTRIES 5 + +#define CAM_LRME_BASE_IDX 0 + +/** + * enum cam_lrme_hw_type : Enum for LRME HW type + * + * @CAM_HW_LRME : LRME HW type + */ +enum cam_lrme_hw_type { + CAM_HW_LRME, +}; + +/** + * enum cam_lrme_cb_type : HW manager call back type + * + * @CAM_LRME_CB_BUF_DONE : Indicate buf done has been generated + * @CAM_LRME_CB_COMP_REG_UPDATE : Indicate receiving WE comp reg update + * @CAM_LRME_CB_PUT_FRAME : Request HW manager to put back the frame + * @CAM_LRME_CB_ERROR : Indicate error irq has been generated + */ +enum cam_lrme_cb_type { + CAM_LRME_CB_BUF_DONE = 1, + CAM_LRME_CB_COMP_REG_UPDATE = 1 << 1, + CAM_LRME_CB_PUT_FRAME = 1 << 2, + CAM_LRME_CB_ERROR = 1 << 3, +}; + +/** + * enum cam_lrme_hw_cmd_type : HW CMD type + * + * @CAM_LRME_HW_CMD_prepare_hw_update : Prepare HW update + * @CAM_LRME_HW_CMD_REGISTER_CB : register HW manager callback + * @CAM_LRME_HW_CMD_SUBMIT : Submit frame to HW + * @CAM_LRME_HW_CMD_DUMP_REGISTER : dump register values + */ +enum cam_lrme_hw_cmd_type { + CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, + CAM_LRME_HW_CMD_REGISTER_CB, + CAM_LRME_HW_CMD_SUBMIT, + CAM_LRME_HW_CMD_DUMP_REGISTER, +}; + +/** + * enum cam_lrme_hw_reset_type : Type of reset + * + * @CAM_LRME_HW_RESET_TYPE_HW_RESET : HW reset + * @CAM_LRME_HW_RESET_TYPE_SW_RESET : SW reset + */ +enum cam_lrme_hw_reset_type { + CAM_LRME_HW_RESET_TYPE_HW_RESET, + CAM_LRME_HW_RESET_TYPE_SW_RESET, +}; + +/** + *struct cam_lrme_frame_request : LRME frame request + * + * @frame_list : List head + * @req_id : Request ID + * @ctxt_to_hw_map : Information about context id, priority and device id + * @hw_device : Pointer to HW device + * @hw_update_entries : List of hw_update_entries + * @num_hw_update_entries : number of hw_update_entries + */ +struct cam_lrme_frame_request { + struct list_head frame_list; + uint64_t req_id; + void *ctxt_to_hw_map; + struct cam_lrme_device *hw_device; + struct cam_hw_update_entry hw_update_entries[CAM_LRME_MAX_HW_ENTRIES]; + uint32_t num_hw_update_entries; +}; + +/** + * struct cam_lrme_hw_io_buffer : IO buffer information + * + * @valid : Indicate whether this IO config is valid + * @io_cfg : Pointer to IO configuration + * @num_buf : Number of buffers + * @num_plane : Number of planes + * @io_addr : List of IO address + */ +struct cam_lrme_hw_io_buffer { + bool valid; + struct cam_buf_io_cfg *io_cfg; + uint32_t num_buf; + uint32_t num_plane; + uint64_t io_addr[CAM_PACKET_MAX_PLANES]; +}; + +/** + * struct cam_lrme_hw_cmd_config_args : Args for prepare HW update + * + * @hw_device : Pointer to HW device + * @input_buf : List of input buffers + * @output_buf : List of output buffers + * @cmd_buf_addr : Pointer to available KMD buffer + * @size : Available KMD buffer size + * @config_buf_size : Size used to prepare update + */ +struct cam_lrme_hw_cmd_config_args { + struct cam_lrme_device *hw_device; + struct cam_lrme_hw_io_buffer input_buf[CAM_LRME_MAX_IO_BUFFER]; + struct cam_lrme_hw_io_buffer output_buf[CAM_LRME_MAX_IO_BUFFER]; + uint32_t *cmd_buf_addr; + uint32_t size; + uint32_t config_buf_size; +}; + +/** + * struct cam_lrme_hw_flush_args : Args for flush HW + * + * @ctxt_to_hw_map : Identity of context + * @req_to_flush : Pointer to the frame need to flush in + * case of single frame flush + * @flush_type : Flush type + */ +struct cam_lrme_hw_flush_args { + void *ctxt_to_hw_map; + struct cam_lrme_frame_request *req_to_flush; + uint32_t flush_type; +}; + +/** + * struct cam_lrme_hw_reset_args : Args for reset HW + * + * @reset_type : Enum cam_lrme_hw_reset_type + */ +struct cam_lrme_hw_reset_args { + uint32_t reset_type; +}; + +/** + * struct cam_lrme_hw_cb_args : HW manager callback args + * + * @cb_type : Callback event type + * @frame_req : Pointer to the frame associated with the cb + */ +struct cam_lrme_hw_cb_args { + uint32_t cb_type; + struct cam_lrme_frame_request *frame_req; +}; + +/** + * struct cam_lrme_hw_cmd_set_cb : Args for set callback function + * + * @cam_lrme_hw_mgr_cb : Callback function pointer + * @data : Data sent along with callback function + */ +struct cam_lrme_hw_cmd_set_cb { + int (*cam_lrme_hw_mgr_cb)(void *data, + struct cam_lrme_hw_cb_args *args); + void *data; +}; + +/** + * struct cam_lrme_hw_submit_args : Args for submit request + * + * @hw_update_entries : List of hw update entries used to program registers + * @num_hw_update_entries : Number of hw update entries + * @frame_req : Pointer to the frame request + */ +struct cam_lrme_hw_submit_args { + struct cam_hw_update_entry *hw_update_entries; + uint32_t num_hw_update_entries; + struct cam_lrme_frame_request *frame_req; +}; + +#endif /* _CAM_LRME_HW_INTF_H_ */ diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h new file mode 100644 index 000000000000..17eb25b0facf --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_REG_H_ +#define _CAM_LRME_HW_REG_H_ + +#include "cam_lrme_hw_core.h" + +static struct cam_lrme_hw_info cam_lrme10_hw_info = { + .clc_reg = { + .clc_hw_version = 0x00000000, + .clc_hw_status = 0x00000004, + .clc_hw_status_dbg = 0x00000008, + .clc_module_cfg = 0x00000060, + .clc_moduleformat = 0x000000A8, + .clc_rangestep = 0x00000068, + .clc_offset = 0x0000006C, + .clc_maxallowedsad = 0x00000070, + .clc_minallowedtarmad = 0x00000074, + .clc_meaningfulsaddiff = 0x00000078, + .clc_minsaddiffdenom = 0x0000007C, + .clc_robustnessmeasuredistmap_0 = 0x00000080, + .clc_robustnessmeasuredistmap_1 = 0x00000084, + .clc_robustnessmeasuredistmap_2 = 0x00000088, + .clc_robustnessmeasuredistmap_3 = 0x0000008C, + .clc_robustnessmeasuredistmap_4 = 0x00000090, + .clc_robustnessmeasuredistmap_5 = 0x00000094, + .clc_robustnessmeasuredistmap_6 = 0x00000098, + .clc_robustnessmeasuredistmap_7 = 0x0000009C, + .clc_ds_crop_horizontal = 0x000000A0, + .clc_ds_crop_vertical = 0x000000A4, + .clc_tar_pd_unpacker = 0x000000AC, + .clc_ref_pd_unpacker = 0x000000B0, + .clc_sw_override = 0x000000B4, + .clc_tar_height = 0x000000B8, + .clc_ref_height = 0x000000BC, + .clc_test_bus_ctrl = 0x000001F8, + .clc_spare = 0x000001FC, + }, + .bus_rd_reg = { + .common_reg = { + .hw_version = 0x00000200, + .hw_capability = 0x00000204, + .sw_reset = 0x00000208, + .cgc_override = 0x0000020C, + .irq_mask = 0x00000210, + .irq_clear = 0x00000214, + .irq_cmd = 0x00000218, + .irq_status = 0x0000021C, + .cmd = 0x00000220, + .irq_set = 0x00000224, + .misr_reset = 0x0000022C, + .security_cfg = 0x00000230, + .pwr_iso_cfg = 0x00000234, + .pwr_iso_seed = 0x00000238, + .test_bus_ctrl = 0x00000248, + .spare = 0x0000024C, + }, + .bus_client_reg = { + /* bus client 0 */ + { + .core_cfg = 0x00000250, + .ccif_meta_data = 0x00000254, + .addr_image = 0x00000258, + .rd_buffer_size = 0x0000025C, + .rd_stride = 0x00000260, + .unpack_cfg_0 = 0x00000264, + .latency_buff_allocation = 0x00000278, + .burst_limit_cfg = 0x00000280, + .misr_cfg_0 = 0x00000284, + .misr_cfg_1 = 0x00000288, + .misr_rd_val = 0x0000028C, + .debug_status_cfg = 0x00000290, + .debug_status_0 = 0x00000294, + .debug_status_1 = 0x00000298, + }, + /* bus client 1 */ + { + .core_cfg = 0x000002F0, + .ccif_meta_data = 0x000002F4, + .addr_image = 0x000002F8, + .rd_buffer_size = 0x000002FC, + .rd_stride = 0x00000300, + .unpack_cfg_0 = 0x00000304, + .latency_buff_allocation = 0x00000318, + .burst_limit_cfg = 0x00000320, + .misr_cfg_0 = 0x00000324, + .misr_cfg_1 = 0x00000328, + .misr_rd_val = 0x0000032C, + .debug_status_cfg = 0x00000330, + .debug_status_0 = 0x00000334, + .debug_status_1 = 0x00000338, + }, + }, + }, + .bus_wr_reg = { + .common_reg = { + .hw_version = 0x00000500, + .hw_capability = 0x00000504, + .sw_reset = 0x00000508, + .cgc_override = 0x0000050C, + .misr_reset = 0x000005C8, + .pwr_iso_cfg = 0x000005CC, + .test_bus_ctrl = 0x0000061C, + .composite_mask_0 = 0x00000510, + .irq_mask_0 = 0x00000544, + .irq_mask_1 = 0x00000548, + .irq_clear_0 = 0x00000550, + .irq_clear_1 = 0x00000554, + .irq_status_0 = 0x0000055C, + .irq_status_1 = 0x00000560, + .irq_cmd = 0x00000568, + .irq_set_0 = 0x000005BC, + .irq_set_1 = 0x000005C0, + .addr_fifo_status = 0x000005A8, + .frame_header_cfg0 = 0x000005AC, + .frame_header_cfg1 = 0x000005B0, + .spare = 0x00000620, + }, + .bus_client_reg = { + /* bus client 0 */ + { + .status_0 = 0x00000700, + .status_1 = 0x00000704, + .cfg = 0x00000708, + .addr_frame_header = 0x0000070C, + .frame_header_cfg = 0x00000710, + .addr_image = 0x00000714, + .addr_image_offset = 0x00000718, + .buffer_width_cfg = 0x0000071C, + .buffer_height_cfg = 0x00000720, + .packer_cfg = 0x00000724, + .wr_stride = 0x00000728, + .irq_subsample_cfg_period = 0x00000748, + .irq_subsample_cfg_pattern = 0x0000074C, + .burst_limit_cfg = 0x0000075C, + .misr_cfg = 0x00000760, + .misr_rd_word_sel = 0x00000764, + .misr_val = 0x00000768, + .debug_status_cfg = 0x0000076C, + .debug_status_0 = 0x00000770, + .debug_status_1 = 0x00000774, + }, + /* bus client 1 */ + { + .status_0 = 0x00000800, + .status_1 = 0x00000804, + .cfg = 0x00000808, + .addr_frame_header = 0x0000080C, + .frame_header_cfg = 0x00000810, + .addr_image = 0x00000814, + .addr_image_offset = 0x00000818, + .buffer_width_cfg = 0x0000081C, + .buffer_height_cfg = 0x00000820, + .packer_cfg = 0x00000824, + .wr_stride = 0x00000828, + .irq_subsample_cfg_period = 0x00000848, + .irq_subsample_cfg_pattern = 0x0000084C, + .burst_limit_cfg = 0x0000085C, + .misr_cfg = 0x00000860, + .misr_rd_word_sel = 0x00000864, + .misr_val = 0x00000868, + .debug_status_cfg = 0x0000086C, + .debug_status_0 = 0x00000870, + .debug_status_1 = 0x00000874, + }, + }, + }, + .titan_reg = { + .top_hw_version = 0x00000900, + .top_titan_version = 0x00000904, + .top_rst_cmd = 0x00000908, + .top_core_clk_cfg = 0x00000920, + .top_irq_status = 0x0000090C, + .top_irq_mask = 0x00000910, + .top_irq_clear = 0x00000914, + .top_irq_set = 0x00000918, + .top_irq_cmd = 0x0000091C, + .top_violation_status = 0x00000924, + .top_spare = 0x000009FC, + }, +}; + +#endif /* _CAM_LRME_HW_REG_H_ */ diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c new file mode 100644 index 000000000000..ba227d2223eb --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" + + +int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_soc_private *soc_private = + (struct cam_lrme_soc_private *)soc_info->soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc = 0; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = 7200000; + axi_vote.axi_path[0].mnoc_ab_bw = 7200000; + axi_vote.axi_path[0].mnoc_ib_bw = 7200000; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = 7200000; + axi_vote.axi_path[1].mnoc_ab_bw = 7200000; + axi_vote.axi_path[1].mnoc_ib_bw = 7200000; + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to start cpas, rc %d", rc); + return -EFAULT; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE, + true); + if (rc) { + CAM_ERR(CAM_LRME, + "Failed to enable platform resource, rc %d", rc); + goto stop_cpas; + } + + cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_ENABLE); + + return rc; + +stop_cpas: + if (cam_cpas_stop(soc_private->cpas_handle)) + CAM_ERR(CAM_LRME, "Failed to stop cpas"); + + return rc; +} + +int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_soc_private *soc_private; + int rc = 0; + + soc_private = soc_info->soc_private; + + cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_DISABLE); + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to disable platform resource"); + return rc; + } + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_LRME, "Failed to stop cpas"); + + return rc; +} + +int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data) +{ + struct cam_lrme_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in get_dt_properties, rc=%d", rc); + return rc; + } + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + private_data); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in request_platform_resource rc=%d", + rc); + return rc; + } + + soc_private = kzalloc(sizeof(struct cam_lrme_soc_private), GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto release_res; + } + soc_info->soc_private = soc_private; + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, + "lrmecpas", CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = &soc_info->pdev->dev; + cpas_register_param.userdata = private_data; + cpas_register_param.cam_cpas_client_cb = NULL; + + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_LRME, "CPAS registration failed"); + goto free_soc_private; + } + soc_private->cpas_handle = cpas_register_param.client_handle; + CAM_DBG(CAM_LRME, "CPAS handle=%d", soc_private->cpas_handle); + + return rc; + +free_soc_private: + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; +release_res: + cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_lrme_soc_private *soc_private = + (struct cam_lrme_soc_private *)soc_info->soc_private; + int rc; + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_LRME, "Unregister cpas failed, handle=%d, rc=%d", + soc_private->cpas_handle, rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_LRME, "release platform failed, rc=%d", rc); + + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; + + return rc; +} diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h new file mode 100644 index 000000000000..d77ac2bfdb63 --- /dev/null +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_SOC_H_ +#define _CAM_LRME_HW_SOC_H_ + +#include "cam_soc_util.h" + +struct cam_lrme_soc_private { + uint32_t cpas_handle; +}; + +int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw); +int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw); +int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data); +int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_LRME_HW_SOC_H_ */ diff --git a/drivers/cam_req_mgr/Makefile b/drivers/cam_req_mgr/Makefile new file mode 100644 index 000000000000..375d17133193 --- /dev/null +++ b/drivers/cam_req_mgr/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_core.o\ + cam_req_mgr_dev.o \ + cam_req_mgr_util.o \ + cam_req_mgr_workq.o \ + cam_mem_mgr.o \ + cam_req_mgr_timer.o \ + cam_req_mgr_debug.o diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c new file mode 100644 index 000000000000..73ac694eeafa --- /dev/null +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -0,0 +1,1391 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_req_mgr_util.h" +#include "cam_mem_mgr.h" +#include "cam_smmu_api.h" +#include "cam_debug_util.h" + +static struct cam_mem_table tbl; +static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); + +static int cam_mem_util_get_dma_dir(uint32_t flags) +{ + int rc = -EINVAL; + + if (flags & CAM_MEM_FLAG_HW_READ_ONLY) + rc = DMA_TO_DEVICE; + else if (flags & CAM_MEM_FLAG_HW_WRITE_ONLY) + rc = DMA_FROM_DEVICE; + else if (flags & CAM_MEM_FLAG_HW_READ_WRITE) + rc = DMA_BIDIRECTIONAL; + else if (flags & CAM_MEM_FLAG_PROTECTED_MODE) + rc = DMA_BIDIRECTIONAL; + + return rc; +} + +static int cam_mem_util_map_cpu_va(struct dma_buf *dmabuf, + uintptr_t *vaddr, + size_t *len) +{ + int i, j, rc; + void *addr; + + /* + * dma_buf_begin_cpu_access() and dma_buf_end_cpu_access() + * need to be called in pair to avoid stability issue. + */ + rc = dma_buf_begin_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + if (rc) { + CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); + return rc; + } + + /* + * Code could be simplified if ION support of dma_buf_vmap is + * available. This workaround takes the avandaage that ion_alloc + * returns a virtually contiguous memory region, so we just need + * to _kmap each individual page and then only use the virtual + * address returned from the first call to _kmap. + */ + for (i = 0; i < PAGE_ALIGN(dmabuf->size) / PAGE_SIZE; i++) { + addr = dma_buf_kmap(dmabuf, i); + if (IS_ERR_OR_NULL(addr)) { + CAM_ERR(CAM_MEM, "kernel map fail"); + for (j = 0; j < i; j++) + dma_buf_kunmap(dmabuf, + j, + (void *)(*vaddr + (j * PAGE_SIZE))); + *vaddr = 0; + *len = 0; + rc = -ENOSPC; + goto fail; + } + if (i == 0) + *vaddr = (uint64_t)addr; + } + + *len = dmabuf->size; + + return 0; + +fail: + dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + return rc; +} +static int cam_mem_util_unmap_cpu_va(struct dma_buf *dmabuf, + uint64_t vaddr) +{ + int i, rc = 0, page_num; + + if (!dmabuf || !vaddr) { + CAM_ERR(CAM_MEM, "Invalid input args %pK %llX", dmabuf, vaddr); + return -EINVAL; + } + + page_num = PAGE_ALIGN(dmabuf->size) / PAGE_SIZE; + + for (i = 0; i < page_num; i++) { + dma_buf_kunmap(dmabuf, i, + (void *)(vaddr + (i * PAGE_SIZE))); + } + + /* + * dma_buf_begin_cpu_access() and + * dma_buf_end_cpu_access() need to be called in pair + * to avoid stability issue. + */ + rc = dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + if (rc) { + CAM_ERR(CAM_MEM, "Failed in end cpu access, dmabuf=%pK", + dmabuf); + return rc; + } + + return rc; +} + +int cam_mem_mgr_init(void) +{ + int i; + int bitmap_size; + + memset(tbl.bufq, 0, sizeof(tbl.bufq)); + + bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long); + tbl.bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!tbl.bitmap) + return -ENOMEM; + + tbl.bits = bitmap_size * BITS_PER_BYTE; + bitmap_zero(tbl.bitmap, tbl.bits); + /* We need to reserve slot 0 because 0 is invalid */ + set_bit(0, tbl.bitmap); + + for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { + tbl.bufq[i].fd = -1; + tbl.bufq[i].buf_handle = -1; + } + mutex_init(&tbl.m_lock); + + atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED); + + return 0; +} + +static int32_t cam_mem_get_slot(void) +{ + int32_t idx; + + mutex_lock(&tbl.m_lock); + idx = find_first_zero_bit(tbl.bitmap, tbl.bits); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + mutex_unlock(&tbl.m_lock); + return -ENOMEM; + } + + set_bit(idx, tbl.bitmap); + tbl.bufq[idx].active = true; + mutex_init(&tbl.bufq[idx].q_lock); + mutex_unlock(&tbl.m_lock); + + return idx; +} + +static void cam_mem_put_slot(int32_t idx) +{ + mutex_lock(&tbl.m_lock); + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].active = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + mutex_destroy(&tbl.bufq[idx].q_lock); + clear_bit(idx, tbl.bitmap); + mutex_unlock(&tbl.m_lock); +} + +int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, + uint64_t *iova_ptr, size_t *len_ptr) +{ + int rc = 0, idx; + + *len_ptr = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) + return -EINVAL; + + if (!tbl.bufq[idx].active) + return -EINVAL; + + mutex_lock(&tbl.bufq[idx].q_lock); + if (buf_handle != tbl.bufq[idx].buf_handle) { + rc = -EINVAL; + goto handle_mismatch; + } + + if (CAM_MEM_MGR_IS_SECURE_HDL(buf_handle)) + rc = cam_smmu_get_stage2_iova(mmu_handle, + tbl.bufq[idx].fd, + iova_ptr, + len_ptr); + else + rc = cam_smmu_get_iova(mmu_handle, + tbl.bufq[idx].fd, + iova_ptr, + len_ptr); + if (rc) { + CAM_ERR(CAM_MEM, + "fail to map buf_hdl:0x%x, mmu_hdl: 0x%x for fd:%d", + buf_handle, mmu_handle, tbl.bufq[idx].fd); + goto handle_mismatch; + } + + CAM_DBG(CAM_MEM, + "handle:0x%x fd:%d iova_ptr:%pK len_ptr:%llu", + mmu_handle, tbl.bufq[idx].fd, iova_ptr, *len_ptr); +handle_mismatch: + mutex_unlock(&tbl.bufq[idx].q_lock); + return rc; +} +EXPORT_SYMBOL(cam_mem_get_io_buf); + +int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) +{ + int idx; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!buf_handle || !vaddr_ptr || !len) + return -EINVAL; + + idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) + return -EINVAL; + + if (!tbl.bufq[idx].active) + return -EPERM; + + if (buf_handle != tbl.bufq[idx].buf_handle) + return -EINVAL; + + if (!(tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)) + return -EINVAL; + + if (tbl.bufq[idx].kmdvaddr) { + *vaddr_ptr = tbl.bufq[idx].kmdvaddr; + *len = tbl.bufq[idx].len; + } else { + CAM_ERR(CAM_MEM, "No KMD access was requested for 0x%x handle", + buf_handle); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(cam_mem_get_cpu_buf); + +int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) +{ + int rc = 0, idx; + uint32_t cache_dir; + unsigned long dmabuf_flag = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd) + return -EINVAL; + + idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) + return -EINVAL; + + mutex_lock(&tbl.bufq[idx].q_lock); + + if (!tbl.bufq[idx].active) { + rc = -EINVAL; + goto end; + } + + if (cmd->buf_handle != tbl.bufq[idx].buf_handle) { + rc = -EINVAL; + goto end; + } + + rc = dma_buf_get_flags(tbl.bufq[idx].dma_buf, &dmabuf_flag); + if (rc) { + CAM_ERR(CAM_MEM, "cache get flags failed %d", rc); + goto end; + } + + if (dmabuf_flag & ION_FLAG_CACHED) { + switch (cmd->mem_cache_ops) { + case CAM_MEM_CLEAN_CACHE: + cache_dir = DMA_TO_DEVICE; + break; + case CAM_MEM_INV_CACHE: + cache_dir = DMA_FROM_DEVICE; + break; + case CAM_MEM_CLEAN_INV_CACHE: + cache_dir = DMA_BIDIRECTIONAL; + break; + default: + CAM_ERR(CAM_MEM, + "invalid cache ops :%d", cmd->mem_cache_ops); + rc = -EINVAL; + goto end; + } + } else { + CAM_DBG(CAM_MEM, "BUF is not cached"); + goto end; + } + + rc = dma_buf_begin_cpu_access(tbl.bufq[idx].dma_buf, + (cmd->mem_cache_ops == CAM_MEM_CLEAN_INV_CACHE) ? + DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + if (rc) { + CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); + goto end; + } + + rc = dma_buf_end_cpu_access(tbl.bufq[idx].dma_buf, + cache_dir); + if (rc) { + CAM_ERR(CAM_MEM, "dma end access failed rc=%d", rc); + goto end; + } + +end: + mutex_unlock(&tbl.bufq[idx].q_lock); + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_cache_ops); + +static int cam_mem_util_get_dma_buf(size_t len, + unsigned int heap_id_mask, + unsigned int flags, + struct dma_buf **buf) +{ + int rc = 0; + + if (!buf) { + CAM_ERR(CAM_MEM, "Invalid params"); + return -EINVAL; + } + + *buf = ion_alloc(len, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*buf)) + return -ENOMEM; + + return rc; +} + +static int cam_mem_util_get_dma_buf_fd(size_t len, + size_t align, + unsigned int heap_id_mask, + unsigned int flags, + struct dma_buf **buf, + int *fd) +{ + struct dma_buf *dmabuf = NULL; + int rc = 0; + + if (!buf || !fd) { + CAM_ERR(CAM_MEM, "Invalid params, buf=%pK, fd=%pK", buf, fd); + return -EINVAL; + } + + *buf = ion_alloc(len, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*buf)) + return -ENOMEM; + + *fd = dma_buf_fd(*buf, O_CLOEXEC); + if (*fd < 0) { + CAM_ERR(CAM_MEM, "get fd fail, *fd=%d", *fd); + rc = -EINVAL; + goto get_fd_fail; + } + + /* + * increment the ref count so that ref count becomes 2 here + * when we close fd, refcount becomes 1 and when we do + * dmap_put_buf, ref count becomes 0 and memory will be freed. + */ + dmabuf = dma_buf_get(*fd); + if (IS_ERR_OR_NULL(dmabuf)) { + CAM_ERR(CAM_MEM, "dma_buf_get failed, *fd=%d", *fd); + rc = -EINVAL; + } + + return rc; + +get_fd_fail: + dma_buf_put(*buf); + return rc; +} + +static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, + struct dma_buf **dmabuf, + int *fd) +{ + uint32_t heap_id; + uint32_t ion_flag = 0; + int rc; + + if ((cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) && + (cmd->flags & CAM_MEM_FLAG_CDSP_OUTPUT)) { + heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID); + ion_flag |= + ION_FLAG_SECURE | ION_FLAG_CP_CAMERA | ION_FLAG_CP_CDSP; + } else if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) { + heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID); + ion_flag |= ION_FLAG_SECURE | ION_FLAG_CP_CAMERA; + } else { + heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) | + ION_HEAP(ION_CAMERA_HEAP_ID); + } + + if (cmd->flags & CAM_MEM_FLAG_CACHE) + ion_flag |= ION_FLAG_CACHED; + else + ion_flag &= ~ION_FLAG_CACHED; + + rc = cam_mem_util_get_dma_buf_fd(cmd->len, + cmd->align, + heap_id, + ion_flag, + dmabuf, + fd); + + return rc; +} + + +static int cam_mem_util_check_alloc_flags(struct cam_mem_mgr_alloc_cmd *cmd) +{ + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", + CAM_MEM_MMU_MAX_HANDLE); + return -EINVAL; + } + + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && + cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); + return -EINVAL; + } + + return 0; +} + +static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd) +{ + if (!cmd->flags) { + CAM_ERR(CAM_MEM, "Invalid flags"); + return -EINVAL; + } + + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_MEM, "Num of mmu hdl %d exceeded maximum(%d)", + cmd->num_hdl, CAM_MEM_MMU_MAX_HANDLE); + return -EINVAL; + } + + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && + cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + CAM_ERR(CAM_MEM, + "Kernel mapping in secure mode not allowed, flags=0x%x", + cmd->flags); + return -EINVAL; + } + + if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { + CAM_ERR(CAM_MEM, + "Shared memory buffers are not allowed to be mapped"); + return -EINVAL; + } + + return 0; +} + +static int cam_mem_util_map_hw_va(uint32_t flags, + int32_t *mmu_hdls, + int32_t num_hdls, + int fd, + dma_addr_t *hw_vaddr, + size_t *len, + enum cam_smmu_region_id region) +{ + int i; + int rc = -1; + int dir = cam_mem_util_get_dma_dir(flags); + + if (dir < 0) { + CAM_ERR(CAM_MEM, "fail to map DMA direction, dir=%d", dir); + return dir; + } + + CAM_DBG(CAM_MEM, + "map_hw_va : fd = %d, flags = 0x%x, dir=%d, num_hdls=%d", + fd, flags, dir, num_hdls); + + if (flags & CAM_MEM_FLAG_PROTECTED_MODE) { + for (i = 0; i < num_hdls; i++) { + rc = cam_smmu_map_stage2_iova(mmu_hdls[i], + fd, + dir, + hw_vaddr, + len); + + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed to securely map to smmu, i=%d, fd=%d, dir=%d, mmu_hdl=%d, rc=%d", + i, fd, dir, mmu_hdls[i], rc); + goto multi_map_fail; + } + } + } else { + for (i = 0; i < num_hdls; i++) { + rc = cam_smmu_map_user_iova(mmu_hdls[i], + fd, + dir, + (dma_addr_t *)hw_vaddr, + len, + region); + + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed to map to smmu, i=%d, fd=%d, dir=%d, mmu_hdl=%d, region=%d, rc=%d", + i, fd, dir, mmu_hdls[i], region, rc); + goto multi_map_fail; + } + } + } + + return rc; +multi_map_fail: + if (flags & CAM_MEM_FLAG_PROTECTED_MODE) + for (--i; i > 0; i--) + cam_smmu_unmap_stage2_iova(mmu_hdls[i], fd); + else + for (--i; i > 0; i--) + cam_smmu_unmap_user_iova(mmu_hdls[i], + fd, + CAM_SMMU_REGION_IO); + return rc; + +} + +int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) +{ + int rc; + int32_t idx; + struct dma_buf *dmabuf = NULL; + int fd = -1; + dma_addr_t hw_vaddr = 0; + size_t len; + uintptr_t kvaddr = 0; + size_t klen; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_MEM, " Invalid argument"); + return -EINVAL; + } + len = cmd->len; + + rc = cam_mem_util_check_alloc_flags(cmd); + if (rc) { + CAM_ERR(CAM_MEM, "Invalid flags: flags = 0x%X, rc=%d", + cmd->flags, rc); + return rc; + } + + rc = cam_mem_util_ion_alloc(cmd, + &dmabuf, + &fd); + if (rc) { + CAM_ERR(CAM_MEM, + "Ion Alloc failed, len=%llu, align=%llu, flags=0x%x, num_hdl=%d", + cmd->len, cmd->align, cmd->flags, cmd->num_hdl); + return rc; + } + + idx = cam_mem_get_slot(); + if (idx < 0) { + CAM_ERR(CAM_MEM, "Failed in getting mem slot, idx=%d", idx); + rc = -ENOMEM; + goto slot_fail; + } + + if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) || + (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) || + (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) { + + enum cam_smmu_region_id region; + + if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + + + if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) + region = CAM_SMMU_REGION_SHARED; + + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) + region = CAM_SMMU_REGION_SECHEAP; + + rc = cam_mem_util_map_hw_va(cmd->flags, + cmd->mmu_hdls, + cmd->num_hdl, + fd, + &hw_vaddr, + &len, + region); + + if (rc) { + CAM_ERR(CAM_MEM, + "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->flags, fd, region, cmd->num_hdl, rc); + goto map_hw_fail; + } + } + + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].fd = fd; + tbl.bufq[idx].dma_buf = NULL; + tbl.bufq[idx].flags = cmd->flags; + tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, fd); + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) + CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true); + + if (cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + rc = cam_mem_util_map_cpu_va(dmabuf, &kvaddr, &klen); + if (rc) { + CAM_ERR(CAM_MEM, "dmabuf: %pK mapping failed: %d", + dmabuf, rc); + goto map_kernel_fail; + } + } + + tbl.bufq[idx].kmdvaddr = kvaddr; + tbl.bufq[idx].vaddr = hw_vaddr; + tbl.bufq[idx].dma_buf = dmabuf; + tbl.bufq[idx].len = cmd->len; + tbl.bufq[idx].num_hdl = cmd->num_hdl; + memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls, + sizeof(int32_t) * cmd->num_hdl); + tbl.bufq[idx].is_imported = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + + cmd->out.buf_handle = tbl.bufq[idx].buf_handle; + cmd->out.fd = tbl.bufq[idx].fd; + cmd->out.vaddr = 0; + + CAM_DBG(CAM_MEM, + "fd=%d, flags=0x%x, num_hdl=%d, idx=%d, buf handle=%x, len=%zu", + cmd->out.fd, cmd->flags, cmd->num_hdl, idx, cmd->out.buf_handle, + tbl.bufq[idx].len); + + return rc; + +map_kernel_fail: + mutex_unlock(&tbl.bufq[idx].q_lock); +map_hw_fail: + cam_mem_put_slot(idx); +slot_fail: + dma_buf_put(dmabuf); + return rc; +} + +int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) +{ + int32_t idx; + int rc; + struct dma_buf *dmabuf; + dma_addr_t hw_vaddr = 0; + size_t len = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd || (cmd->fd < 0)) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_MEM, "Num of mmu hdl %d exceeded maximum(%d)", + cmd->num_hdl, CAM_MEM_MMU_MAX_HANDLE); + return -EINVAL; + } + + rc = cam_mem_util_check_map_flags(cmd); + if (rc) { + CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags); + return rc; + } + + dmabuf = dma_buf_get(cmd->fd); + if (IS_ERR_OR_NULL((void *)(dmabuf))) { + CAM_ERR(CAM_MEM, "Failed to import dma_buf fd"); + return -EINVAL; + } + + if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) || + (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) { + rc = cam_mem_util_map_hw_va(cmd->flags, + cmd->mmu_hdls, + cmd->num_hdl, + cmd->fd, + &hw_vaddr, + &len, + CAM_SMMU_REGION_IO); + if (rc) { + CAM_ERR(CAM_MEM, + "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->flags, cmd->fd, CAM_SMMU_REGION_IO, + cmd->num_hdl, rc); + goto map_fail; + } + } + + idx = cam_mem_get_slot(); + if (idx < 0) { + rc = -ENOMEM; + goto map_fail; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].fd = cmd->fd; + tbl.bufq[idx].dma_buf = NULL; + tbl.bufq[idx].flags = cmd->flags; + tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, cmd->fd); + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) + CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true); + tbl.bufq[idx].kmdvaddr = 0; + + if (cmd->num_hdl > 0) + tbl.bufq[idx].vaddr = hw_vaddr; + else + tbl.bufq[idx].vaddr = 0; + + tbl.bufq[idx].dma_buf = dmabuf; + tbl.bufq[idx].len = len; + tbl.bufq[idx].num_hdl = cmd->num_hdl; + memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls, + sizeof(int32_t) * cmd->num_hdl); + tbl.bufq[idx].is_imported = true; + mutex_unlock(&tbl.bufq[idx].q_lock); + + cmd->out.buf_handle = tbl.bufq[idx].buf_handle; + cmd->out.vaddr = 0; + + CAM_DBG(CAM_MEM, + "fd=%d, flags=0x%x, num_hdl=%d, idx=%d, buf handle=%x, len=%zu", + cmd->fd, cmd->flags, cmd->num_hdl, idx, cmd->out.buf_handle, + tbl.bufq[idx].len); + + return rc; + +map_fail: + dma_buf_put(dmabuf); + return rc; +} + +static int cam_mem_util_unmap_hw_va(int32_t idx, + enum cam_smmu_region_id region, + enum cam_smmu_mapping_client client) +{ + int i; + uint32_t flags; + int32_t *mmu_hdls; + int num_hdls; + int fd; + int rc = 0; + + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index"); + return -EINVAL; + } + + flags = tbl.bufq[idx].flags; + mmu_hdls = tbl.bufq[idx].hdls; + num_hdls = tbl.bufq[idx].num_hdl; + fd = tbl.bufq[idx].fd; + + CAM_DBG(CAM_MEM, + "unmap_hw_va : idx=%d, fd=%x, flags=0x%x, num_hdls=%d, client=%d", + idx, fd, flags, num_hdls, client); + + if (flags & CAM_MEM_FLAG_PROTECTED_MODE) { + for (i = 0; i < num_hdls; i++) { + rc = cam_smmu_unmap_stage2_iova(mmu_hdls[i], fd); + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed in secure unmap, i=%d, fd=%d, mmu_hdl=%d, rc=%d", + i, fd, mmu_hdls[i], rc); + goto unmap_end; + } + } + } else { + for (i = 0; i < num_hdls; i++) { + if (client == CAM_SMMU_MAPPING_USER) { + rc = cam_smmu_unmap_user_iova(mmu_hdls[i], + fd, region); + } else if (client == CAM_SMMU_MAPPING_KERNEL) { + rc = cam_smmu_unmap_kernel_iova(mmu_hdls[i], + tbl.bufq[idx].dma_buf, region); + } else { + CAM_ERR(CAM_MEM, + "invalid caller for unmapping : %d", + client); + rc = -EINVAL; + } + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed in unmap, i=%d, fd=%d, mmu_hdl=%d, region=%d, rc=%d", + i, fd, mmu_hdls[i], region, rc); + goto unmap_end; + } + } + } + + return rc; + +unmap_end: + CAM_ERR(CAM_MEM, "unmapping failed"); + return rc; +} + +static void cam_mem_mgr_unmap_active_buf(int idx) +{ + enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; + + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) + region = CAM_SMMU_REGION_SHARED; + else if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + + cam_mem_util_unmap_hw_va(idx, region, CAM_SMMU_MAPPING_USER); +} + +static int cam_mem_mgr_cleanup_table(void) +{ + int i; + + mutex_lock(&tbl.m_lock); + for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { + if (!tbl.bufq[i].active) { + CAM_DBG(CAM_MEM, + "Buffer inactive at idx=%d, continuing", i); + continue; + } else { + CAM_DBG(CAM_MEM, + "Active buffer at idx=%d, possible leak needs unmapping", + i); + cam_mem_mgr_unmap_active_buf(i); + } + + mutex_lock(&tbl.bufq[i].q_lock); + if (tbl.bufq[i].dma_buf) { + dma_buf_put(tbl.bufq[i].dma_buf); + tbl.bufq[i].dma_buf = NULL; + } + tbl.bufq[i].fd = -1; + tbl.bufq[i].flags = 0; + tbl.bufq[i].buf_handle = -1; + tbl.bufq[i].vaddr = 0; + tbl.bufq[i].len = 0; + memset(tbl.bufq[i].hdls, 0, + sizeof(int32_t) * tbl.bufq[i].num_hdl); + tbl.bufq[i].num_hdl = 0; + tbl.bufq[i].dma_buf = NULL; + tbl.bufq[i].active = false; + mutex_unlock(&tbl.bufq[i].q_lock); + mutex_destroy(&tbl.bufq[i].q_lock); + } + + bitmap_zero(tbl.bitmap, tbl.bits); + /* We need to reserve slot 0 because 0 is invalid */ + set_bit(0, tbl.bitmap); + mutex_unlock(&tbl.m_lock); + + return 0; +} + +void cam_mem_mgr_deinit(void) +{ + atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_UNINITIALIZED); + cam_mem_mgr_cleanup_table(); + mutex_lock(&tbl.m_lock); + bitmap_zero(tbl.bitmap, tbl.bits); + kfree(tbl.bitmap); + tbl.bitmap = NULL; + mutex_unlock(&tbl.m_lock); + mutex_destroy(&tbl.m_lock); +} + +static int cam_mem_util_unmap(int32_t idx, + enum cam_smmu_mapping_client client) +{ + int rc = 0; + enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; + + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index"); + return -EINVAL; + } + + CAM_DBG(CAM_MEM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx); + + mutex_lock(&tbl.m_lock); + if ((!tbl.bufq[idx].active) && + (tbl.bufq[idx].vaddr) == 0) { + CAM_WARN(CAM_MEM, "Buffer at idx=%d is already unmapped,", + idx); + mutex_unlock(&tbl.m_lock); + return 0; + } + + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) { + if (tbl.bufq[idx].dma_buf && tbl.bufq[idx].kmdvaddr) { + rc = cam_mem_util_unmap_cpu_va(tbl.bufq[idx].dma_buf, + tbl.bufq[idx].kmdvaddr); + if (rc) + CAM_ERR(CAM_MEM, + "Failed, dmabuf=%pK, kmdvaddr=%pK", + tbl.bufq[idx].dma_buf, + (void *) tbl.bufq[idx].kmdvaddr); + } + } + + /* SHARED flag gets precedence, all other flags after it */ + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { + region = CAM_SMMU_REGION_SHARED; + } else { + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + } + + if ((tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE) || + (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) || + (tbl.bufq[idx].flags & CAM_MEM_FLAG_PROTECTED_MODE)) { + if (cam_mem_util_unmap_hw_va(idx, region, client)) + CAM_ERR(CAM_MEM, "Failed, dmabuf=%pK", + tbl.bufq[idx].dma_buf); + if (client == CAM_SMMU_MAPPING_KERNEL) + tbl.bufq[idx].dma_buf = NULL; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].flags = 0; + tbl.bufq[idx].buf_handle = -1; + tbl.bufq[idx].vaddr = 0; + memset(tbl.bufq[idx].hdls, 0, + sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE); + + CAM_DBG(CAM_MEM, + "Ion buf at idx = %d freeing fd = %d, imported %d, dma_buf %pK", + idx, tbl.bufq[idx].fd, + tbl.bufq[idx].is_imported, + tbl.bufq[idx].dma_buf); + + if (tbl.bufq[idx].dma_buf) + dma_buf_put(tbl.bufq[idx].dma_buf); + + tbl.bufq[idx].fd = -1; + tbl.bufq[idx].dma_buf = NULL; + tbl.bufq[idx].is_imported = false; + tbl.bufq[idx].len = 0; + tbl.bufq[idx].num_hdl = 0; + tbl.bufq[idx].active = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + mutex_destroy(&tbl.bufq[idx].q_lock); + clear_bit(idx, tbl.bitmap); + mutex_unlock(&tbl.m_lock); + + return rc; +} + +int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd) +{ + int idx; + int rc; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index %d extracted from mem handle", + idx); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + CAM_ERR(CAM_MEM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != cmd->buf_handle) { + CAM_ERR(CAM_MEM, + "Released buf handle %d not matching within table %d, idx=%d", + cmd->buf_handle, tbl.bufq[idx].buf_handle, idx); + return -EINVAL; + } + + CAM_DBG(CAM_MEM, "Releasing hdl = %x, idx = %d", cmd->buf_handle, idx); + rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_USER); + + return rc; +} + +int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, + struct cam_mem_mgr_memory_desc *out) +{ + struct dma_buf *buf = NULL; + int ion_fd = -1; + int rc = 0; + uint32_t heap_id; + int32_t ion_flag = 0; + uintptr_t kvaddr; + dma_addr_t iova = 0; + size_t request_len = 0; + uint32_t mem_handle; + int32_t idx; + int32_t smmu_hdl = 0; + int32_t num_hdl = 0; + + enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp || !out) { + CAM_ERR(CAM_MEM, "Invalid params"); + return -EINVAL; + } + + if (!(inp->flags & CAM_MEM_FLAG_HW_READ_WRITE || + inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS || + inp->flags & CAM_MEM_FLAG_CACHE)) { + CAM_ERR(CAM_MEM, "Invalid flags for request mem"); + return -EINVAL; + } + + if (inp->flags & CAM_MEM_FLAG_CACHE) + ion_flag |= ION_FLAG_CACHED; + else + ion_flag &= ~ION_FLAG_CACHED; + + heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) | + ION_HEAP(ION_CAMERA_HEAP_ID); + + rc = cam_mem_util_get_dma_buf(inp->size, + heap_id, + ion_flag, + &buf); + + if (rc) { + CAM_ERR(CAM_MEM, "ION alloc failed for shared buffer"); + goto ion_fail; + } else { + CAM_DBG(CAM_MEM, "Got dma_buf = %pK", buf); + } + + /* + * we are mapping kva always here, + * update flags so that we do unmap properly + */ + inp->flags |= CAM_MEM_FLAG_KMD_ACCESS; + rc = cam_mem_util_map_cpu_va(buf, &kvaddr, &request_len); + if (rc) { + CAM_ERR(CAM_MEM, "Failed to get kernel vaddr"); + goto map_fail; + } + + if (!inp->smmu_hdl) { + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); + rc = -EINVAL; + goto smmu_fail; + } + + /* SHARED flag gets precedence, all other flags after it */ + if (inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { + region = CAM_SMMU_REGION_SHARED; + } else { + if (inp->flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + } + + rc = cam_smmu_map_kernel_iova(inp->smmu_hdl, + buf, + CAM_SMMU_MAP_RW, + &iova, + &request_len, + region); + + if (rc < 0) { + CAM_ERR(CAM_MEM, "SMMU mapping failed"); + goto smmu_fail; + } + + smmu_hdl = inp->smmu_hdl; + num_hdl = 1; + + idx = cam_mem_get_slot(); + if (idx < 0) { + rc = -ENOMEM; + goto slot_fail; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + mem_handle = GET_MEM_HANDLE(idx, ion_fd); + tbl.bufq[idx].dma_buf = buf; + tbl.bufq[idx].fd = -1; + tbl.bufq[idx].flags = inp->flags; + tbl.bufq[idx].buf_handle = mem_handle; + tbl.bufq[idx].kmdvaddr = kvaddr; + + tbl.bufq[idx].vaddr = iova; + + tbl.bufq[idx].len = inp->size; + tbl.bufq[idx].num_hdl = num_hdl; + memcpy(tbl.bufq[idx].hdls, &smmu_hdl, + sizeof(int32_t)); + tbl.bufq[idx].is_imported = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + + out->kva = kvaddr; + out->iova = (uint32_t)iova; + out->smmu_hdl = smmu_hdl; + out->mem_handle = mem_handle; + out->len = inp->size; + out->region = region; + + return rc; +slot_fail: + cam_smmu_unmap_kernel_iova(inp->smmu_hdl, + buf, region); +smmu_fail: + cam_mem_util_unmap_cpu_va(buf, kvaddr); +map_fail: + dma_buf_put(buf); +ion_fail: + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_request_mem); + +int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp) +{ + int32_t idx; + int rc; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + if (tbl.bufq[idx].vaddr == 0) { + CAM_ERR(CAM_MEM, "buffer is released already"); + return 0; + } + CAM_ERR(CAM_MEM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != inp->mem_handle) { + CAM_ERR(CAM_MEM, + "Released buf handle not matching within table"); + return -EINVAL; + } + + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); + rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); + + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_release_mem); + +int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, + enum cam_smmu_region_id region, + struct cam_mem_mgr_memory_desc *out) +{ + struct dma_buf *buf = NULL; + int rc = 0; + int ion_fd = -1; + uint32_t heap_id; + dma_addr_t iova = 0; + size_t request_len = 0; + uint32_t mem_handle; + int32_t idx; + int32_t smmu_hdl = 0; + int32_t num_hdl = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp || !out) { + CAM_ERR(CAM_MEM, "Invalid param(s)"); + return -EINVAL; + } + + if (!inp->smmu_hdl) { + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); + return -EINVAL; + } + + if (region != CAM_SMMU_REGION_SECHEAP) { + CAM_ERR(CAM_MEM, "Only secondary heap supported"); + return -EINVAL; + } + + heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) | + ION_HEAP(ION_CAMERA_HEAP_ID); + rc = cam_mem_util_get_dma_buf(inp->size, + heap_id, + 0, + &buf); + + if (rc) { + CAM_ERR(CAM_MEM, "ION alloc failed for sec heap buffer"); + goto ion_fail; + } else { + CAM_DBG(CAM_MEM, "Got dma_buf = %pK", buf); + } + + rc = cam_smmu_reserve_sec_heap(inp->smmu_hdl, + buf, + &iova, + &request_len); + + if (rc) { + CAM_ERR(CAM_MEM, "Reserving secondary heap failed"); + goto smmu_fail; + } + + smmu_hdl = inp->smmu_hdl; + num_hdl = 1; + + idx = cam_mem_get_slot(); + if (idx < 0) { + rc = -ENOMEM; + goto slot_fail; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + mem_handle = GET_MEM_HANDLE(idx, ion_fd); + tbl.bufq[idx].fd = -1; + tbl.bufq[idx].dma_buf = buf; + tbl.bufq[idx].flags = inp->flags; + tbl.bufq[idx].buf_handle = mem_handle; + tbl.bufq[idx].kmdvaddr = 0; + + tbl.bufq[idx].vaddr = iova; + + tbl.bufq[idx].len = request_len; + tbl.bufq[idx].num_hdl = num_hdl; + memcpy(tbl.bufq[idx].hdls, &smmu_hdl, + sizeof(int32_t)); + tbl.bufq[idx].is_imported = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + + out->kva = 0; + out->iova = (uint32_t)iova; + out->smmu_hdl = smmu_hdl; + out->mem_handle = mem_handle; + out->len = request_len; + out->region = region; + + return rc; + +slot_fail: + cam_smmu_release_sec_heap(smmu_hdl); +smmu_fail: + dma_buf_put(buf); +ion_fail: + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_reserve_memory_region); + +int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) +{ + int32_t idx; + int rc; + int32_t smmu_hdl; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + if (inp->region != CAM_SMMU_REGION_SECHEAP) { + CAM_ERR(CAM_MEM, "Only secondary heap supported"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + if (tbl.bufq[idx].vaddr == 0) { + CAM_ERR(CAM_MEM, "buffer is released already"); + return 0; + } + CAM_ERR(CAM_MEM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != inp->mem_handle) { + CAM_ERR(CAM_MEM, + "Released buf handle not matching within table"); + return -EINVAL; + } + + if (tbl.bufq[idx].num_hdl != 1) { + CAM_ERR(CAM_MEM, + "Sec heap region should have only one smmu hdl"); + return -ENODEV; + } + + memcpy(&smmu_hdl, tbl.bufq[idx].hdls, + sizeof(int32_t)); + if (inp->smmu_hdl != smmu_hdl) { + CAM_ERR(CAM_MEM, + "Passed SMMU handle doesn't match with internal hdl"); + return -ENODEV; + } + + rc = cam_smmu_release_sec_heap(inp->smmu_hdl); + if (rc) { + CAM_ERR(CAM_MEM, + "Sec heap region release failed"); + return -ENODEV; + } + + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); + rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); + if (rc) + CAM_ERR(CAM_MEM, "unmapping secondary heap failed"); + + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_free_memory_region); diff --git a/drivers/cam_req_mgr/cam_mem_mgr.h b/drivers/cam_req_mgr/cam_mem_mgr.h new file mode 100644 index 000000000000..6ce30db66fe3 --- /dev/null +++ b/drivers/cam_req_mgr/cam_mem_mgr.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_MEM_MGR_H_ +#define _CAM_MEM_MGR_H_ + +#include +#include +#include +#include "cam_mem_mgr_api.h" + +#define CAM_MEM_BUFQ_MAX 1024 + +/* Enum for possible mem mgr states */ +enum cam_mem_mgr_state { + CAM_MEM_MGR_UNINITIALIZED, + CAM_MEM_MGR_INITIALIZED, +}; + +/*Enum for possible SMMU operations */ +enum cam_smmu_mapping_client { + CAM_SMMU_MAPPING_USER, + CAM_SMMU_MAPPING_KERNEL, +}; + +/** + * struct cam_mem_buf_queue + * + * @dma_buf: pointer to the allocated dma_buf in the table + * @q_lock: mutex lock for buffer + * @hdls: list of mapped handles + * @num_hdl: number of handles + * @fd: file descriptor of buffer + * @buf_handle: unique handle for buffer + * @align: alignment for allocation + * @len: size of buffer + * @flags: attributes of buffer + * @vaddr: IOVA of buffer + * @kmdvaddr: Kernel virtual address + * @active: state of the buffer + * @is_imported: Flag indicating if buffer is imported from an FD in user space + */ +struct cam_mem_buf_queue { + struct dma_buf *dma_buf; + struct mutex q_lock; + int32_t hdls[CAM_MEM_MMU_MAX_HANDLE]; + int32_t num_hdl; + int32_t fd; + int32_t buf_handle; + int32_t align; + size_t len; + uint32_t flags; + uint64_t vaddr; + uintptr_t kmdvaddr; + bool active; + bool is_imported; +}; + +/** + * struct cam_mem_table + * + * @m_lock: mutex lock for table + * @bitmap: bitmap of the mem mgr utility + * @bits: max bits of the utility + * @bufq: array of buffers + */ +struct cam_mem_table { + struct mutex m_lock; + void *bitmap; + size_t bits; + struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX]; +}; + +/** + * @brief: Allocates and maps buffer + * + * @cmd: Allocation information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd); + +/** + * @brief: Releases a buffer reference + * + * @cmd: Buffer release information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd); + +/** + * @brief Maps a buffer + * + * @cmd: Buffer mapping information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd); + +/** + * @brief: Perform cache ops on the buffer + * + * @cmd: Cache ops information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd); + +/** + * @brief: Initializes the memory manager + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_init(void); + +/** + * @brief: Tears down the memory manager + * + * @return None + */ +void cam_mem_mgr_deinit(void); + +#endif /* _CAM_MEM_MGR_H_ */ diff --git a/drivers/cam_req_mgr/cam_mem_mgr_api.h b/drivers/cam_req_mgr/cam_mem_mgr_api.h new file mode 100644 index 000000000000..6141e7cc136b --- /dev/null +++ b/drivers/cam_req_mgr/cam_mem_mgr_api.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_MEM_MGR_API_H_ +#define _CAM_MEM_MGR_API_H_ + +#include +#include "../cam_smmu/cam_smmu_api.h" + +/** + * struct cam_mem_mgr_request_desc + * + * @size : Size of memory requested for allocation + * @align : Alignment of requested memory + * @smmu_hdl: SMMU handle to identify context bank where memory will be mapped + * @flags : Flags to indicate cached/uncached property + * @region : Region where memory should be allocated + */ +struct cam_mem_mgr_request_desc { + uint64_t size; + uint64_t align; + int32_t smmu_hdl; + uint32_t flags; +}; + +/** + * struct cam_mem_mgr_memory_desc + * + * @kva : Kernel virtual address of allocated memory + * @iova : IOVA of allocated memory + * @smmu_hdl : SMMU handle of allocated memory + * @mem_handle : Mem handle identifying allocated memory + * @len : Length of allocated memory + * @region : Region to which allocated memory belongs + */ +struct cam_mem_mgr_memory_desc { + uintptr_t kva; + uint32_t iova; + int32_t smmu_hdl; + uint32_t mem_handle; + uint64_t len; + enum cam_smmu_region_id region; +}; + +/** + * @brief: Requests a memory buffer + * + * @inp: Information specifying requested buffer properties + * @out: Information about allocated buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, + struct cam_mem_mgr_memory_desc *out); + +/** + * @brief: Releases a memory buffer + * + * @inp: Information specifying buffer to be released + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp); + +/** + * @brief: Returns IOVA information about buffer + * + * @buf_handle: Handle of the buffer + * @mmu_handle: SMMU handle where buffer is mapped + * @iova_ptr : Pointer to mmu's iova + * @len_ptr : Length of the buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, + uint64_t *iova_ptr, size_t *len_ptr); + +/** + * @brief: This indicates begin of CPU access. + * Also returns CPU address information about DMA buffer + * + * @buf_handle: Handle for the buffer + * @vaddr_ptr : pointer to kernel virtual address + * @len_ptr : Length of the buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, + size_t *len); + +static inline bool cam_mem_is_secure_buf(int32_t buf_handle) +{ + return CAM_MEM_MGR_IS_SECURE_HDL(buf_handle); +} + +/** + * @brief: Reserves a memory region + * + * @inp: Information specifying requested region properties + * @region : Region which is to be reserved + * @out : Information about reserved region + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, + enum cam_smmu_region_id region, + struct cam_mem_mgr_memory_desc *out); + +/** + * @brief: Frees a memory region + * + * @inp : Information about region which is to be freed + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp); + +#endif /* _CAM_MEM_MGR_API_H_ */ diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c new file mode 100644 index 000000000000..9f11077f05c4 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -0,0 +1,3242 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "cam_req_mgr_interface.h" +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_core.h" +#include "cam_req_mgr_workq.h" +#include "cam_req_mgr_debug.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_req_mgr_dev.h" + +static struct cam_req_mgr_core_device *g_crm_core_dev; +static struct cam_req_mgr_core_link g_links[MAXIMUM_LINKS_PER_SESSION]; + +void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) +{ + link->link_hdl = 0; + link->num_devs = 0; + link->max_delay = CAM_PIPELINE_DELAY_0; + link->workq = NULL; + link->pd_mask = 0; + link->l_dev = NULL; + link->req.in_q = NULL; + link->req.l_tbl = NULL; + link->req.num_tbl = 0; + link->watchdog = NULL; + link->state = CAM_CRM_LINK_STATE_AVAILABLE; + link->parent = NULL; + link->subscribe_event = 0; + link->trigger_mask = 0; + link->sync_link = 0; + link->sync_link_sof_skip = false; + link->open_req_cnt = 0; + link->last_flush_id = 0; + link->initial_sync_req = -1; + link->in_msync_mode = false; + link->retry_cnt = 0; +} + +void cam_req_mgr_handle_core_shutdown(void) +{ + struct cam_req_mgr_core_session *session; + struct cam_req_mgr_core_session *tsession; + struct cam_req_mgr_session_info ses_info; + + if (!list_empty(&g_crm_core_dev->session_head)) { + list_for_each_entry_safe(session, tsession, + &g_crm_core_dev->session_head, entry) { + ses_info.session_hdl = + session->session_hdl; + cam_req_mgr_destroy_session(&ses_info); + } + } +} + +static int __cam_req_mgr_setup_payload(struct cam_req_mgr_core_workq *workq) +{ + int32_t i = 0; + int rc = 0; + struct crm_task_payload *task_data = NULL; + + task_data = kcalloc( + workq->task.num_task, sizeof(*task_data), + GFP_KERNEL); + if (!task_data) { + rc = -ENOMEM; + } else { + for (i = 0; i < workq->task.num_task; i++) + workq->task.pool[i].payload = &task_data[i]; + } + + return rc; +} + +/** + * __cam_req_mgr_find_pd_tbl() + * + * @brief : Find pipeline delay based table pointer which matches delay + * @tbl : Pointer to list of request table + * @delay : Pipeline delay value to be searched for comparison + * + * @return : pointer to request table for matching pipeline delay table. + * + */ +static struct cam_req_mgr_req_tbl *__cam_req_mgr_find_pd_tbl( + struct cam_req_mgr_req_tbl *tbl, int32_t delay) +{ + if (!tbl) + return NULL; + + do { + if (delay != tbl->pd) + tbl = tbl->next; + else + return tbl; + } while (tbl != NULL); + + return NULL; +} + +/** + * __cam_req_mgr_inc_idx() + * + * @brief : Increment val passed by step size and rollover after max_val + * @val : value to be incremented + * @step : amount/step by which val is incremented + * @max_val : max val after which idx will roll over + * + */ +static void __cam_req_mgr_inc_idx(int32_t *val, int32_t step, int32_t max_val) +{ + *val = (*val + step) % max_val; +} + +/** + * __cam_req_mgr_dec_idx() + * + * @brief : Decrement val passed by step size and rollover after max_val + * @val : value to be decremented + * @step : amount/step by which val is decremented + * @max_val : after zero value will roll over to max val + * + */ +static void __cam_req_mgr_dec_idx(int32_t *val, int32_t step, int32_t max_val) +{ + *val = *val - step; + if (*val < 0) + *val = max_val + (*val); +} + +/** + * __cam_req_mgr_inject_delay() + * + * @brief : Check if any pd device is injecting delay + * @tbl : cam_req_mgr_req_tbl + * @curr_idx : slot idx + * + * @return : 0 for success, negative for failure + */ +static int __cam_req_mgr_inject_delay( + struct cam_req_mgr_req_tbl *tbl, + int32_t curr_idx) +{ + struct cam_req_mgr_tbl_slot *slot = NULL; + int rc = 0; + + while (tbl) { + slot = &tbl->slot[curr_idx]; + if (slot->inject_delay > 0) { + slot->inject_delay--; + CAM_DBG(CAM_CRM, + "Delay injected by pd %d device", + tbl->pd); + rc = -EAGAIN; + } + __cam_req_mgr_dec_idx(&curr_idx, tbl->pd_delta, + tbl->num_slots); + tbl = tbl->next; + } + return rc; +} + +/** + * __cam_req_mgr_notify_error_on_link() + * + * @brief : Notify userspace on exceeding max retry + * attempts to apply same req + * @link : link on which the req could not be applied + * + */ +static int __cam_req_mgr_notify_error_on_link( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_connected_device *dev) +{ + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_message msg; + int rc = 0, pd; + + session = (struct cam_req_mgr_core_session *)link->parent; + + pd = dev->dev_info.p_delay; + if (pd >= CAM_PIPELINE_DELAY_MAX) { + CAM_ERR(CAM_CRM, "pd : %d is more than expected", pd); + return -EINVAL; + } + + CAM_ERR(CAM_CRM, + "Notifying userspace to trigger recovery on link 0x%x for session %d", + link->link_hdl, session->session_hdl); + + memset(&msg, 0, sizeof(msg)); + + msg.session_hdl = session->session_hdl; + msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + msg.u.err_msg.request_id = + link->req.apply_data[pd].req_id; + msg.u.err_msg.link_hdl = link->link_hdl; + + CAM_DBG(CAM_CRM, "Failed for device: %s while applying request: %lld", + dev->dev_info.name, link->req.apply_data[pd].req_id); + + rc = cam_req_mgr_notify_message(&msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, + V4L_EVENT_CAM_REQ_MGR_EVENT); + + if (rc) + CAM_ERR(CAM_CRM, + "Error in notifying recovery for session %d link 0x%x rc %d", + session->session_hdl, link->link_hdl, rc); + + return rc; +} + +/** + * __cam_req_mgr_traverse() + * + * @brief : Traverse through pd tables, it will internally cover all linked + * pd tables. Each pd table visited will check if idx passed to its + * in ready state. If ready means all devices linked to the pd table + * have this request id packet ready. Then it calls subsequent pd + * tbl with new idx. New idx value takes into account the delta + * between current pd table and next one. + * @traverse_data: contains all the info to traverse through pd tables + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) +{ + int rc = 0; + int32_t next_idx = traverse_data->idx; + int32_t curr_idx = traverse_data->idx; + struct cam_req_mgr_req_tbl *tbl; + struct cam_req_mgr_apply *apply_data; + struct cam_req_mgr_tbl_slot *slot = NULL; + + if (!traverse_data->tbl || !traverse_data->apply_data) { + CAM_ERR(CAM_CRM, "NULL pointer %pK %pK", + traverse_data->tbl, traverse_data->apply_data); + traverse_data->result = 0; + return -EINVAL; + } + + tbl = traverse_data->tbl; + apply_data = traverse_data->apply_data; + slot = &tbl->slot[curr_idx]; + CAM_DBG(CAM_CRM, + "Enter pd %d idx %d state %d skip %d status %d skip_idx %d", + tbl->pd, curr_idx, tbl->slot[curr_idx].state, + tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status, + traverse_data->in_q->slot[curr_idx].skip_idx); + + /* Check if req is ready or in skip mode or pd tbl is in skip mode */ + if (tbl->slot[curr_idx].state == CRM_REQ_STATE_READY || + traverse_data->in_q->slot[curr_idx].skip_idx == 1 || + tbl->skip_traverse > 0) { + if (tbl->next) { + __cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta, + tbl->num_slots); + traverse_data->idx = next_idx; + traverse_data->tbl = tbl->next; + rc = __cam_req_mgr_traverse(traverse_data); + } + if (rc >= 0) { + SET_SUCCESS_BIT(traverse_data->result, tbl->pd); + + if (traverse_data->validate_only == false) { + apply_data[tbl->pd].pd = tbl->pd; + apply_data[tbl->pd].req_id = + CRM_GET_REQ_ID( + traverse_data->in_q, curr_idx); + apply_data[tbl->pd].idx = curr_idx; + + CAM_DBG(CAM_CRM, "req_id: %lld with pd of %d", + apply_data[tbl->pd].req_id, + apply_data[tbl->pd].pd); + /* + * If traverse is successful decrement + * traverse skip + */ + if (tbl->skip_traverse > 0) { + apply_data[tbl->pd].req_id = -1; + tbl->skip_traverse--; + } + } + } else { + /* linked pd table is not ready for this traverse yet */ + return rc; + } + } else { + /* This pd table is not ready to proceed with asked idx */ + CAM_INFO(CAM_CRM, + "Skip Frame: req: %lld not ready pd: %d open_req count: %d", + CRM_GET_REQ_ID(traverse_data->in_q, curr_idx), + tbl->pd, + traverse_data->open_req_cnt); + SET_FAILURE_BIT(traverse_data->result, tbl->pd); + return -EAGAIN; + } + return 0; +} + +/** + * __cam_req_mgr_in_q_skip_idx() + * + * @brief : Decrement val passed by step size and rollover after max_val + * @in_q : input queue pointer + * @idx : Sets skip_idx bit of the particular slot to true so when traverse + * happens for this idx, no req will be submitted for devices + * handling this idx. + * + */ +static void __cam_req_mgr_in_q_skip_idx(struct cam_req_mgr_req_queue *in_q, + int32_t idx) +{ + in_q->slot[idx].req_id = -1; + in_q->slot[idx].skip_idx = 1; + in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED; + CAM_DBG(CAM_CRM, "SET IDX SKIP on slot= %d", idx); +} + +/** + * __cam_req_mgr_tbl_set_id() + * + * @brief : Set unique id to table + * @tbl : pipeline based table which requires new id + * @req : pointer to request data wihch contains num_tables counter + * + */ +static void __cam_req_mgr_tbl_set_id(struct cam_req_mgr_req_tbl *tbl, + struct cam_req_mgr_req_data *req) +{ + if (!tbl) + return; + do { + tbl->id = req->num_tbl++; + CAM_DBG(CAM_CRM, "%d: pd %d skip_traverse %d delta %d", + tbl->id, tbl->pd, tbl->skip_traverse, + tbl->pd_delta); + tbl = tbl->next; + } while (tbl != NULL); +} + +/** + * __cam_req_mgr_tbl_set_all_skip_cnt() + * + * @brief : Each pd table sets skip value based on delta between itself and + * max pd value. During initial streamon or bubble case this is + * used. That way each pd table skips required num of traverse and + * align themselve with req mgr connected devs. + * @l_tbl : iterates through list of pd tables and sets skip traverse + * + */ +static void __cam_req_mgr_tbl_set_all_skip_cnt( + struct cam_req_mgr_req_tbl **l_tbl) +{ + struct cam_req_mgr_req_tbl *tbl = *l_tbl; + int32_t max_pd; + + if (!tbl) + return; + + max_pd = tbl->pd; + do { + tbl->skip_traverse = max_pd - tbl->pd; + CAM_DBG(CAM_CRM, "%d: pd %d skip_traverse %d delta %d", + tbl->id, tbl->pd, tbl->skip_traverse, + tbl->pd_delta); + tbl = tbl->next; + } while (tbl != NULL); +} + +/** + * __cam_req_mgr_reset_req_slot() + * + * @brief : reset specified idx/slot in input queue as well as all pd tables + * @link : link pointer + * @idx : slot index which will be reset + * + */ +static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, + int32_t idx) +{ + struct cam_req_mgr_slot *slot; + struct cam_req_mgr_req_tbl *tbl = link->req.l_tbl; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + + slot = &in_q->slot[idx]; + CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status); + + /* Check if CSL has already pushed new request*/ + if (slot->status == CRM_SLOT_STATUS_REQ_ADDED) + return; + + /* Reset input queue slot */ + slot->req_id = -1; + slot->skip_idx = 0; + slot->recover = 0; + slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->status = CRM_SLOT_STATUS_NO_REQ; + + /* Reset all pd table slot */ + while (tbl != NULL) { + CAM_DBG(CAM_CRM, "pd: %d: idx %d state %d", + tbl->pd, idx, tbl->slot[idx].state); + tbl->slot[idx].req_ready_map = 0; + tbl->slot[idx].state = CRM_REQ_STATE_EMPTY; + tbl = tbl->next; + } +} + +/** + * __cam_req_mgr_check_for_lower_pd_devices() + * + * @brief : Checks if there are any devices on the link having a lesser + * pd than the max pd of the link + * @link : Pointer to link which needs to be checked + * + * @return : 0 if a lower pd device is found negative otherwise + */ +static int __cam_req_mgr_check_for_lower_pd_devices( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev->dev_info.p_delay < link->max_delay) + return 0; + } + + return -EAGAIN; +} + +/** + * __cam_req_mgr_check_next_req_slot() + * + * @brief : While streaming if input queue does not contain any pending + * request, req mgr still needs to submit pending request ids to + * devices with lower pipeline delay value. + * @in_q : Pointer to input queue where req mgr wil peep into + * + * @return : 0 for success, negative for failure + */ +static int __cam_req_mgr_check_next_req_slot( + struct cam_req_mgr_core_link *link) +{ + int rc = 0; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + int32_t idx = in_q->rd_idx; + struct cam_req_mgr_slot *slot; + + __cam_req_mgr_inc_idx(&idx, 1, in_q->num_slots); + slot = &in_q->slot[idx]; + + CAM_DBG(CAM_CRM, "idx: %d: slot->status %d", idx, slot->status); + + /* Check if there is new req from CSL, if not complete req */ + if (slot->status == CRM_SLOT_STATUS_NO_REQ) { + rc = __cam_req_mgr_check_for_lower_pd_devices(link); + if (rc) { + CAM_DBG(CAM_CRM, "No lower pd devices on link 0x%x", + link->link_hdl); + return rc; + } + __cam_req_mgr_in_q_skip_idx(in_q, idx); + if (in_q->wr_idx != idx) + CAM_WARN(CAM_CRM, + "CHECK here wr %d, rd %d", in_q->wr_idx, idx); + __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); + } + + return rc; +} + +/** + * __cam_req_mgr_send_req() + * + * @brief : send request id to be applied to each device connected on link + * @link : pointer to link whose input queue and req tbl are + * traversed through + * @in_q : pointer to input request queue + * + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_req_queue *in_q, uint32_t trigger, + struct cam_req_mgr_connected_device **failed_dev) +{ + int rc = 0, pd, i, idx; + struct cam_req_mgr_connected_device *dev = NULL; + struct cam_req_mgr_apply_request apply_req; + struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_tbl_slot *slot = NULL; + + apply_req.link_hdl = link->link_hdl; + apply_req.report_if_bubble = 0; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (!dev) + continue; + pd = dev->dev_info.p_delay; + if (pd >= CAM_PIPELINE_DELAY_MAX) { + CAM_WARN(CAM_CRM, "pd %d greater than max", + pd); + continue; + } + + idx = link->req.apply_data[pd].idx; + slot = &dev->pd_tbl->slot[idx]; + /* + * Just let flash go for this request and other + * device get restricted + */ + + if ((slot->skip_next_frame != true) || + (slot->dev_hdl != dev->dev_hdl)) + continue; + + if (!(dev->dev_info.trigger & trigger)) + continue; + + apply_req.dev_hdl = dev->dev_hdl; + apply_req.request_id = + link->req.apply_data[pd].req_id; + apply_req.trigger_point = trigger; + if (dev->ops && dev->ops->apply_req) { + rc = dev->ops->apply_req(&apply_req); + if (rc) + return rc; + CAM_DBG(CAM_REQ, + "SEND: link_hdl: %x pd: %d req_id %lld", + link->link_hdl, pd, apply_req.request_id); + slot->skip_next_frame = false; + slot->is_applied = true; + return -EAGAIN; + } + } + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev) { + pd = dev->dev_info.p_delay; + if (pd >= CAM_PIPELINE_DELAY_MAX) { + CAM_WARN(CAM_CRM, "pd %d greater than max", + pd); + continue; + } + if (link->req.apply_data[pd].skip_idx || + link->req.apply_data[pd].req_id < 0) { + CAM_DBG(CAM_CRM, "skip %d req_id %lld", + link->req.apply_data[pd].skip_idx, + link->req.apply_data[pd].req_id); + continue; + } + if (!(dev->dev_info.trigger & trigger)) + continue; + + apply_req.dev_hdl = dev->dev_hdl; + apply_req.request_id = + link->req.apply_data[pd].req_id; + idx = link->req.apply_data[pd].idx; + slot = &dev->pd_tbl->slot[idx]; + apply_req.report_if_bubble = + in_q->slot[idx].recover; + + if ((slot->dev_hdl == dev->dev_hdl) && + (slot->is_applied == true)) { + slot->is_applied = false; + continue; + } + + apply_req.trigger_point = trigger; + CAM_DBG(CAM_REQ, + "SEND: link_hdl: %x pd %d req_id %lld", + link->link_hdl, pd, apply_req.request_id); + if (dev->ops && dev->ops->apply_req) { + rc = dev->ops->apply_req(&apply_req); + if (rc < 0) { + *failed_dev = dev; + break; + } + + if (pd == link->max_delay) + link->open_req_cnt--; + } + trace_cam_req_mgr_apply_request(link, &apply_req, dev); + } + } + if (rc < 0) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "APPLY FAILED pd %d req_id %lld", + dev->dev_info.p_delay, apply_req.request_id); + /* Apply req failed notify already applied devs */ + for (; i >= 0; i--) { + dev = &link->l_dev[i]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_ERR; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = apply_req.request_id; + evt_data.u.error = CRM_KMD_ERR_BUBBLE; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } + } + return rc; +} + +/** + * __cam_req_mgr_check_link_is_ready() + * + * @brief : traverse through all request tables and see if all devices are + * ready to apply request settings. + * @link : pointer to link whose input queue and req tbl are + * traversed through + * @idx : index within input request queue + * @validate_only : Whether to validate only and/or update settings + * + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, + int32_t idx, bool validate_only) +{ + int rc; + struct cam_req_mgr_traverse traverse_data; + struct cam_req_mgr_req_queue *in_q; + struct cam_req_mgr_apply *apply_data; + + in_q = link->req.in_q; + + apply_data = link->req.apply_data; + + if (validate_only == false) { + memset(apply_data, 0, + sizeof(struct cam_req_mgr_apply) * CAM_PIPELINE_DELAY_MAX); + } + + traverse_data.apply_data = apply_data; + traverse_data.idx = idx; + traverse_data.tbl = link->req.l_tbl; + traverse_data.in_q = in_q; + traverse_data.result = 0; + traverse_data.validate_only = validate_only; + traverse_data.open_req_cnt = link->open_req_cnt; + + /* + * Traverse through all pd tables, if result is success, + * apply the settings + */ + rc = __cam_req_mgr_traverse(&traverse_data); + CAM_DBG(CAM_CRM, + "SOF: idx %d result %x pd_mask %x rc %d", + idx, traverse_data.result, link->pd_mask, rc); + + if (!rc && traverse_data.result == link->pd_mask) { + CAM_DBG(CAM_CRM, + "READY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld", + link->link_hdl, idx, + apply_data[2].req_id, + apply_data[1].req_id, + apply_data[0].req_id); + } else + rc = -EAGAIN; + + return rc; +} + +/** + * __cam_req_mgr_find_slot_for_req() + * + * @brief : Find idx from input queue at which req id is enqueued + * @in_q : input request queue pointer + * @req_id : request id which needs to be searched in input queue + * + * @return : slot index where passed request id is stored, -1 for failure + * + */ +static int32_t __cam_req_mgr_find_slot_for_req( + struct cam_req_mgr_req_queue *in_q, int64_t req_id) +{ + int32_t idx, i; + struct cam_req_mgr_slot *slot; + + idx = in_q->rd_idx; + for (i = 0; i < in_q->num_slots; i++) { + slot = &in_q->slot[idx]; + if (slot->req_id == req_id) { + CAM_DBG(CAM_CRM, + "req: %lld found at idx: %d status: %d sync_mode: %d", + req_id, idx, slot->status, slot->sync_mode); + break; + } + __cam_req_mgr_dec_idx(&idx, 1, in_q->num_slots); + } + if (i >= in_q->num_slots) + idx = -1; + + return idx; +} + +/** + * __cam_req_mgr_check_sync_for_mslave() + * + * @brief : Processes requests during sync mode [master-slave] + * Here master corresponds to the link having a higher + * max_delay (pd) compared to the slave link. + * @link : Pointer to link whose input queue and req tbl are + * traversed through + * @slot : Pointer to the current slot being processed + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_check_sync_for_mslave( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_slot *slot) +{ + struct cam_req_mgr_core_link *sync_link = NULL; + struct cam_req_mgr_slot *sync_slot = NULL; + int sync_slot_idx = 0, prev_idx, next_idx, rd_idx, sync_rd_idx, rc = 0; + int64_t req_id = 0, sync_req_id = 0; + int32_t sync_num_slots = 0; + + if (!link->sync_link) { + CAM_ERR(CAM_CRM, "Sync link null"); + return -EINVAL; + } + + sync_link = link->sync_link; + req_id = slot->req_id; + sync_num_slots = sync_link->req.in_q->num_slots; + sync_rd_idx = sync_link->req.in_q->rd_idx; + + CAM_DBG(CAM_CRM, + "link_hdl %x req %lld frame_skip_flag %d open_req_cnt:%d initial_sync_req [%lld,%lld] is_master:%d", + link->link_hdl, req_id, link->sync_link_sof_skip, + link->open_req_cnt, link->initial_sync_req, + sync_link->initial_sync_req, link->is_master); + + if (sync_link->sync_link_sof_skip) { + CAM_DBG(CAM_CRM, + "No req applied on corresponding SOF on sync link: %x", + sync_link->link_hdl); + sync_link->sync_link_sof_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; + } + + if (link->in_msync_mode && + sync_link->in_msync_mode && + (req_id - sync_link->req.in_q->slot[sync_rd_idx].req_id > + link->max_delay - sync_link->max_delay)) { + CAM_DBG(CAM_CRM, + "Req: %lld on link:%x need to hold for link: %x req:%d", + req_id, + link->link_hdl, + sync_link->link_hdl, + sync_link->req.in_q->slot[sync_rd_idx].req_id); + return -EINVAL; + } + + if (link->is_master) { + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } + + if (sync_link->initial_skip) { + CAM_DBG(CAM_CRM, "Link 0x%x [slave] not streamed on", + sync_link->link_hdl); + return -EAGAIN; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [master] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + + prev_idx = slot->idx; + __cam_req_mgr_dec_idx(&prev_idx, + (link->max_delay - sync_link->max_delay), + link->req.in_q->num_slots); + + rd_idx = sync_link->req.in_q->rd_idx; + sync_req_id = link->req.in_q->slot[prev_idx].req_id; + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not found on link: %x [slave]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + (((sync_slot_idx - rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not next on link: %x [slave]", + sync_req_id, + sync_link->link_hdl); + return -EINVAL; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && + (sync_link->req.in_q->slot[sync_slot_idx].status + != CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [slave] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } + } else { + if (link->initial_skip) + link->initial_skip = false; + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [slave] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + + next_idx = link->req.in_q->rd_idx; + rd_idx = sync_link->req.in_q->rd_idx; + __cam_req_mgr_inc_idx(&next_idx, + (sync_link->max_delay - link->max_delay), + link->req.in_q->num_slots); + + sync_req_id = link->req.in_q->slot[next_idx].req_id; + + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not found on link: %x [master]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + (((sync_slot_idx - rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not next on link: %x [master]", + sync_req_id, sync_link->link_hdl); + return -EINVAL; + } + + sync_slot = &sync_link->req.in_q->slot[sync_slot_idx]; + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && (sync_slot->status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not ready on [master] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } + } + + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); + + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; +} + + +/** + * __cam_req_mgr_check_sync_request_is_ready() + * + * @brief : processes requests during sync mode + * @link : pointer to link whose input queue and req tbl are + * traversed through + * @slot : pointer to the current slot being processed + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_check_sync_req_is_ready( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_slot *slot) +{ + struct cam_req_mgr_core_link *sync_link = NULL; + int64_t req_id = 0; + int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; + int32_t sync_num_slots = 0; + bool ready = true, sync_ready = true; + + if (!link->sync_link) { + CAM_ERR(CAM_CRM, "Sync link null"); + return -EINVAL; + } + + sync_link = link->sync_link; + req_id = slot->req_id; + sync_num_slots = sync_link->req.in_q->num_slots; + + CAM_DBG(CAM_REQ, + "link_hdl %x req %lld frame_skip_flag %d ", + link->link_hdl, req_id, link->sync_link_sof_skip); + + if (sync_link->sync_link_sof_skip) { + CAM_DBG(CAM_REQ, + "No req applied on corresponding SOF on sync link: %x", + sync_link->link_hdl); + sync_link->sync_link_sof_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; + } + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + ready = false; + } + + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, req_id); + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", + req_id, sync_link->link_hdl); + sync_ready = false; + } + + sync_rd_idx = sync_link->req.in_q->rd_idx; + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + (((sync_slot_idx - sync_rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && + (sync_link->req.in_q->slot[sync_rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld [other link] not next req to be applied on link: %x", + req_id, sync_link->link_hdl); + return -EAGAIN; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [My link] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + ready = false; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, sync_slot_idx, true); + if (rc && (sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [other link] link: %x, rc=%d", + req_id, sync_link->link_hdl, rc); + sync_ready = false; + } + + /* + * If both of them are ready or not ready, then just + * skip this sof and don't skip sync link next SOF. + */ + if (sync_ready != ready) { + CAM_DBG(CAM_CRM, + "Req: %lld ready %d sync_ready %d, ignore sync link next SOF", + req_id, ready, sync_ready); + link->sync_link_sof_skip = true; + return -EINVAL; + } else if (ready == false) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on link: %x", + req_id, link->link_hdl); + return -EINVAL; + } + + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); + + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; +} + +/** + * __cam_req_mgr_process_req() + * + * @brief : processes read index in request queue and traverse through table + * @link : pointer to link whose input queue and req tbl are + * traversed through + * + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, + uint32_t trigger) +{ + int rc = 0, idx; + int reset_step = 0; + struct cam_req_mgr_slot *slot = NULL; + struct cam_req_mgr_req_queue *in_q; + struct cam_req_mgr_core_session *session; + struct cam_req_mgr_connected_device *dev; + + in_q = link->req.in_q; + session = (struct cam_req_mgr_core_session *)link->parent; + mutex_lock(&session->lock); + /* + * Check if new read index, + * - if in pending state, traverse again to complete + * transaction of this read index. + * - if in applied_state, somthign wrong. + * - if in no_req state, no new req + */ + CAM_DBG(CAM_REQ, "SOF Req[%lld] idx %d req_status %d link_hdl %x", + in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx, + in_q->slot[in_q->rd_idx].status, link->link_hdl); + + slot = &in_q->slot[in_q->rd_idx]; + if (slot->status == CRM_SLOT_STATUS_NO_REQ) { + CAM_DBG(CAM_CRM, "No Pending req"); + rc = 0; + goto error; + } + + if ((trigger != CAM_TRIGGER_POINT_SOF) && + (trigger != CAM_TRIGGER_POINT_EOF)) + goto error; + + if ((trigger == CAM_TRIGGER_POINT_EOF) && + (!(link->trigger_mask & CAM_TRIGGER_POINT_SOF))) { + CAM_DBG(CAM_CRM, "Applying for last SOF fails"); + rc = -EINVAL; + goto error; + } + + if (trigger == CAM_TRIGGER_POINT_SOF) { + if (link->trigger_mask) { + CAM_ERR_RATE_LIMIT(CAM_CRM, + "Applying for last EOF fails"); + rc = -EINVAL; + goto error; + } + + if ((slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) && + (link->sync_link)) { + if (link->is_master || link->sync_link->is_master) { + if (!link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = true; + } + + rc = __cam_req_mgr_check_sync_for_mslave( + link, slot); + } else { + rc = __cam_req_mgr_check_sync_req_is_ready( + link, slot); + } + } else { + if (link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave non sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = false; + link->initial_sync_req = -1; + if (link->sync_link) { + link->sync_link->initial_sync_req = -1; + link->sync_link->in_msync_mode = false; + } + } + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, + slot->idx); + if (!rc) + rc = __cam_req_mgr_check_link_is_ready(link, + slot->idx, false); + } + + if (rc < 0) { + /* + * If traverse result is not success, then some devices + * are not ready with packet for the asked request id, + * hence try again in next sof + */ + slot->status = CRM_SLOT_STATUS_REQ_PENDING; + spin_lock_bh(&link->link_state_spin_lock); + if (link->state == CAM_CRM_LINK_STATE_ERR) { + /* + * During error recovery all tables should be + * ready, don't expect to enter here. + * @TODO: gracefully handle if recovery fails. + */ + CAM_ERR_RATE_LIMIT(CAM_CRM, + "FATAL recovery cant finish idx %d status %d", + in_q->rd_idx, + in_q->slot[in_q->rd_idx].status); + rc = -EPERM; + } + spin_unlock_bh(&link->link_state_spin_lock); + goto error; + } + } + + rc = __cam_req_mgr_send_req(link, link->req.in_q, trigger, &dev); + if (rc < 0) { + /* Apply req failed retry at next sof */ + slot->status = CRM_SLOT_STATUS_REQ_PENDING; + + link->retry_cnt++; + if (link->retry_cnt == MAXIMUM_RETRY_ATTEMPTS) { + CAM_DBG(CAM_CRM, + "Max retry attempts reached on link[0x%x] for req [%lld]", + link->link_hdl, + in_q->slot[in_q->rd_idx].req_id); + __cam_req_mgr_notify_error_on_link(link, dev); + link->retry_cnt = 0; + } + } else { + if (link->retry_cnt) + link->retry_cnt = 0; + + link->trigger_mask |= trigger; + + CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success", + slot->req_id, link->link_hdl); + spin_lock_bh(&link->link_state_spin_lock); + if (link->state == CAM_CRM_LINK_STATE_ERR) { + CAM_WARN(CAM_CRM, "Err recovery done idx %d", + in_q->rd_idx); + link->state = CAM_CRM_LINK_STATE_READY; + } + spin_unlock_bh(&link->link_state_spin_lock); + + if (link->sync_link_sof_skip) + link->sync_link_sof_skip = false; + + if (link->trigger_mask == link->subscribe_event) { + slot->status = CRM_SLOT_STATUS_REQ_APPLIED; + link->trigger_mask = 0; + CAM_DBG(CAM_CRM, "req %d is applied on link %x", + slot->req_id, + link->link_hdl); + idx = in_q->rd_idx; + reset_step = link->max_delay; + if (link->sync_link) { + if ((link->in_msync_mode) && + (link->sync_link->is_master)) + reset_step = + link->sync_link->max_delay; + } + __cam_req_mgr_dec_idx( + &idx, reset_step + 1, + in_q->num_slots); + __cam_req_mgr_reset_req_slot(link, idx); + } + } + + mutex_unlock(&session->lock); + return rc; +error: + mutex_unlock(&session->lock); + return rc; +} + +/** + * __cam_req_mgr_add_tbl_to_link() + * + * @brief : Add table to list under link sorted by pd decremeting order + * @l_tbl : list of pipeline delay tables. + * @new_tbl : new tbl which will be appended to above list as per its pd value + * + */ +static void __cam_req_mgr_add_tbl_to_link(struct cam_req_mgr_req_tbl **l_tbl, + struct cam_req_mgr_req_tbl *new_tbl) +{ + struct cam_req_mgr_req_tbl *tbl; + + if (!(*l_tbl) || (*l_tbl)->pd < new_tbl->pd) { + new_tbl->next = *l_tbl; + if (*l_tbl) { + new_tbl->pd_delta = + new_tbl->pd - (*l_tbl)->pd; + } + *l_tbl = new_tbl; + } else { + tbl = *l_tbl; + + /* Reach existing tbl which has less pd value */ + while (tbl->next != NULL && + new_tbl->pd < tbl->next->pd) { + tbl = tbl->next; + } + if (tbl->next != NULL) { + new_tbl->pd_delta = + new_tbl->pd - tbl->next->pd; + } else { + /* This is last table in linked list*/ + new_tbl->pd_delta = 0; + } + new_tbl->next = tbl->next; + tbl->next = new_tbl; + tbl->pd_delta = tbl->pd - new_tbl->pd; + } + CAM_DBG(CAM_CRM, "added pd %d tbl to link delta %d", new_tbl->pd, + new_tbl->pd_delta); +} + +/** + * __cam_req_mgr_create_pd_tbl() + * + * @brief : Creates new request table for new delay value + * @delay : New pd table allocated will have this delay value + * + * @return : pointer to newly allocated table, NULL for failure + * + */ +static struct cam_req_mgr_req_tbl *__cam_req_mgr_create_pd_tbl(int32_t delay) +{ + struct cam_req_mgr_req_tbl *tbl = + kzalloc(sizeof(struct cam_req_mgr_req_tbl), GFP_KERNEL); + if (tbl != NULL) { + tbl->num_slots = MAX_REQ_SLOTS; + CAM_DBG(CAM_CRM, "pd= %d slots= %d", delay, tbl->num_slots); + } + + return tbl; +} + +/** + * __cam_req_mgr_destroy_all_tbl() + * + * @brief : This func will destroy all pipeline delay based req table structs + * @l_tbl : pointer to first table in list and it has max pd . + * + */ +static void __cam_req_mgr_destroy_all_tbl(struct cam_req_mgr_req_tbl **l_tbl) +{ + struct cam_req_mgr_req_tbl *tbl = *l_tbl, *temp; + + CAM_DBG(CAM_CRM, "*l_tbl %pK", tbl); + while (tbl != NULL) { + temp = tbl->next; + kfree(tbl); + tbl = temp; + } + *l_tbl = NULL; +} + +/** + * __cam_req_mgr_setup_in_q() + * + * @brief : Initialize req table data + * @req : request data pointer + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_setup_in_q(struct cam_req_mgr_req_data *req) +{ + int i; + struct cam_req_mgr_req_queue *in_q = req->in_q; + + if (!in_q) { + CAM_ERR(CAM_CRM, "NULL in_q"); + return -EINVAL; + } + + mutex_lock(&req->lock); + in_q->num_slots = MAX_REQ_SLOTS; + + for (i = 0; i < in_q->num_slots; i++) { + in_q->slot[i].idx = i; + in_q->slot[i].req_id = -1; + in_q->slot[i].skip_idx = 0; + in_q->slot[i].status = CRM_SLOT_STATUS_NO_REQ; + } + + in_q->wr_idx = 0; + in_q->rd_idx = 0; + mutex_unlock(&req->lock); + + return 0; +} + +/** + * __cam_req_mgr_reset_req_tbl() + * + * @brief : Initialize req table data + * @req : request queue pointer + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_reset_in_q(struct cam_req_mgr_req_data *req) +{ + struct cam_req_mgr_req_queue *in_q = req->in_q; + + if (!in_q) { + CAM_ERR(CAM_CRM, "NULL in_q"); + return -EINVAL; + } + + mutex_lock(&req->lock); + memset(in_q->slot, 0, + sizeof(struct cam_req_mgr_slot) * in_q->num_slots); + in_q->num_slots = 0; + + in_q->wr_idx = 0; + in_q->rd_idx = 0; + mutex_unlock(&req->lock); + + return 0; +} + +/** + * __cam_req_mgr_notify_sof_freeze() + * + * @brief : Notify devices on link on detecting a SOF freeze + * @link : link on which the sof freeze was detected + * + */ +static void __cam_req_mgr_notify_sof_freeze( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_SOF_FREEZE; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = 0; + evt_data.u.error = CRM_KMD_ERR_FATAL; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } +} + +/** + * __cam_req_mgr_process_sof_freeze() + * + * @brief : Apoptosis - Handles case when connected devices are not responding + * @priv : link information + * @data : task data + * + */ +static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) +{ + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_message msg; + int rc = 0; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + return -EINVAL; + } + + link = (struct cam_req_mgr_core_link *)priv; + session = (struct cam_req_mgr_core_session *)link->parent; + + CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", + session->session_hdl, link->link_hdl); + + __cam_req_mgr_notify_sof_freeze(link); + memset(&msg, 0, sizeof(msg)); + + msg.session_hdl = session->session_hdl; + msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + msg.u.err_msg.request_id = 0; + msg.u.err_msg.link_hdl = link->link_hdl; + + rc = cam_req_mgr_notify_message(&msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT); + + if (rc) + CAM_ERR(CAM_CRM, + "Error notifying SOF freeze for session %d link 0x%x rc %d", + session->session_hdl, link->link_hdl, rc); + + return rc; +} + +/** + * __cam_req_mgr_sof_freeze() + * + * @brief : Callback function for timer timeout indicating SOF freeze + * @data : timer pointer + * + */ +static void __cam_req_mgr_sof_freeze(struct timer_list *timer_data) +{ + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct crm_task_payload *task_data; + + if (!timer) { + CAM_ERR(CAM_CRM, "NULL timer"); + return; + } + + link = (struct cam_req_mgr_core_link *)timer->parent; + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "No empty task"); + return; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_FREEZE; + task->process_cb = &__cam_req_mgr_process_sof_freeze; + cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); +} + +/** + * __cam_req_mgr_create_subdevs() + * + * @brief : Create new crm subdev to link with realtime devices + * @l_dev : list of subdevs internal to crm + * @num_dev : num of subdevs to be created for link + * + * @return : pointer to allocated list of devices + */ +static int __cam_req_mgr_create_subdevs( + struct cam_req_mgr_connected_device **l_dev, int32_t num_dev) +{ + int rc = 0; + *l_dev = kzalloc(sizeof(struct cam_req_mgr_connected_device) * + num_dev, GFP_KERNEL); + if (!*l_dev) + rc = -ENOMEM; + + return rc; +} + +/** + * __cam_req_mgr_destroy_subdev() + * + * @brief : Cleans up the subdevs allocated by crm for link + * @l_device : pointer to list of subdevs crm created + * + */ +static void __cam_req_mgr_destroy_subdev( + struct cam_req_mgr_connected_device *l_device) +{ + kfree(l_device); + l_device = NULL; +} + +/** + * __cam_req_mgr_destroy_link_info() + * + * @brief : Unlinks all devices on the link + * @link : pointer to link + * + * @return : returns if unlink for any device was success or failure + */ +static int __cam_req_mgr_disconnect_link(struct cam_req_mgr_core_link *link) +{ + int32_t i = 0; + struct cam_req_mgr_connected_device *dev; + struct cam_req_mgr_core_dev_link_setup link_data; + int rc = 0; + + link_data.link_enable = 0; + link_data.link_hdl = link->link_hdl; + link_data.crm_cb = NULL; + link_data.subscribe_event = 0; + + /* Using device ops unlink devices */ + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev == NULL) + continue; + + link_data.dev_hdl = dev->dev_hdl; + if (dev->ops && dev->ops->link_setup) { + rc = dev->ops->link_setup(&link_data); + if (rc) + CAM_ERR(CAM_CRM, + "Unlink failed dev name %s hdl %x", + dev->dev_info.name, + dev->dev_hdl); + } + dev->dev_hdl = 0; + dev->parent = NULL; + dev->ops = NULL; + } + + return rc; +} + +/** + * __cam_req_mgr_destroy_link_info() + * + * @brief : Cleans up the mem allocated while linking + * @link : pointer to link, mem associated with this link is freed + */ +static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link) +{ + __cam_req_mgr_destroy_all_tbl(&link->req.l_tbl); + __cam_req_mgr_reset_in_q(&link->req); + link->req.num_tbl = 0; + mutex_destroy(&link->req.lock); + + link->pd_mask = 0; + link->num_devs = 0; + link->max_delay = 0; +} + +/** + * __cam_req_mgr_reserve_link() + * + * @brief: Reserves one link data struct within session + * @session: session identifier + * + * @return: pointer to link reserved + * + */ +static struct cam_req_mgr_core_link *__cam_req_mgr_reserve_link( + struct cam_req_mgr_core_session *session) +{ + struct cam_req_mgr_core_link *link; + struct cam_req_mgr_req_queue *in_q; + int i; + + if (!session || !g_crm_core_dev) { + CAM_ERR(CAM_CRM, "NULL session/core_dev ptr"); + return NULL; + } + + if (session->num_links >= MAXIMUM_LINKS_PER_SESSION) { + CAM_ERR(CAM_CRM, "Reached max links %d per session limit %d", + session->num_links, MAXIMUM_LINKS_PER_SESSION); + return NULL; + } + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (!atomic_cmpxchg(&g_links[i].is_used, 0, 1)) { + link = &g_links[i]; + CAM_DBG(CAM_CRM, "alloc link index %d", i); + cam_req_mgr_core_link_reset(link); + break; + } + } + if (i == MAXIMUM_LINKS_PER_SESSION) + return NULL; + + in_q = kzalloc(sizeof(struct cam_req_mgr_req_queue), + GFP_KERNEL); + if (!in_q) { + CAM_ERR(CAM_CRM, "failed to create input queue, no mem"); + return NULL; + } + + mutex_lock(&link->lock); + link->num_devs = 0; + link->max_delay = 0; + memset(in_q->slot, 0, + sizeof(struct cam_req_mgr_slot) * MAX_REQ_SLOTS); + link->req.in_q = in_q; + in_q->num_slots = 0; + link->state = CAM_CRM_LINK_STATE_IDLE; + link->parent = (void *)session; + link->sync_link = NULL; + mutex_unlock(&link->lock); + + mutex_lock(&session->lock); + /* Loop through and find a free index */ + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (!session->links[i]) { + CAM_DBG(CAM_CRM, + "Free link index %d found, num_links=%d", + i, session->num_links); + session->links[i] = link; + break; + } + } + + if (i == MAXIMUM_LINKS_PER_SESSION) { + CAM_ERR(CAM_CRM, "Free link index not found"); + goto error; + } + + session->num_links++; + CAM_DBG(CAM_CRM, "Active session links (%d)", + session->num_links); + mutex_unlock(&session->lock); + + return link; +error: + mutex_unlock(&session->lock); + kfree(in_q); + return NULL; +} + +/* + * __cam_req_mgr_free_link() + * + * @brief: Frees the link and its request queue + * + * @link: link identifier + * + */ +static void __cam_req_mgr_free_link(struct cam_req_mgr_core_link *link) +{ + ptrdiff_t i; + kfree(link->req.in_q); + link->req.in_q = NULL; + i = link - g_links; + CAM_DBG(CAM_CRM, "free link index %d", i); + cam_req_mgr_core_link_reset(link); + atomic_set(&g_links[i].is_used, 0); +} + +/** + * __cam_req_mgr_unreserve_link() + * + * @brief : Removes the link data struct from the session and frees it + * @session: session identifier + * @link : link identifier + * + */ +static void __cam_req_mgr_unreserve_link( + struct cam_req_mgr_core_session *session, + struct cam_req_mgr_core_link *link) +{ + int i; + + if (!session || !link) { + CAM_ERR(CAM_CRM, "NULL session/link ptr %pK %pK", + session, link); + return; + } + + mutex_lock(&session->lock); + if (!session->num_links) { + CAM_WARN(CAM_CRM, "No active link or invalid state: hdl %x", + link->link_hdl); + mutex_unlock(&session->lock); + return; + } + + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (session->links[i] == link) + session->links[i] = NULL; + + if (link->sync_link) { + if (link->sync_link == session->links[i]) + session->links[i]->sync_link = NULL; + } + } + + link->sync_link = NULL; + session->num_links--; + CAM_DBG(CAM_CRM, "Active session links (%d)", session->num_links); + mutex_unlock(&session->lock); + __cam_req_mgr_free_link(link); +} + +/* Workqueue context processing section */ + +/** + * cam_req_mgr_process_send_req() + * + * @brief: This runs in workque thread context. Call core funcs to send + * apply request id to drivers. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_send_req(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_send_request *send_req = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_connected_device *dev; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + send_req = (struct cam_req_mgr_send_request *)data; + in_q = send_req->in_q; + + rc = __cam_req_mgr_send_req(link, in_q, CAM_TRIGGER_POINT_SOF, &dev); +end: + return rc; +} + +/** + * cam_req_mgr_process_flush_req() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which requests need to be removed/cancelled. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_flush_req(void *priv, void *data) +{ + int rc = 0, i = 0, idx = -1; + struct cam_req_mgr_flush_info *flush_info = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; + struct cam_req_mgr_connected_device *device = NULL; + struct cam_req_mgr_flush_request flush_req; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + flush_info = (struct cam_req_mgr_flush_info *)&task_data->u; + CAM_DBG(CAM_REQ, "link_hdl %x req_id %lld type %d", + flush_info->link_hdl, + flush_info->req_id, + flush_info->flush_type); + + in_q = link->req.in_q; + + trace_cam_flush_req(link, flush_info); + + mutex_lock(&link->req.lock); + if (flush_info->flush_type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + link->last_flush_id = flush_info->req_id; + CAM_INFO(CAM_CRM, "Last request id to flush is %lld", + flush_info->req_id); + for (i = 0; i < in_q->num_slots; i++) { + slot = &in_q->slot[i]; + slot->req_id = -1; + slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->skip_idx = 1; + slot->status = CRM_SLOT_STATUS_NO_REQ; + } + in_q->wr_idx = 0; + in_q->rd_idx = 0; + } else if (flush_info->flush_type == + CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + idx = __cam_req_mgr_find_slot_for_req(in_q, flush_info->req_id); + if (idx < 0) { + CAM_ERR(CAM_CRM, "req_id %lld not found in input queue", + flush_info->req_id); + } else { + CAM_DBG(CAM_CRM, "req_id %lld found at idx %d", + flush_info->req_id, idx); + slot = &in_q->slot[idx]; + if (slot->status == CRM_SLOT_STATUS_REQ_PENDING || + slot->status == CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_WARN(CAM_CRM, + "req_id %lld can not be cancelled", + flush_info->req_id); + mutex_unlock(&link->req.lock); + return -EINVAL; + } + __cam_req_mgr_in_q_skip_idx(in_q, idx); + } + } + + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + flush_req.link_hdl = flush_info->link_hdl; + flush_req.dev_hdl = device->dev_hdl; + flush_req.req_id = flush_info->req_id; + flush_req.type = flush_info->flush_type; + /* @TODO: error return handling from drivers */ + if (device->ops && device->ops->flush_req) + rc = device->ops->flush_req(&flush_req); + } + complete(&link->workq_comp); + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_sched_req() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which peding requests can be processed. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_sched_req(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_sched_request *sched_req = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + sched_req = (struct cam_req_mgr_sched_request *)&task_data->u; + in_q = link->req.in_q; + + CAM_DBG(CAM_CRM, + "link_hdl %x req_id %lld at slot %d sync_mode %d is_master:%d", + sched_req->link_hdl, sched_req->req_id, + in_q->wr_idx, sched_req->sync_mode, + link->is_master); + + mutex_lock(&link->req.lock); + slot = &in_q->slot[in_q->wr_idx]; + + if (slot->status != CRM_SLOT_STATUS_NO_REQ && + slot->status != CRM_SLOT_STATUS_REQ_APPLIED) + CAM_WARN(CAM_CRM, "in_q overwrite %d", slot->status); + + slot->status = CRM_SLOT_STATUS_REQ_ADDED; + slot->req_id = sched_req->req_id; + slot->sync_mode = sched_req->sync_mode; + slot->skip_idx = 0; + slot->recover = sched_req->bubble_enable; + link->open_req_cnt++; + __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); + + if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + if (link->initial_sync_req == -1) + link->initial_sync_req = slot->req_id; + } else { + link->initial_sync_req = -1; + if (link->sync_link) + link->sync_link->initial_sync_req = -1; + } + + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_add_req() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which peding requests can be processed. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_add_req(void *priv, void *data) +{ + int rc = 0, i = 0, idx; + struct cam_req_mgr_add_request *add_req = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_connected_device *device = NULL; + struct cam_req_mgr_req_tbl *tbl = NULL; + struct cam_req_mgr_tbl_slot *slot = NULL; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + add_req = (struct cam_req_mgr_add_request *)&task_data->u; + + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + if (device->dev_hdl == add_req->dev_hdl) { + tbl = device->pd_tbl; + break; + } + } + if (!tbl) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "dev_hdl not found %x, %x %x", + add_req->dev_hdl, + link->l_dev[0].dev_hdl, + link->l_dev[1].dev_hdl); + rc = -EINVAL; + goto end; + } + /* + * Go through request table and add + * request id to proper table + * 1. find req slot in in_q matching req_id.sent by dev + * 2. goto table of this device based on p_delay + * 3. mark req_ready_map with this dev_bit. + */ + + mutex_lock(&link->req.lock); + idx = __cam_req_mgr_find_slot_for_req(link->req.in_q, add_req->req_id); + if (idx < 0) { + CAM_ERR(CAM_CRM, + "req %lld not found in in_q for dev %s on link 0x%x", + add_req->req_id, device->dev_info.name, link->link_hdl); + rc = -EBADSLT; + mutex_unlock(&link->req.lock); + goto end; + } + + slot = &tbl->slot[idx]; + slot->is_applied = false; + if ((add_req->skip_before_applying & 0xFF) > slot->inject_delay) { + slot->inject_delay = (add_req->skip_before_applying & 0xFF); + slot->dev_hdl = add_req->dev_hdl; + if (add_req->skip_before_applying & SKIP_NEXT_FRAME) + slot->skip_next_frame = true; + CAM_DBG(CAM_CRM, "Req_id %llu injecting delay %llu", + add_req->req_id, + (add_req->skip_before_applying & 0xFF)); + } + + if (slot->state != CRM_REQ_STATE_PENDING && + slot->state != CRM_REQ_STATE_EMPTY) { + CAM_WARN(CAM_CRM, + "Unexpected state %d for slot %d map %x for dev %s on link 0x%x", + slot->state, idx, slot->req_ready_map, + device->dev_info.name, link->link_hdl); + } + + slot->state = CRM_REQ_STATE_PENDING; + slot->req_ready_map |= (1 << device->dev_bit); + + CAM_DBG(CAM_CRM, "idx %d dev_hdl %x req_id %lld pd %d ready_map %x", + idx, add_req->dev_hdl, add_req->req_id, tbl->pd, + slot->req_ready_map); + + trace_cam_req_mgr_add_req(link, idx, add_req, tbl, device); + + if (slot->req_ready_map == tbl->dev_mask) { + CAM_DBG(CAM_REQ, + "link 0x%x idx %d req_id %lld pd %d SLOT READY", + link->link_hdl, idx, add_req->req_id, tbl->pd); + slot->state = CRM_REQ_STATE_READY; + } + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_error() + * + * @brief: This runs in workque thread context. bubble /err recovery. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_error(void *priv, void *data) +{ + int rc = 0, idx = -1, i; + struct cam_req_mgr_error_notify *err_info = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; + struct cam_req_mgr_connected_device *device = NULL; + struct cam_req_mgr_link_evt_data evt_data; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + err_info = (struct cam_req_mgr_error_notify *)&task_data->u; + CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld error %d", + err_info->link_hdl, + err_info->req_id, + err_info->error); + + in_q = link->req.in_q; + + mutex_lock(&link->req.lock); + if (err_info->error == CRM_KMD_ERR_BUBBLE) { + idx = __cam_req_mgr_find_slot_for_req(in_q, err_info->req_id); + if (idx < 0) { + CAM_ERR_RATE_LIMIT(CAM_CRM, + "req_id %lld not found in input queue", + err_info->req_id); + } else { + CAM_DBG(CAM_CRM, "req_id %lld found at idx %d", + err_info->req_id, idx); + slot = &in_q->slot[idx]; + if (!slot->recover) { + CAM_WARN(CAM_CRM, + "err recovery disabled req_id %lld", + err_info->req_id); + mutex_unlock(&link->req.lock); + return 0; + } else if (slot->status != CRM_SLOT_STATUS_REQ_PENDING + && slot->status != CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_WARN(CAM_CRM, + "req_id %lld can not be recovered %d", + err_info->req_id, slot->status); + mutex_unlock(&link->req.lock); + return -EINVAL; + } + /* Notify all devices in the link about error */ + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + if (device != NULL) { + evt_data.dev_hdl = device->dev_hdl; + evt_data.evt_type = + CAM_REQ_MGR_LINK_EVT_ERR; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = err_info->req_id; + evt_data.u.error = err_info->error; + if (device->ops && + device->ops->process_evt) + rc = device->ops->process_evt( + &evt_data); + } + } + /* Bring processing pointer to bubbled req id */ + __cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl); + in_q->rd_idx = idx; + in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED; + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_ERR; + spin_unlock_bh(&link->link_state_spin_lock); + } + } + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_trigger() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which peding requests can be processed. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +static int cam_req_mgr_process_trigger(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_trigger_notify *trigger_data = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + trigger_data = (struct cam_req_mgr_trigger_notify *)&task_data->u; + + CAM_DBG(CAM_REQ, "link_hdl %x frame_id %lld, trigger %x\n", + trigger_data->link_hdl, + trigger_data->frame_id, + trigger_data->trigger); + + in_q = link->req.in_q; + + mutex_lock(&link->req.lock); + /* + * Check if current read index is in applied state, if yes make it free + * and increment read index to next slot. + */ + CAM_DBG(CAM_CRM, "link_hdl %x curent idx %d req_status %d", + link->link_hdl, in_q->rd_idx, in_q->slot[in_q->rd_idx].status); + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state == CAM_CRM_LINK_STATE_ERR) + CAM_WARN(CAM_CRM, "Error recovery idx %d status %d", + in_q->rd_idx, + in_q->slot[in_q->rd_idx].status); + + spin_unlock_bh(&link->link_state_spin_lock); + + if (in_q->slot[in_q->rd_idx].status == CRM_SLOT_STATUS_REQ_APPLIED) { + /* + * Do NOT reset req q slot data here, it can not be done + * here because we need to preserve the data to handle bubble. + * + * Check if any new req is pending in slot, if not finish the + * lower pipeline delay device with available req ids. + */ + CAM_DBG(CAM_CRM, "link[%x] Req[%lld] invalidating slot", + link->link_hdl, in_q->slot[in_q->rd_idx].req_id); + rc = __cam_req_mgr_check_next_req_slot(link); + if (rc) { + CAM_DBG(CAM_REQ, + "No pending req to apply to lower pd devices"); + rc = 0; + goto release_lock; + } + __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); + } + + rc = __cam_req_mgr_process_req(link, trigger_data->trigger); + +release_lock: + mutex_unlock(&link->req.lock); +end: + return rc; +} + +/** + * __cam_req_mgr_dev_handle_to_name() + * + * @brief : Finds device name based on the device handle + * @dev_hdl : Device handle whose name is to be found + * @link : Link on which the device is connected + * @return : String containing the device name + * + */ +static const char *__cam_req_mgr_dev_handle_to_name( + int32_t dev_hdl, struct cam_req_mgr_core_link *link) +{ + struct cam_req_mgr_connected_device *dev = NULL; + int i = 0; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + + if (dev_hdl == dev->dev_hdl) + return dev->dev_info.name; + } + + return "Invalid dev_hdl"; +} + +/* Linked devices' Callback section */ + +/** + * cam_req_mgr_cb_add_req() + * + * @brief : Drivers call this function to notify new packet is available. + * @add_req : Information about new request available at a device. + * + * @return : 0 on success, negative in case of failure + * + */ +static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req) +{ + int rc = 0, idx; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_add_request *dev_req; + struct crm_task_payload *task_data; + + if (!add_req) { + CAM_ERR(CAM_CRM, "sof_data is NULL"); + return -EINVAL; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(add_req->link_hdl); + + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", add_req->link_hdl); + return -EINVAL; + } + + CAM_DBG(CAM_REQ, "dev name %s dev_hdl %d dev req %lld", + __cam_req_mgr_dev_handle_to_name(add_req->dev_hdl, link), + add_req->dev_hdl, add_req->req_id); + + mutex_lock(&link->lock); + spin_lock_bh(&link->link_state_spin_lock); + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + rc = -EPERM; + spin_unlock_bh(&link->link_state_spin_lock); + goto end; + } + spin_unlock_bh(&link->link_state_spin_lock); + + /* Validate if req id is present in input queue */ + idx = __cam_req_mgr_find_slot_for_req(link->req.in_q, add_req->req_id); + if (idx < 0) { + CAM_ERR(CAM_CRM, "req %lld not found in in_q", add_req->req_id); + rc = -ENOENT; + goto end; + } + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "no empty task dev %x req %lld", + add_req->dev_hdl, add_req->req_id); + rc = -EBUSY; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_DEV_ADD_REQ; + dev_req = (struct cam_req_mgr_add_request *)&task_data->u; + dev_req->req_id = add_req->req_id; + dev_req->link_hdl = add_req->link_hdl; + dev_req->dev_hdl = add_req->dev_hdl; + dev_req->skip_before_applying = add_req->skip_before_applying; + task->process_cb = &cam_req_mgr_process_add_req; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + CAM_DBG(CAM_CRM, "X: dev %x dev req %lld", + add_req->dev_hdl, add_req->req_id); + +end: + mutex_unlock(&link->lock); + return rc; +} + +/** + * cam_req_mgr_cb_notify_err() + * + * @brief : Error received from device, sends bubble recovery + * @err_info : contains information about error occurred like bubble/overflow + * + * @return : 0 on success, negative in case of failure + * + */ +static int cam_req_mgr_cb_notify_err( + struct cam_req_mgr_error_notify *err_info) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_error_notify *notify_err; + struct crm_task_payload *task_data; + + if (!err_info) { + CAM_ERR(CAM_CRM, "err_info is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(err_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", err_info->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state != CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + crm_timer_reset(link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "no empty task req_id %lld", err_info->req_id); + rc = -EBUSY; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_ERR; + notify_err = (struct cam_req_mgr_error_notify *)&task_data->u; + notify_err->req_id = err_info->req_id; + notify_err->link_hdl = err_info->link_hdl; + notify_err->dev_hdl = err_info->dev_hdl; + notify_err->error = err_info->error; + task->process_cb = &cam_req_mgr_process_error; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + +end: + return rc; +} + +/** + * cam_req_mgr_cb_notify_trigger() + * + * @brief : SOF received from device, sends trigger through workqueue + * @sof_data: contains information about frame_id, link etc. + * + * @return : 0 on success + * + */ +static int cam_req_mgr_cb_notify_trigger( + struct cam_req_mgr_trigger_notify *trigger_data) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_trigger_notify *notify_trigger; + struct crm_task_payload *task_data; + + if (!trigger_data) { + CAM_ERR(CAM_CRM, "sof_data is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(trigger_data->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", trigger_data->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + crm_timer_reset(link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "no empty task frame %lld", + trigger_data->frame_id); + rc = -EBUSY; + goto end; + } + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_SOF; + notify_trigger = (struct cam_req_mgr_trigger_notify *)&task_data->u; + notify_trigger->frame_id = trigger_data->frame_id; + notify_trigger->link_hdl = trigger_data->link_hdl; + notify_trigger->dev_hdl = trigger_data->dev_hdl; + notify_trigger->trigger = trigger_data->trigger; + task->process_cb = &cam_req_mgr_process_trigger; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + +end: + return rc; +} + +static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { + .notify_trigger = cam_req_mgr_cb_notify_trigger, + .notify_err = cam_req_mgr_cb_notify_err, + .add_req = cam_req_mgr_cb_add_req, +}; + +/** + * __cam_req_mgr_setup_link_info() + * + * @brief : Sets up input queue, create pd based tables, communicate with + * devs connected on this link and setup communication. + * @link : pointer to link to setup + * @link_info : link_info coming from CSL to prepare link + * + * @return : 0 on success, negative in case of failure + * + */ +static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_link_info *link_info) +{ + int rc = 0, i = 0; + struct cam_req_mgr_core_dev_link_setup link_data; + struct cam_req_mgr_connected_device *dev; + struct cam_req_mgr_req_tbl *pd_tbl; + enum cam_pipeline_delay max_delay; + uint32_t subscribe_event = 0; + + if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) + return -EPERM; + + mutex_init(&link->req.lock); + CAM_DBG(CAM_CRM, "LOCK_DBG in_q lock %pK", &link->req.lock); + link->req.num_tbl = 0; + + rc = __cam_req_mgr_setup_in_q(&link->req); + if (rc < 0) + return rc; + + max_delay = CAM_PIPELINE_DELAY_0; + for (i = 0; i < link_info->num_devices; i++) { + dev = &link->l_dev[i]; + /* Using dev hdl, get ops ptr to communicate with device */ + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops(link_info->dev_hdls[i]); + if (!dev->ops || + !dev->ops->get_dev_info || + !dev->ops->link_setup) { + CAM_ERR(CAM_CRM, "FATAL: device ops NULL"); + rc = -ENXIO; + goto error; + } + dev->dev_hdl = link_info->dev_hdls[i]; + dev->parent = (void *)link; + dev->dev_info.dev_hdl = dev->dev_hdl; + rc = dev->ops->get_dev_info(&dev->dev_info); + + trace_cam_req_mgr_connect_device(link, &dev->dev_info); + + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->session_hdl, dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); + if (rc < 0 || + dev->dev_info.p_delay >= + CAM_PIPELINE_DELAY_MAX || + dev->dev_info.p_delay < + CAM_PIPELINE_DELAY_0) { + CAM_ERR(CAM_CRM, "get device info failed"); + goto error; + } else { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + if (dev->dev_info.p_delay > max_delay) + max_delay = dev->dev_info.p_delay; + + subscribe_event |= (uint32_t)dev->dev_info.trigger; + } + } + + link->subscribe_event = subscribe_event; + link_data.link_enable = 1; + link_data.link_hdl = link->link_hdl; + link_data.crm_cb = &cam_req_mgr_ops; + link_data.max_delay = max_delay; + link_data.subscribe_event = subscribe_event; + + for (i = 0; i < link_info->num_devices; i++) { + dev = &link->l_dev[i]; + + link_data.dev_hdl = dev->dev_hdl; + /* + * For unique pipeline delay table create request + * tracking table + */ + if (link->pd_mask & (1 << dev->dev_info.p_delay)) { + pd_tbl = __cam_req_mgr_find_pd_tbl(link->req.l_tbl, + dev->dev_info.p_delay); + if (!pd_tbl) { + CAM_ERR(CAM_CRM, "pd %d tbl not found", + dev->dev_info.p_delay); + rc = -ENXIO; + goto error; + } + } else { + pd_tbl = __cam_req_mgr_create_pd_tbl( + dev->dev_info.p_delay); + if (pd_tbl == NULL) { + CAM_ERR(CAM_CRM, "create new pd tbl failed"); + rc = -ENXIO; + goto error; + } + pd_tbl->pd = dev->dev_info.p_delay; + link->pd_mask |= (1 << pd_tbl->pd); + /* + * Add table to list and also sort list + * from max pd to lowest + */ + __cam_req_mgr_add_tbl_to_link(&link->req.l_tbl, pd_tbl); + } + dev->dev_bit = pd_tbl->dev_count++; + dev->pd_tbl = pd_tbl; + pd_tbl->dev_mask |= (1 << dev->dev_bit); + + /* Communicate with dev to establish the link */ + dev->ops->link_setup(&link_data); + + if (link->max_delay < dev->dev_info.p_delay) + link->max_delay = dev->dev_info.p_delay; + } + link->num_devs = link_info->num_devices; + + /* Assign id for pd tables */ + __cam_req_mgr_tbl_set_id(link->req.l_tbl, &link->req); + + /* At start, expect max pd devices, all are in skip state */ + __cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl); + + return 0; + +error: + __cam_req_mgr_destroy_link_info(link); + return rc; +} + +/* IOCTLs handling section */ +int cam_req_mgr_create_session( + struct cam_req_mgr_session_info *ses_info) +{ + int rc = 0; + int32_t session_hdl; + struct cam_req_mgr_core_session *cam_session = NULL; + + if (!ses_info) { + CAM_DBG(CAM_CRM, "NULL session info pointer"); + return -EINVAL; + } + mutex_lock(&g_crm_core_dev->crm_lock); + cam_session = kzalloc(sizeof(*cam_session), + GFP_KERNEL); + if (!cam_session) { + rc = -ENOMEM; + goto end; + } + + session_hdl = cam_create_session_hdl((void *)cam_session); + if (session_hdl < 0) { + CAM_ERR(CAM_CRM, "unable to create session_hdl = %x", + session_hdl); + rc = session_hdl; + kfree(cam_session); + goto end; + } + ses_info->session_hdl = session_hdl; + + mutex_init(&cam_session->lock); + CAM_DBG(CAM_CRM, "LOCK_DBG session lock %pK", &cam_session->lock); + + mutex_lock(&cam_session->lock); + cam_session->session_hdl = session_hdl; + cam_session->num_links = 0; + cam_session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + list_add(&cam_session->entry, &g_crm_core_dev->session_head); + mutex_unlock(&cam_session->lock); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +/** + * __cam_req_mgr_unlink() + * + * @brief : Unlink devices on a link structure from the session + * @link : Pointer to the link structure + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) +{ + int rc; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_IDLE; + spin_unlock_bh(&link->link_state_spin_lock); + + rc = __cam_req_mgr_disconnect_link(link); + if (rc) + CAM_ERR(CAM_CORE, + "Unlink for all devices was not successful"); + + mutex_lock(&link->lock); + /* Destroy timer of link */ + crm_timer_exit(&link->watchdog); + + /* Destroy workq of link */ + cam_req_mgr_workq_destroy(&link->workq); + + /* Cleanup request tables and unlink devices */ + __cam_req_mgr_destroy_link_info(link); + + /* Free memory holding data of linked devs */ + __cam_req_mgr_destroy_subdev(link->l_dev); + + /* Destroy the link handle */ + rc = cam_destroy_device_hdl(link->link_hdl); + if (rc < 0) { + CAM_ERR(CAM_CRM, "error destroying link hdl %x rc %d", + link->link_hdl, rc); + } else + link->link_hdl = -1; + + mutex_unlock(&link->lock); + return rc; +} + +int cam_req_mgr_destroy_session( + struct cam_req_mgr_session_info *ses_info) +{ + int rc; + int i; + struct cam_req_mgr_core_session *cam_session = NULL; + struct cam_req_mgr_core_link *link; + + if (!ses_info) { + CAM_DBG(CAM_CRM, "NULL session info pointer"); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(ses_info->session_hdl); + if (!cam_session) { + CAM_ERR(CAM_CRM, "failed to get session priv"); + rc = -ENOENT; + goto end; + + } + if (cam_session->num_links) { + CAM_DBG(CAM_CRM, "destroy session %x num_active_links %d", + ses_info->session_hdl, + cam_session->num_links); + + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + link = cam_session->links[i]; + + if (!link) + continue; + + /* Ignore return value since session is going away */ + __cam_req_mgr_unlink(link); + __cam_req_mgr_free_link(link); + } + } + list_del(&cam_session->entry); + mutex_destroy(&cam_session->lock); + kfree(cam_session); + + rc = cam_destroy_session_hdl(ses_info->session_hdl); + if (rc < 0) + CAM_ERR(CAM_CRM, "unable to destroy session_hdl = %x rc %d", + ses_info->session_hdl, rc); + +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) +{ + int rc = 0; + int wq_flag = 0; + char buf[128]; + struct cam_create_dev_hdl root_dev; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!link_info) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->num_devices); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* Allocate link struct and map it with session's request queue */ + link = __cam_req_mgr_reserve_link(cam_session); + if (!link) { + CAM_ERR(CAM_CRM, "failed to reserve new link"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); + + memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); + root_dev.session_hdl = link_info->session_hdl; + root_dev.priv = (void *)link; + + mutex_lock(&link->lock); + /* Create unique dev handle for link */ + link->link_hdl = cam_create_device_hdl(&root_dev); + if (link->link_hdl < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new device handle"); + rc = link->link_hdl; + goto link_hdl_fail; + } + link_info->link_hdl = link->link_hdl; + link->last_flush_id = 0; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->num_devices); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new crm subdevs"); + goto create_subdev_failed; + } + + /* Using device ops query connected devs, prepare request tables */ + rc = __cam_req_mgr_setup_link_info(link, link_info); + if (rc < 0) + goto setup_failed; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); + + /* Create worker for current link */ + snprintf(buf, sizeof(buf), "%x-%x", + link_info->session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + if (rc < 0) { + CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); + __cam_req_mgr_destroy_link_info(link); + goto setup_failed; + } + + /* Assign payload to workqueue tasks */ + rc = __cam_req_mgr_setup_payload(link->workq); + if (rc < 0) { + __cam_req_mgr_destroy_link_info(link); + cam_req_mgr_workq_destroy(&link->workq); + goto setup_failed; + } + + mutex_unlock(&link->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +setup_failed: + __cam_req_mgr_destroy_subdev(link->l_dev); +create_subdev_failed: + cam_destroy_device_hdl(link->link_hdl); + link_info->link_hdl = -1; +link_hdl_fail: + mutex_unlock(&link->lock); + __cam_req_mgr_unreserve_link(cam_session, link); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) +{ + int rc = 0; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!unlink_info) { + CAM_ERR(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + CAM_DBG(CAM_CRM, "link_hdl %x", unlink_info->link_hdl); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(unlink_info->session_hdl); + if (!cam_session) { + CAM_ERR(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* link hdl's priv data is core_link struct */ + link = cam_get_device_priv(unlink_info->link_hdl); + if (!link) { + CAM_ERR(CAM_CRM, "NULL pointer"); + rc = -EINVAL; + goto done; + } + + rc = __cam_req_mgr_unlink(link); + + /* Free curent link and put back into session's free pool of links */ + __cam_req_mgr_unreserve_link(cam_session, link); + +done: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_schedule_request( + struct cam_req_mgr_sched_request *sched_req) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_sched_request *sched; + struct crm_task_payload task_data; + + if (!sched_req) { + CAM_ERR(CAM_CRM, "csl_req is NULL"); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(sched_req->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", sched_req->link_hdl); + rc = -EINVAL; + goto end; + } + + session = (struct cam_req_mgr_core_session *)link->parent; + if (!session) { + CAM_WARN(CAM_CRM, "session ptr NULL %x", sched_req->link_hdl); + rc = -EINVAL; + goto end; + } + + if (sched_req->req_id <= link->last_flush_id) { + CAM_INFO(CAM_CRM, + "request %lld is flushed, last_flush_id to flush %d", + sched_req->req_id, link->last_flush_id); + rc = -EINVAL; + goto end; + } + + if (sched_req->req_id > link->last_flush_id) + link->last_flush_id = 0; + + CAM_DBG(CAM_CRM, "link 0x%x req %lld, sync_mode %d", + sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); + + task_data.type = CRM_WORKQ_TASK_SCHED_REQ; + sched = (struct cam_req_mgr_sched_request *)&task_data.u; + sched->req_id = sched_req->req_id; + sched->sync_mode = sched_req->sync_mode; + sched->link_hdl = sched_req->link_hdl; + if (session->force_err_recovery == AUTO_RECOVERY) { + sched->bubble_enable = sched_req->bubble_enable; + } else { + sched->bubble_enable = + (session->force_err_recovery == FORCE_ENABLE_RECOVERY) ? 1 : 0; + } + + rc = cam_req_mgr_process_sched_req(link, &task_data); + + CAM_DBG(CAM_REQ, "Open req %lld on link 0x%x with sync_mode %d", + sched_req->req_id, sched_req->link_hdl, sched_req->sync_mode); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +/** + * __cam_req_mgr_set_master_link() + * + * @brief : Each links sets its max pd delay based on the devices on the + * link. The link with higher pd is assigned master. + * @link1 : One of the sync links + * @link2 : The other sync link + */ +static void __cam_req_mgr_set_master_link( + struct cam_req_mgr_core_link *link1, + struct cam_req_mgr_core_link *link2) +{ + + if (link1->max_delay > link2->max_delay) { + link1->is_master = true; + link2->initial_skip = true; + } else if (link2->max_delay > link1->max_delay) { + link2->is_master = true; + link1->initial_skip = true; + } + + CAM_DBG(CAM_CRM, + "link_hdl1[0x%x] is_master [%u] link_hdl2[0x%x] is_master[%u]", + link1->link_hdl, link1->is_master, + link2->link_hdl, link2->is_master); +} + +int cam_req_mgr_sync_config( + struct cam_req_mgr_sync_mode *sync_info) +{ + int rc = 0; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link1 = NULL; + struct cam_req_mgr_core_link *link2 = NULL; + + if (!sync_info) { + CAM_ERR(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + + if ((sync_info->num_links < 0) || + (sync_info->num_links > + MAX_LINKS_PER_SESSION)) { + CAM_ERR(CAM_CRM, "Invalid num links %d", sync_info->num_links); + return -EINVAL; + } + + if ((sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_SYNC) && + (sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC)) { + CAM_ERR(CAM_CRM, "Invalid sync mode %d", sync_info->sync_mode); + return -EINVAL; + } + + if ((!sync_info->link_hdls[0]) || (!sync_info->link_hdls[1])) { + CAM_WARN(CAM_CRM, "Invalid link handles 0x%x 0x%x", + sync_info->link_hdls[0], sync_info->link_hdls[1]); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(sync_info->session_hdl); + if (!cam_session) { + CAM_ERR(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + mutex_lock(&cam_session->lock); + + CAM_DBG(CAM_CRM, "link handles %x %x", + sync_info->link_hdls[0], sync_info->link_hdls[1]); + + /* only two links existing per session in dual cam use case*/ + link1 = cam_get_device_priv(sync_info->link_hdls[0]); + if (!link1) { + CAM_ERR(CAM_CRM, "link1 NULL pointer"); + rc = -EINVAL; + goto done; + } + + link2 = cam_get_device_priv(sync_info->link_hdls[1]); + if (!link2) { + CAM_ERR(CAM_CRM, "link2 NULL pointer"); + rc = -EINVAL; + goto done; + } + + link1->sync_link_sof_skip = false; + link1->sync_link = NULL; + + link2->sync_link_sof_skip = false; + link2->sync_link = NULL; + + link1->is_master = false; + link2->is_master = false; + link1->initial_skip = false; + link2->initial_skip = false; + + link1->in_msync_mode = false; + link2->in_msync_mode = false; + link1->initial_sync_req = -1; + link2->initial_sync_req = -1; + + if (sync_info->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + link1->sync_link = link2; + link2->sync_link = link1; + __cam_req_mgr_set_master_link(link1, link2); + } + + cam_session->sync_mode = sync_info->sync_mode; + CAM_DBG(CAM_REQ, + "Sync config on link1 0x%x & link2 0x%x with sync_mode %d", + link1->link_hdl, link2->link_hdl, cam_session->sync_mode); + +done: + mutex_unlock(&cam_session->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_flush_requests( + struct cam_req_mgr_flush_info *flush_info) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_flush_info *flush; + struct crm_task_payload *task_data; + struct cam_req_mgr_core_session *session = NULL; + + if (!flush_info) { + CAM_ERR(CAM_CRM, "flush req is NULL"); + rc = -EFAULT; + goto end; + } + if (flush_info->flush_type >= CAM_REQ_MGR_FLUSH_TYPE_MAX) { + CAM_ERR(CAM_CRM, "incorrect flush type %x", + flush_info->flush_type); + rc = -EINVAL; + goto end; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ + session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(flush_info->session_hdl); + if (!session) { + CAM_ERR(CAM_CRM, "Invalid session %x", flush_info->session_hdl); + rc = -EINVAL; + goto end; + } + if (session->num_links <= 0) { + CAM_WARN(CAM_CRM, "No active links in session %x", + flush_info->session_hdl); + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(flush_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", flush_info->link_hdl); + rc = -EINVAL; + goto end; + } + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + rc = -ENOMEM; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_FLUSH_REQ; + flush = (struct cam_req_mgr_flush_info *)&task_data->u; + flush->req_id = flush_info->req_id; + flush->link_hdl = flush_info->link_hdl; + flush->flush_type = flush_info->flush_type; + task->process_cb = &cam_req_mgr_process_flush_req; + init_completion(&link->workq_comp); + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + + /* Blocking call */ + rc = wait_for_completion_timeout( + &link->workq_comp, + msecs_to_jiffies(CAM_REQ_MGR_SCHED_REQ_TIMEOUT)); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) +{ + int rc = 0; + int i, j; + struct cam_req_mgr_core_link *link = NULL; + + struct cam_req_mgr_connected_device *dev = NULL; + struct cam_req_mgr_link_evt_data evt_data; + + if (!control) { + CAM_ERR(CAM_CRM, "Control command is NULL"); + rc = -EINVAL; + goto end; + } + + if ((control->num_links <= 0) || + (control->num_links > MAX_LINKS_PER_SESSION)) { + CAM_ERR(CAM_CRM, "Invalid number of links %d", + control->num_links); + rc = -EINVAL; + goto end; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + for (i = 0; i < control->num_links; i++) { + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(control->link_hdls[i]); + if (!link) { + CAM_ERR(CAM_CRM, "Link(%d) is NULL on session 0x%x", + i, control->session_hdl); + rc = -EINVAL; + break; + } + + mutex_lock(&link->lock); + if (control->ops == CAM_REQ_MGR_LINK_ACTIVATE) { + /* Start SOF watchdog timer */ + rc = crm_timer_init(&link->watchdog, + CAM_REQ_MGR_WATCHDOG_TIMEOUT, link, + &__cam_req_mgr_sof_freeze); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "SOF timer start fails: link=0x%x", + link->link_hdl); + rc = -EFAULT; + } + /* notify nodes */ + for (j = 0; j < link->num_devs; j++) { + dev = &link->l_dev[j]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_RESUME; + evt_data.link_hdl = link->link_hdl; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.req_id = 0; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } + } else if (control->ops == CAM_REQ_MGR_LINK_DEACTIVATE) { + /* Destroy SOF watchdog timer */ + spin_lock_bh(&link->link_state_spin_lock); + crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + /* notify nodes */ + for (j = 0; j < link->num_devs; j++) { + dev = &link->l_dev[j]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_PAUSE; + evt_data.link_hdl = link->link_hdl; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.req_id = 0; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } + } else { + CAM_ERR(CAM_CRM, "Invalid link control command"); + rc = -EINVAL; + } + mutex_unlock(&link->lock); + } + mutex_unlock(&g_crm_core_dev->crm_lock); +end: + return rc; +} + + +int cam_req_mgr_core_device_init(void) +{ + int i; + CAM_DBG(CAM_CRM, "Enter g_crm_core_dev %pK", g_crm_core_dev); + + if (g_crm_core_dev) { + CAM_WARN(CAM_CRM, "core device is already initialized"); + return 0; + } + g_crm_core_dev = kzalloc(sizeof(*g_crm_core_dev), + GFP_KERNEL); + if (!g_crm_core_dev) + return -ENOMEM; + + CAM_DBG(CAM_CRM, "g_crm_core_dev %pK", g_crm_core_dev); + INIT_LIST_HEAD(&g_crm_core_dev->session_head); + mutex_init(&g_crm_core_dev->crm_lock); + cam_req_mgr_debug_register(g_crm_core_dev); + + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + mutex_init(&g_links[i].lock); + spin_lock_init(&g_links[i].link_state_spin_lock); + atomic_set(&g_links[i].is_used, 0); + cam_req_mgr_core_link_reset(&g_links[i]); + } + return 0; +} + +int cam_req_mgr_core_device_deinit(void) +{ + if (!g_crm_core_dev) { + CAM_ERR(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + + CAM_DBG(CAM_CRM, "g_crm_core_dev %pK", g_crm_core_dev); + mutex_destroy(&g_crm_core_dev->crm_lock); + kfree(g_crm_core_dev); + g_crm_core_dev = NULL; + + return 0; +} diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h new file mode 100644 index 000000000000..9a6acbc2c43e --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -0,0 +1,470 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_REQ_MGR_CORE_H_ +#define _CAM_REQ_MGR_CORE_H_ + +#include +#include "cam_req_mgr_interface.h" +#include "cam_req_mgr_core_defs.h" +#include "cam_req_mgr_timer.h" + +#define CAM_REQ_MGR_MAX_LINKED_DEV 16 +#define MAX_REQ_SLOTS 48 + +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 5000 +#define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 +#define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 + +#define FORCE_DISABLE_RECOVERY 2 +#define FORCE_ENABLE_RECOVERY 1 +#define AUTO_RECOVERY 0 + +#define CRM_WORKQ_NUM_TASKS 60 + +#define MAX_SYNC_COUNT 65535 + +#define SYNC_LINK_SOF_CNT_MAX_LMT 1 + +#define MAXIMUM_LINKS_PER_SESSION 4 + +#define MAXIMUM_RETRY_ATTEMPTS 3 + +/** + * enum crm_workq_task_type + * @codes: to identify which type of task is present + */ +enum crm_workq_task_type { + CRM_WORKQ_TASK_GET_DEV_INFO, + CRM_WORKQ_TASK_SETUP_LINK, + CRM_WORKQ_TASK_DEV_ADD_REQ, + CRM_WORKQ_TASK_APPLY_REQ, + CRM_WORKQ_TASK_NOTIFY_SOF, + CRM_WORKQ_TASK_NOTIFY_ERR, + CRM_WORKQ_TASK_NOTIFY_FREEZE, + CRM_WORKQ_TASK_SCHED_REQ, + CRM_WORKQ_TASK_FLUSH_REQ, + CRM_WORKQ_TASK_INVALID, +}; + +/** + * struct crm_task_payload + * @type : to identify which type of task is present + * @u : union of payload of all types of tasks supported + * @sched_req : contains info of incoming reqest from CSL to CRM + * @flush_info : contains info of cancelled reqest + * @dev_req : contains tracking info of available req id at device + * @send_req : contains info of apply settings to be sent to devs in link + * @apply_req : contains info of which request is applied at device + * @notify_trigger : contains notification from IFE to CRM about trigger + * @notify_err : contains error info happened while processing request + * - + */ +struct crm_task_payload { + enum crm_workq_task_type type; + union { + struct cam_req_mgr_sched_request sched_req; + struct cam_req_mgr_flush_info flush_info; + struct cam_req_mgr_add_request dev_req; + struct cam_req_mgr_send_request send_req; + struct cam_req_mgr_trigger_notify notify_trigger; + struct cam_req_mgr_error_notify notify_err; + } u; +}; + +/** + * enum crm_req_state + * State machine for life cycle of request in pd table + * EMPTY : indicates req slot is empty + * PENDING : indicates req slot is waiting for reqs from all devs + * READY : indicates req slot is ready to be sent to devs + * INVALID : indicates req slot is not in valid state + */ +enum crm_req_state { + CRM_REQ_STATE_EMPTY, + CRM_REQ_STATE_PENDING, + CRM_REQ_STATE_READY, + CRM_REQ_STATE_INVALID, +}; + +/** + * enum crm_slot_status + * State machine for life cycle of request in input queue + * NO_REQ : empty slot + * REQ_ADDED : new entry in slot + * PENDING : waiting for next trigger to apply + * APPLIED : req is sent to all devices + * INVALID : invalid state + */ +enum crm_slot_status { + CRM_SLOT_STATUS_NO_REQ, + CRM_SLOT_STATUS_REQ_ADDED, + CRM_SLOT_STATUS_REQ_PENDING, + CRM_SLOT_STATUS_REQ_APPLIED, + CRM_SLOT_STATUS_INVALID, +}; + +/** + * enum cam_req_mgr_link_state + * State machine for life cycle of link in crm + * AVAILABLE : link available + * IDLE : link initialized but not ready yet + * READY : link is ready for use + * ERR : link has encountered error + * MAX : invalid state + */ +enum cam_req_mgr_link_state { + CAM_CRM_LINK_STATE_AVAILABLE, + CAM_CRM_LINK_STATE_IDLE, + CAM_CRM_LINK_STATE_READY, + CAM_CRM_LINK_STATE_ERR, + CAM_CRM_LINK_STATE_MAX, +}; + +/** + * struct cam_req_mgr_traverse + * @idx : slot index + * @result : contains which all tables were able to apply successfully + * @tbl : pointer of pipeline delay based request table + * @apply_data : pointer which various tables will update during traverse + * @in_q : input request queue pointer + * @validate_only : Whether to validate only and/or update settings + * @open_req_cnt : Count of open requests yet to be serviced in the kernel. + */ +struct cam_req_mgr_traverse { + int32_t idx; + uint32_t result; + struct cam_req_mgr_req_tbl *tbl; + struct cam_req_mgr_apply *apply_data; + struct cam_req_mgr_req_queue *in_q; + bool validate_only; + int32_t open_req_cnt; +}; + +/** + * struct cam_req_mgr_apply + * @idx : corresponding input queue slot index + * @pd : pipeline delay of device + * @req_id : req id for dev with above pd to process + * @skip_idx: skip applying settings when this is set. + */ +struct cam_req_mgr_apply { + int32_t idx; + int32_t pd; + int64_t req_id; + int32_t skip_idx; +}; + +/** + * struct cam_req_mgr_tbl_slot + * @idx : slot index + * @req_ready_map : mask tracking which all devices have request ready + * @state : state machine for life cycle of a slot + * @inject_delay : insert extra bubbling for flash type of use cases + * @dev_hdl : stores the dev_hdl, who is having higher inject delay + * @skip_next_frame : flag to drop the frame after skip_before_apply frame + * @is_applied : flag to identify if request is already applied to + * device. + */ +struct cam_req_mgr_tbl_slot { + int32_t idx; + uint32_t req_ready_map; + enum crm_req_state state; + uint32_t inject_delay; + int32_t dev_hdl; + bool skip_next_frame; + bool is_applied; +}; + +/** + * struct cam_req_mgr_req_tbl + * @id : table indetifier + * @pd : pipeline delay of table + * @dev_count : num of devices having same pipeline delay + * @dev_mask : mask to track which devices are linked + * @skip_traverse : to indicate how many traverses need to be dropped + * by this table especially in the beginning or bubble recovery + * @next : pointer to next pipeline delay request table + * @pd_delta : differnce between this table's pipeline delay and next + * @num_slots : number of request slots present in the table + * @slot : array of slots tracking requests availability at devices + */ +struct cam_req_mgr_req_tbl { + int32_t id; + int32_t pd; + int32_t dev_count; + int32_t dev_mask; + int32_t skip_traverse; + struct cam_req_mgr_req_tbl *next; + int32_t pd_delta; + int32_t num_slots; + struct cam_req_mgr_tbl_slot slot[MAX_REQ_SLOTS]; +}; + +/** + * struct cam_req_mgr_slot + * - Internal Book keeping + * @idx : slot index + * @skip_idx : if req id in this slot needs to be skipped/not applied + * @status : state machine for life cycle of a slot + * - members updated due to external events + * @recover : if user enabled recovery for this request. + * @req_id : mask tracking which all devices have request ready + * @sync_mode : Sync mode in which req id in this slot has to applied + */ +struct cam_req_mgr_slot { + int32_t idx; + int32_t skip_idx; + enum crm_slot_status status; + int32_t recover; + int64_t req_id; + int32_t sync_mode; +}; + +/** + * struct cam_req_mgr_req_queue + * @num_slots : max num of input queue slots + * @slot : request slot holding incoming request id and bubble info. + * @rd_idx : indicates slot index currently in process. + * @wr_idx : indicates slot index to hold new upcoming req. + */ +struct cam_req_mgr_req_queue { + int32_t num_slots; + struct cam_req_mgr_slot slot[MAX_REQ_SLOTS]; + int32_t rd_idx; + int32_t wr_idx; +}; + +/** + * struct cam_req_mgr_req_data + * @in_q : Poiner to Input request queue + * @l_tbl : unique pd request tables. + * @num_tbl : how many unique pd value devices are present + * @apply_data : Holds information about request id for a request + * @lock : mutex lock protecting request data ops. + */ +struct cam_req_mgr_req_data { + struct cam_req_mgr_req_queue *in_q; + struct cam_req_mgr_req_tbl *l_tbl; + int32_t num_tbl; + struct cam_req_mgr_apply apply_data[CAM_PIPELINE_DELAY_MAX]; + struct mutex lock; +}; + +/** + * struct cam_req_mgr_connected_device + * - Device Properties + * @dev_hdl : device handle + * @dev_bit : unique bit assigned to device in link + * - Device characteristics + * @pd_tbl : tracks latest available req id at this device + * @dev_info : holds dev characteristics such as pipeline delay, dev name + * @ops : holds func pointer to call methods on this device + * @parent : pvt data - like link which this dev hdl belongs to + */ +struct cam_req_mgr_connected_device { + int32_t dev_hdl; + int64_t dev_bit; + struct cam_req_mgr_req_tbl *pd_tbl; + struct cam_req_mgr_device_info dev_info; + struct cam_req_mgr_kmd_ops *ops; + void *parent; +}; + +/** + * struct cam_req_mgr_core_link + * - Link Properties + * @link_hdl : Link identifier + * @num_devs : num of connected devices to this link + * @max_delay : Max of pipeline delay of all connected devs + * @workq : Pointer to handle workq related jobs + * @pd_mask : each set bit indicates the device with pd equal to + * bit position is available. + * - List of connected devices + * @l_dev : List of connected devices to this link + * - Request handling data struct + * @req : req data holder. + * - Timer + * @watchdog : watchdog timer to recover from sof freeze + * - Link private data + * @workq_comp : conditional variable to block user thread for workq + * to finish schedule request processing + * @state : link state machine + * @parent : pvt data - link's parent is session + * @lock : mutex lock to guard link data operations + * @link_state_spin_lock : spin lock to protect link state variable + * @subscribe_event : irqs that link subscribes, IFE should send + * notification to CRM at those hw events. + * @trigger_mask : mask on which irq the req is already applied + * @sync_link : pointer to the sync link for synchronization + * @sync_link_sof_skip : flag determines if a pkt is not available for a given + * frame in a particular link skip corresponding + * frame in sync link as well. + * @open_req_cnt : Counter to keep track of open requests that are yet + * to be serviced in the kernel. + * @last_flush_id : Last request to flush + * @is_used : 1 if link is in use else 0 + * @is_master : Based on pd among links, the link with the highest pd + * is assigned as master + * @initial_skip : Flag to determine if slave has started streaming in + * master-slave sync + * @in_msync_mode : Flag to determine if a link is in master-slave mode + * @initial_sync_req : The initial req which is required to sync with the + * other link + * @retry_cnt : Counter that tracks number of attempts to apply + * the same req + */ +struct cam_req_mgr_core_link { + int32_t link_hdl; + int32_t num_devs; + enum cam_pipeline_delay max_delay; + struct cam_req_mgr_core_workq *workq; + int32_t pd_mask; + struct cam_req_mgr_connected_device *l_dev; + struct cam_req_mgr_req_data req; + struct cam_req_mgr_timer *watchdog; + struct completion workq_comp; + enum cam_req_mgr_link_state state; + void *parent; + struct mutex lock; + spinlock_t link_state_spin_lock; + uint32_t subscribe_event; + uint32_t trigger_mask; + struct cam_req_mgr_core_link *sync_link; + bool sync_link_sof_skip; + int32_t open_req_cnt; + uint32_t last_flush_id; + atomic_t is_used; + bool is_master; + bool initial_skip; + bool in_msync_mode; + int64_t initial_sync_req; + uint32_t retry_cnt; +}; + +/** + * struct cam_req_mgr_core_session + * - Session Properties + * @session_hdl : session identifier + * @num_links : num of active links for current session + * - Links of this session + * @links : pointer to array of links within session + * @in_q : Input request queue one per session + * - Session private data + * @entry : pvt data - entry in the list of sessions + * @lock : pvt data - spin lock to guard session data + * - Debug data + * @force_err_recovery : For debugging, we can force bubble recovery + * to be always ON or always OFF using debugfs. + * @sync_mode : Sync mode for this session links + */ +struct cam_req_mgr_core_session { + int32_t session_hdl; + uint32_t num_links; + struct cam_req_mgr_core_link *links[MAXIMUM_LINKS_PER_SESSION]; + struct list_head entry; + struct mutex lock; + int32_t force_err_recovery; + int32_t sync_mode; +}; + +/** + * struct cam_req_mgr_core_device + * - Core camera request manager data struct + * @session_head : list head holding sessions + * @crm_lock : mutex lock to protect session creation & destruction + */ +struct cam_req_mgr_core_device { + struct list_head session_head; + struct mutex crm_lock; +}; + +/** + * cam_req_mgr_create_session() + * @brief : creates session + * @ses_info : output param for session handle + * + * called as part of session creation. + */ +int cam_req_mgr_create_session(struct cam_req_mgr_session_info *ses_info); + +/** + * cam_req_mgr_destroy_session() + * @brief : destroy session + * @ses_info : session handle info, input param + * + * Called as part of session destroy + * return success/failure + */ +int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info); + +/** + * cam_req_mgr_link() + * @brief : creates a link for a session + * @link_info : handle and session info to create a link + * + * link is formed in a session for multiple devices. it creates + * a unique link handle for the link and is specific to a + * session. Returns link handle + */ +int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info); + +/** + * cam_req_mgr_unlink() + * @brief : destroy a link in a session + * @unlink_info : session and link handle info + * + * link is destroyed in a session + */ +int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info); + +/** + * cam_req_mgr_schedule_request() + * @brief: Request is scheduled + * @sched_req: request id, session and link id info, bubble recovery info + */ +int cam_req_mgr_schedule_request( + struct cam_req_mgr_sched_request *sched_req); + +/** + * cam_req_mgr_sync_mode_setup() + * @brief: sync for links in a session + * @sync_info: session, links info and master link info + */ +int cam_req_mgr_sync_config(struct cam_req_mgr_sync_mode *sync_info); + +/** + * cam_req_mgr_flush_requests() + * @brief: flush all requests + * @flush_info: requests related to link and session + */ +int cam_req_mgr_flush_requests( + struct cam_req_mgr_flush_info *flush_info); + +/** + * cam_req_mgr_core_device_init() + * @brief: initialize crm core + */ +int cam_req_mgr_core_device_init(void); + +/** + * cam_req_mgr_core_device_deinit() + * @brief: cleanp crm core + */ +int cam_req_mgr_core_device_deinit(void); + +/** + * cam_req_mgr_handle_core_shutdown() + * @brief: Handles camera close + */ +void cam_req_mgr_handle_core_shutdown(void); + +/** + * cam_req_mgr_link_control() + * @brief: Handles link control operations + * @control: Link control command + */ +int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control); + +#endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_core_defs.h b/drivers/cam_req_mgr/cam_req_mgr_core_defs.h new file mode 100644 index 000000000000..fbaa7de494f7 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_core_defs.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_REQ_MGR_CORE_DEFS_H_ +#define _CAM_REQ_MGR_CORE_DEFS_H_ + +#define CRM_TRACE_ENABLE 0 +#define CRM_DEBUG_MUTEX 0 + +#define SET_SUCCESS_BIT(ret, pd) (ret |= (1 << (pd))) + +#define SET_FAILURE_BIT(ret, pd) (ret &= (~(1 << (pd)))) + +#define CRM_GET_REQ_ID(in_q, idx) in_q->slot[idx].req_id + +#endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_debug.c b/drivers/cam_req_mgr/cam_req_mgr_debug.c new file mode 100644 index 000000000000..6b428c41c1b0 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_debug.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_req_mgr_debug.h" + +#define MAX_SESS_INFO_LINE_BUFF_LEN 256 + +static char sess_info_buffer[MAX_SESS_INFO_LINE_BUFF_LEN]; + +static int cam_req_mgr_debug_set_bubble_recovery(void *data, u64 val) +{ + struct cam_req_mgr_core_device *core_dev = data; + struct cam_req_mgr_core_session *session; + int rc = 0; + + mutex_lock(&core_dev->crm_lock); + + if (!list_empty(&core_dev->session_head)) { + list_for_each_entry(session, + &core_dev->session_head, entry) { + session->force_err_recovery = val; + } + } + + mutex_unlock(&core_dev->crm_lock); + + return rc; +} + +static int cam_req_mgr_debug_get_bubble_recovery(void *data, u64 *val) +{ + struct cam_req_mgr_core_device *core_dev = data; + struct cam_req_mgr_core_session *session; + + mutex_lock(&core_dev->crm_lock); + + if (!list_empty(&core_dev->session_head)) { + session = list_first_entry(&core_dev->session_head, + struct cam_req_mgr_core_session, + entry); + *val = session->force_err_recovery; + } + mutex_unlock(&core_dev->crm_lock); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(bubble_recovery, cam_req_mgr_debug_get_bubble_recovery, + cam_req_mgr_debug_set_bubble_recovery, "%lld\n"); + +static int session_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t session_info_read(struct file *t_file, char *t_char, + size_t t_size_t, loff_t *t_loff_t) +{ + int i; + char *out_buffer = sess_info_buffer; + char line_buffer[MAX_SESS_INFO_LINE_BUFF_LEN] = {0}; + struct cam_req_mgr_core_device *core_dev = + (struct cam_req_mgr_core_device *) t_file->private_data; + struct cam_req_mgr_core_session *session; + + memset(out_buffer, 0, MAX_SESS_INFO_LINE_BUFF_LEN); + + mutex_lock(&core_dev->crm_lock); + + if (!list_empty(&core_dev->session_head)) { + list_for_each_entry(session, + &core_dev->session_head, entry) { + snprintf(line_buffer, sizeof(line_buffer), + "session_hdl = %x \t" + "num_links = %d\n", + session->session_hdl, session->num_links); + strlcat(out_buffer, line_buffer, + sizeof(sess_info_buffer)); + for (i = 0; i < session->num_links; i++) { + snprintf(line_buffer, sizeof(line_buffer), + "link_hdl[%d] = 0x%x, num_devs connected = %d\n", + i, session->links[i]->link_hdl, + session->links[i]->num_devs); + strlcat(out_buffer, line_buffer, + sizeof(sess_info_buffer)); + } + } + } + + mutex_unlock(&core_dev->crm_lock); + + return simple_read_from_buffer(t_char, t_size_t, + t_loff_t, out_buffer, strlen(out_buffer)); +} + +static ssize_t session_info_write(struct file *t_file, + const char *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + memset(sess_info_buffer, 0, MAX_SESS_INFO_LINE_BUFF_LEN); + + return 0; +} + +static const struct file_operations session_info = { + .open = session_info_open, + .read = session_info_read, + .write = session_info_write, +}; + +int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev) +{ + struct dentry *debugfs_root; + char dirname[32] = {0}; + + snprintf(dirname, sizeof(dirname), "cam_req_mgr"); + debugfs_root = debugfs_create_dir(dirname, NULL); + if (!debugfs_root) + return -ENOMEM; + + if (!debugfs_create_file("sessions_info", 0644, + debugfs_root, core_dev, &session_info)) + return -ENOMEM; + + if (!debugfs_create_file("bubble_recovery", 0644, + debugfs_root, core_dev, &bubble_recovery)) + return -ENOMEM; + + return 0; +} diff --git a/drivers/cam_req_mgr/cam_req_mgr_debug.h b/drivers/cam_req_mgr/cam_req_mgr_debug.h new file mode 100644 index 000000000000..dc72c522d140 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_debug.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_DEBUG_H_ +#define _CAM_REQ_MGR_DEBUG_H_ + +#include +#include "cam_req_mgr_core.h" + +int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev); + +#endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c new file mode 100644 index 000000000000..74d5cfff8d60 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -0,0 +1,752 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_req_mgr_dev.h" +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_core.h" +#include "cam_subdev.h" +#include "cam_mem_mgr.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" +#include + +#define CAM_REQ_MGR_EVENT_MAX 30 + +static struct cam_req_mgr_device g_dev; +struct kmem_cache *g_cam_req_mgr_timer_cachep; + +static int cam_media_device_setup(struct device *dev) +{ + int rc; + + g_dev.v4l2_dev->mdev = kzalloc(sizeof(*g_dev.v4l2_dev->mdev), + GFP_KERNEL); + if (!g_dev.v4l2_dev->mdev) { + rc = -ENOMEM; + goto mdev_fail; + } + + media_device_init(g_dev.v4l2_dev->mdev); + g_dev.v4l2_dev->mdev->dev = dev; + strlcpy(g_dev.v4l2_dev->mdev->model, CAM_REQ_MGR_VNODE_NAME, + sizeof(g_dev.v4l2_dev->mdev->model)); + + rc = media_device_register(g_dev.v4l2_dev->mdev); + if (rc) + goto media_fail; + + return rc; + +media_fail: + kfree(g_dev.v4l2_dev->mdev); + g_dev.v4l2_dev->mdev = NULL; +mdev_fail: + return rc; +} + +static void cam_media_device_cleanup(void) +{ + media_entity_cleanup(&g_dev.video->entity); + media_device_unregister(g_dev.v4l2_dev->mdev); + kfree(g_dev.v4l2_dev->mdev); + g_dev.v4l2_dev->mdev = NULL; +} + +static int cam_v4l2_device_setup(struct device *dev) +{ + int rc; + + g_dev.v4l2_dev = kzalloc(sizeof(*g_dev.v4l2_dev), + GFP_KERNEL); + if (!g_dev.v4l2_dev) + return -ENOMEM; + + rc = v4l2_device_register(dev, g_dev.v4l2_dev); + if (rc) + goto reg_fail; + + return rc; + +reg_fail: + kfree(g_dev.v4l2_dev); + g_dev.v4l2_dev = NULL; + return rc; +} + +static void cam_v4l2_device_cleanup(void) +{ + v4l2_device_unregister(g_dev.v4l2_dev); + kfree(g_dev.v4l2_dev); + g_dev.v4l2_dev = NULL; +} + +static int cam_req_mgr_open(struct file *filep) +{ + int rc; + + mutex_lock(&g_dev.cam_lock); + if (g_dev.open_cnt >= 1) { + rc = -EALREADY; + goto end; + } + + rc = v4l2_fh_open(filep); + if (rc) { + CAM_ERR(CAM_CRM, "v4l2_fh_open failed: %d", rc); + goto end; + } + + spin_lock_bh(&g_dev.cam_eventq_lock); + g_dev.cam_eventq = filep->private_data; + spin_unlock_bh(&g_dev.cam_eventq_lock); + + g_dev.open_cnt++; + rc = cam_mem_mgr_init(); + if (rc) { + g_dev.open_cnt--; + CAM_ERR(CAM_CRM, "mem mgr init failed"); + goto mem_mgr_init_fail; + } + + mutex_unlock(&g_dev.cam_lock); + return rc; + +mem_mgr_init_fail: + v4l2_fh_release(filep); +end: + mutex_unlock(&g_dev.cam_lock); + return rc; +} + +static unsigned int cam_req_mgr_poll(struct file *f, + struct poll_table_struct *pll_table) +{ + int rc = 0; + struct v4l2_fh *eventq = f->private_data; + + if (!eventq) + return -EINVAL; + + poll_wait(f, &eventq->wait, pll_table); + if (v4l2_event_pending(eventq)) + rc = POLLPRI; + + return rc; +} + +static int cam_req_mgr_close(struct file *filep) +{ + struct v4l2_subdev *sd; + struct v4l2_fh *vfh = filep->private_data; + struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); + + mutex_lock(&g_dev.cam_lock); + + if (g_dev.open_cnt <= 0) { + mutex_unlock(&g_dev.cam_lock); + return -EINVAL; + } + + cam_req_mgr_handle_core_shutdown(); + + list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + continue; + if (sd->internal_ops && sd->internal_ops->close) { + CAM_DBG(CAM_CRM, "Invoke subdev close for device %s", + sd->name); + sd->internal_ops->close(sd, subdev_fh); + } + } + + g_dev.open_cnt--; + v4l2_fh_release(filep); + + spin_lock_bh(&g_dev.cam_eventq_lock); + g_dev.cam_eventq = NULL; + spin_unlock_bh(&g_dev.cam_eventq_lock); + + cam_req_mgr_util_free_hdls(); + cam_mem_mgr_deinit(); + mutex_unlock(&g_dev.cam_lock); + + return 0; +} + +static struct v4l2_file_operations g_cam_fops = { + .owner = THIS_MODULE, + .open = cam_req_mgr_open, + .poll = cam_req_mgr_poll, + .release = cam_req_mgr_close, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif +}; + +static int cam_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, CAM_REQ_MGR_EVENT_MAX, NULL); +} + +static int cam_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static long cam_private_ioctl(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + int rc; + struct cam_control *k_ioctl; + + if ((!arg) || (cmd != VIDIOC_CAM_CONTROL)) + return -EINVAL; + + k_ioctl = (struct cam_control *)arg; + + if (!k_ioctl->handle) + return -EINVAL; + + switch (k_ioctl->op_code) { + case CAM_REQ_MGR_CREATE_SESSION: { + struct cam_req_mgr_session_info ses_info; + + if (k_ioctl->size != sizeof(ses_info)) + return -EINVAL; + + if (copy_from_user(&ses_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_session_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_create_session(&ses_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ses_info, + sizeof(struct cam_req_mgr_session_info))) + rc = -EFAULT; + } + break; + + case CAM_REQ_MGR_DESTROY_SESSION: { + struct cam_req_mgr_session_info ses_info; + + if (k_ioctl->size != sizeof(ses_info)) + return -EINVAL; + + if (copy_from_user(&ses_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_session_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_destroy_session(&ses_info); + } + break; + + case CAM_REQ_MGR_LINK: { + struct cam_req_mgr_link_info link_info; + + if (k_ioctl->size != sizeof(link_info)) + return -EINVAL; + + if (copy_from_user(&link_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_link(&link_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &link_info, + sizeof(struct cam_req_mgr_link_info))) + rc = -EFAULT; + } + break; + + case CAM_REQ_MGR_UNLINK: { + struct cam_req_mgr_unlink_info unlink_info; + + if (k_ioctl->size != sizeof(unlink_info)) + return -EINVAL; + + if (copy_from_user(&unlink_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_unlink_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_unlink(&unlink_info); + } + break; + + case CAM_REQ_MGR_SCHED_REQ: { + struct cam_req_mgr_sched_request sched_req; + + if (k_ioctl->size != sizeof(sched_req)) + return -EINVAL; + + if (copy_from_user(&sched_req, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_sched_request))) { + return -EFAULT; + } + + rc = cam_req_mgr_schedule_request(&sched_req); + } + break; + + case CAM_REQ_MGR_FLUSH_REQ: { + struct cam_req_mgr_flush_info flush_info; + + if (k_ioctl->size != sizeof(flush_info)) + return -EINVAL; + + if (copy_from_user(&flush_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_flush_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_flush_requests(&flush_info); + } + break; + + case CAM_REQ_MGR_SYNC_MODE: { + struct cam_req_mgr_sync_mode sync_info; + + if (k_ioctl->size != sizeof(sync_info)) + return -EINVAL; + + if (copy_from_user(&sync_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_sync_mode))) { + return -EFAULT; + } + + rc = cam_req_mgr_sync_config(&sync_info); + } + break; + case CAM_REQ_MGR_ALLOC_BUF: { + struct cam_mem_mgr_alloc_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_mgr_alloc_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_alloc_and_map(&cmd); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &cmd, sizeof(struct cam_mem_mgr_alloc_cmd))) { + rc = -EFAULT; + break; + } + } + break; + case CAM_REQ_MGR_MAP_BUF: { + struct cam_mem_mgr_map_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_mgr_map_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_map(&cmd); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &cmd, sizeof(struct cam_mem_mgr_map_cmd))) { + rc = -EFAULT; + break; + } + } + break; + case CAM_REQ_MGR_RELEASE_BUF: { + struct cam_mem_mgr_release_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_mgr_release_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_release(&cmd); + } + break; + case CAM_REQ_MGR_CACHE_OPS: { + struct cam_mem_cache_ops_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_cache_ops_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_cache_ops(&cmd); + if (rc) + rc = -EINVAL; + } + break; + case CAM_REQ_MGR_LINK_CONTROL: { + struct cam_req_mgr_link_control cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_control))) { + rc = -EFAULT; + break; + } + + rc = cam_req_mgr_link_control(&cmd); + if (rc) + rc = -EINVAL; + } + break; + default: + return -ENOIOCTLCMD; + } + + return rc; +} + +static const struct v4l2_ioctl_ops g_cam_ioctl_ops = { + .vidioc_subscribe_event = cam_subscribe_event, + .vidioc_unsubscribe_event = cam_unsubscribe_event, + .vidioc_default = cam_private_ioctl, +}; + +static int cam_video_device_setup(void) +{ + int rc; + + g_dev.video = video_device_alloc(); + if (!g_dev.video) { + rc = -ENOMEM; + goto video_fail; + } + + g_dev.video->v4l2_dev = g_dev.v4l2_dev; + + strlcpy(g_dev.video->name, "cam-req-mgr", + sizeof(g_dev.video->name)); + g_dev.video->release = video_device_release; + g_dev.video->fops = &g_cam_fops; + g_dev.video->ioctl_ops = &g_cam_ioctl_ops; + g_dev.video->minor = -1; + g_dev.video->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(g_dev.video, VFL_TYPE_GRABBER, -1); + if (rc) + goto v4l2_fail; + + rc = media_entity_pads_init(&g_dev.video->entity, 0, NULL); + if (rc) + goto entity_fail; + + g_dev.video->entity.function = CAM_VNODE_DEVICE_TYPE; + g_dev.video->entity.name = video_device_node_name(g_dev.video); + + return rc; + +entity_fail: + video_unregister_device(g_dev.video); +v4l2_fail: + video_device_release(g_dev.video); + g_dev.video = NULL; +video_fail: + return rc; +} + +int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg, + uint32_t id, + uint32_t type) +{ + struct v4l2_event event; + struct cam_req_mgr_message *ev_header; + + if (!msg) + return -EINVAL; + + event.id = id; + event.type = type; + ev_header = CAM_REQ_MGR_GET_PAYLOAD_PTR(event, + struct cam_req_mgr_message); + memcpy(ev_header, msg, sizeof(struct cam_req_mgr_message)); + v4l2_event_queue(g_dev.video, &event); + + return 0; +} +EXPORT_SYMBOL(cam_req_mgr_notify_message); + +void cam_video_device_cleanup(void) +{ + video_unregister_device(g_dev.video); + video_device_release(g_dev.video); + g_dev.video = NULL; +} + +void cam_register_subdev_fops(struct v4l2_file_operations *fops) +{ + *fops = v4l2_subdev_fops; +} +EXPORT_SYMBOL(cam_register_subdev_fops); + +int cam_register_subdev(struct cam_subdev *csd) +{ + struct v4l2_subdev *sd; + int rc; + + if (g_dev.state != true) { + CAM_ERR(CAM_CRM, "camera root device not ready yet"); + return -ENODEV; + } + + if (!csd || !csd->name) { + CAM_ERR(CAM_CRM, "invalid arguments"); + return -EINVAL; + } + + mutex_lock(&g_dev.dev_lock); + if ((g_dev.subdev_nodes_created) && + (csd->sd_flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) { + CAM_ERR(CAM_CRM, + "dynamic node is not allowed, name: %s, type :%d", + csd->name, csd->ent_function); + rc = -EINVAL; + goto reg_fail; + } + + sd = &csd->sd; + v4l2_subdev_init(sd, csd->ops); + sd->internal_ops = csd->internal_ops; + snprintf(sd->name, ARRAY_SIZE(sd->name), csd->name); + v4l2_set_subdevdata(sd, csd->token); + + sd->flags = csd->sd_flags; + sd->entity.num_pads = 0; + sd->entity.pads = NULL; + sd->entity.function = csd->ent_function; + + rc = v4l2_device_register_subdev(g_dev.v4l2_dev, sd); + if (rc) { + CAM_ERR(CAM_CRM, "register subdev failed"); + goto reg_fail; + } + g_dev.count++; + +reg_fail: + mutex_unlock(&g_dev.dev_lock); + return rc; +} +EXPORT_SYMBOL(cam_register_subdev); + +int cam_unregister_subdev(struct cam_subdev *csd) +{ + if (g_dev.state != true) { + CAM_ERR(CAM_CRM, "camera root device not ready yet"); + return -ENODEV; + } + + mutex_lock(&g_dev.dev_lock); + v4l2_device_unregister_subdev(&csd->sd); + g_dev.count--; + mutex_unlock(&g_dev.dev_lock); + + return 0; +} +EXPORT_SYMBOL(cam_unregister_subdev); + +static int cam_req_mgr_remove(struct platform_device *pdev) +{ + cam_req_mgr_core_device_deinit(); + cam_req_mgr_util_deinit(); + cam_media_device_cleanup(); + cam_video_device_cleanup(); + cam_v4l2_device_cleanup(); + mutex_destroy(&g_dev.dev_lock); + g_dev.state = false; + g_dev.subdev_nodes_created = false; + + return 0; +} + +static int cam_req_mgr_probe(struct platform_device *pdev) +{ + int rc; + + rc = cam_v4l2_device_setup(&pdev->dev); + if (rc) + return rc; + + rc = cam_media_device_setup(&pdev->dev); + if (rc) + goto media_setup_fail; + + rc = cam_video_device_setup(); + if (rc) + goto video_setup_fail; + + g_dev.open_cnt = 0; + mutex_init(&g_dev.cam_lock); + spin_lock_init(&g_dev.cam_eventq_lock); + g_dev.subdev_nodes_created = false; + mutex_init(&g_dev.dev_lock); + + rc = cam_req_mgr_util_init(); + if (rc) { + CAM_ERR(CAM_CRM, "cam req mgr util init is failed"); + goto req_mgr_util_fail; + } + + rc = cam_req_mgr_core_device_init(); + if (rc) { + CAM_ERR(CAM_CRM, "core device setup failed"); + goto req_mgr_core_fail; + } + + g_dev.state = true; + + if (g_cam_req_mgr_timer_cachep == NULL) { + g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer", + sizeof(struct cam_req_mgr_timer), 64, + SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | + SLAB_POISON | SLAB_STORE_USER, NULL); + if (!g_cam_req_mgr_timer_cachep) + CAM_ERR(CAM_CRM, + "Failed to create kmem_cache for crm_timer"); + else + CAM_DBG(CAM_CRM, "Name : %s", + g_cam_req_mgr_timer_cachep->name); + } + + return rc; + +req_mgr_core_fail: + cam_req_mgr_util_deinit(); +req_mgr_util_fail: + mutex_destroy(&g_dev.dev_lock); + mutex_destroy(&g_dev.cam_lock); + cam_video_device_cleanup(); +video_setup_fail: + cam_media_device_cleanup(); +media_setup_fail: + cam_v4l2_device_cleanup(); + return rc; +} + +static const struct of_device_id cam_req_mgr_dt_match[] = { + {.compatible = "qcom,cam-req-mgr"}, + {} +}; +MODULE_DEVICE_TABLE(of, cam_dt_match); + +static struct platform_driver cam_req_mgr_driver = { + .probe = cam_req_mgr_probe, + .remove = cam_req_mgr_remove, + .driver = { + .name = "cam_req_mgr", + .owner = THIS_MODULE, + .of_match_table = cam_req_mgr_dt_match, + .suppress_bind_attrs = true, + }, +}; + +int cam_dev_mgr_create_subdev_nodes(void) +{ + int rc; + struct v4l2_subdev *sd; + + if (!g_dev.v4l2_dev) + return -EINVAL; + + if (g_dev.state != true) { + CAM_ERR(CAM_CRM, "camera root device not ready yet"); + return -ENODEV; + } + + mutex_lock(&g_dev.dev_lock); + if (g_dev.subdev_nodes_created) { + rc = -EEXIST; + goto create_fail; + } + + rc = v4l2_device_register_subdev_nodes(g_dev.v4l2_dev); + if (rc) { + CAM_ERR(CAM_CRM, "failed to register the sub devices"); + goto create_fail; + } + + list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + continue; + sd->entity.name = video_device_node_name(sd->devnode); + CAM_DBG(CAM_CRM, "created node :%s", sd->entity.name); + } + + g_dev.subdev_nodes_created = true; + +create_fail: + mutex_unlock(&g_dev.dev_lock); + return rc; +} + +static int __init cam_req_mgr_init(void) +{ + return platform_driver_register(&cam_req_mgr_driver); +} + +static int __init cam_req_mgr_late_init(void) +{ + return cam_dev_mgr_create_subdev_nodes(); +} + +static void __exit cam_req_mgr_exit(void) +{ + platform_driver_unregister(&cam_req_mgr_driver); +} + +module_init(cam_req_mgr_init); +late_initcall(cam_req_mgr_late_init); +module_exit(cam_req_mgr_exit); +MODULE_DESCRIPTION("Camera Request Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.h b/drivers/cam_req_mgr/cam_req_mgr_dev.h new file mode 100644 index 000000000000..48ad09ce5ee2 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_DEV_H_ +#define _CAM_REQ_MGR_DEV_H_ + +/** + * struct cam_req_mgr_device - a camera request manager device + * + * @video: pointer to struct video device. + * @v4l2_dev: pointer to struct v4l2 device. + * @subdev_nodes_created: flag to check the created state. + * @count: number of subdevices registered. + * @dev_lock: lock for the subdevice count. + * @state: state of the root device. + * @open_cnt: open count of subdev + * @cam_lock: per file handle lock + * @cam_eventq: event queue + * @cam_eventq_lock: lock for event queue + */ +struct cam_req_mgr_device { + struct video_device *video; + struct v4l2_device *v4l2_dev; + bool subdev_nodes_created; + int count; + struct mutex dev_lock; + bool state; + int32_t open_cnt; + struct mutex cam_lock; + struct v4l2_fh *cam_eventq; + spinlock_t cam_eventq_lock; +}; + +#define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \ + (type *)((char *)ev.u.data) + +int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg, + uint32_t id, + uint32_t type); + +#endif /* _CAM_REQ_MGR_DEV_H_ */ diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h new file mode 100644 index 000000000000..40c9050afbb5 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -0,0 +1,332 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_INTERFACE_H +#define _CAM_REQ_MGR_INTERFACE_H + +#include +#include +#include "cam_req_mgr_core_defs.h" +#include "cam_req_mgr_util.h" + +struct cam_req_mgr_trigger_notify; +struct cam_req_mgr_error_notify; +struct cam_req_mgr_add_request; +struct cam_req_mgr_device_info; +struct cam_req_mgr_core_dev_link_setup; +struct cam_req_mgr_apply_request; +struct cam_req_mgr_flush_request; +struct cam_req_mgr_link_evt_data; + +#define SKIP_NEXT_FRAME 0x100 + +/* Request Manager -- camera device driver interface */ +/** + * @brief: camera kernel drivers to cam req mgr communication + * + * @cam_req_mgr_notify_trigger: for device which generates trigger to inform CRM + * @cam_req_mgr_notify_err : device use this to inform about different errors + * @cam_req_mgr_add_req : to info CRm about new rqeuest received from + * userspace + */ +typedef int (*cam_req_mgr_notify_trigger)( + struct cam_req_mgr_trigger_notify *); +typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *); +typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); + +/** + * @brief: cam req mgr to camera device drivers + * + * @cam_req_mgr_get_dev_info: to fetch details about device linked + * @cam_req_mgr_link_setup : to establish link with device for a session + * @cam_req_mgr_notify_err : to broadcast error happened on link for request id + * @cam_req_mgr_apply_req : CRM asks device to apply certain request id. + * @cam_req_mgr_flush_req : Flush or cancel request + * cam_req_mgr_process_evt : generic events + */ +typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *); +typedef int (*cam_req_mgr_link_setup)( + struct cam_req_mgr_core_dev_link_setup *); +typedef int (*cam_req_mgr_apply_req)(struct cam_req_mgr_apply_request *); +typedef int (*cam_req_mgr_flush_req)(struct cam_req_mgr_flush_request *); +typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *); + +/** + * @brief : cam_req_mgr_crm_cb - func table + * + * @notify_trigger : payload for trigger indication event + * @notify_err : payload for different error occurred at device + * @add_req : payload to inform which device and what request is received + */ +struct cam_req_mgr_crm_cb { + cam_req_mgr_notify_trigger notify_trigger; + cam_req_mgr_notify_err notify_err; + cam_req_mgr_add_req add_req; +}; + +/** + * @brief : cam_req_mgr_kmd_ops - func table + * + * @get_dev_info : payload to fetch device details + * @link_setup : payload to establish link with device + * @apply_req : payload to apply request id on a device linked + * @flush_req : payload to flush request + * @process_evt : payload to generic event + */ +struct cam_req_mgr_kmd_ops { + cam_req_mgr_get_dev_info get_dev_info; + cam_req_mgr_link_setup link_setup; + cam_req_mgr_apply_req apply_req; + cam_req_mgr_flush_req flush_req; + cam_req_mgr_process_evt process_evt; +}; + +/** + * enum cam_pipeline_delay + * @brief : enumerator for different pipeline delays in camera + * + * @DELAY_0 : device processed settings on same frame + * @DELAY_1 : device processed settings after 1 frame + * @DELAY_2 : device processed settings after 2 frames + * @DELAY_MAX : maximum supported pipeline delay + */ +enum cam_pipeline_delay { + CAM_PIPELINE_DELAY_0, + CAM_PIPELINE_DELAY_1, + CAM_PIPELINE_DELAY_2, + CAM_PIPELINE_DELAY_MAX, +}; + +/** + * @CAM_TRIGGER_POINT_SOF : Trigger point for SOF + * @CAM_TRIGGER_POINT_EOF : Trigger point for EOF + */ +#define CAM_TRIGGER_POINT_SOF (1 << 0) +#define CAM_TRIGGER_POINT_EOF (1 << 1) + +/** + * enum cam_req_status + * @brief : enumerator for request status + * + * @SUCCESS : device processed settings successfully + * @FAILED : device processed settings failed + * @MAX : invalid status value + */ +enum cam_req_status { + CAM_REQ_STATUS_SUCCESS, + CAM_REQ_STATUS_FAILED, + CAM_REQ_STATUS_MAX, +}; + +/** + * enum cam_req_mgr_device_error + * @brief : enumerator for different errors occurred at device + * + * @NOT_FOUND : settings asked by request manager is not found + * @BUBBLE : device hit timing issue and is able to recover + * @FATAL : device is in bad shape and can not recover from error + * @PAGE_FAULT : Page fault while accessing memory + * @OVERFLOW : Bus Overflow for IFE/VFE + * @TIMEOUT : Timeout from cci or bus. + * @MAX : Invalid error value + */ +enum cam_req_mgr_device_error { + CRM_KMD_ERR_NOT_FOUND, + CRM_KMD_ERR_BUBBLE, + CRM_KMD_ERR_FATAL, + CRM_KMD_ERR_PAGE_FAULT, + CRM_KMD_ERR_OVERFLOW, + CRM_KMD_ERR_TIMEOUT, + CRM_KMD_ERR_MAX, +}; + +/** + * enum cam_req_mgr_device_id + * @brief : enumerator for different devices in subsystem + * + * @CAM_REQ_MGR : request manager itself + * @SENSOR : sensor device + * @FLASH : LED flash or dual LED device + * @ACTUATOR : lens mover + * @IFE : Image processing device + * @EXTERNAL_1 : third party device + * @EXTERNAL_2 : third party device + * @EXTERNAL_3 : third party device + * @MAX : invalid device id + */ +enum cam_req_mgr_device_id { + CAM_REQ_MGR_DEVICE, + CAM_REQ_MGR_DEVICE_SENSOR, + CAM_REQ_MGR_DEVICE_FLASH, + CAM_REQ_MGR_DEVICE_ACTUATOR, + CAM_REQ_MGR_DEVICE_IFE, + CAM_REQ_MGR_DEVICE_EXTERNAL_1, + CAM_REQ_MGR_DEVICE_EXTERNAL_2, + CAM_REQ_MGR_DEVICE_EXTERNAL_3, + CAM_REQ_MGR_DEVICE_ID_MAX, +}; + +/* Camera device driver to Req Mgr device interface */ + +/** + * enum cam_req_mgr_link_evt_type + * @CAM_REQ_MGR_LINK_EVT_ERR : error on the link from any of the + * connected devices + * @CAM_REQ_MGR_LINK_EVT_PAUSE : to pause the link + * @CAM_REQ_MGR_LINK_EVT_RESUME : resumes the link which was paused + * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE : request manager has detected an sof freeze + * @CAM_REQ_MGR_LINK_EVT_MAX : invalid event type + */ +enum cam_req_mgr_link_evt_type { + CAM_REQ_MGR_LINK_EVT_ERR, + CAM_REQ_MGR_LINK_EVT_PAUSE, + CAM_REQ_MGR_LINK_EVT_RESUME, + CAM_REQ_MGR_LINK_EVT_SOF_FREEZE, + CAM_REQ_MGR_LINK_EVT_MAX, +}; + +/** + * struct cam_req_mgr_trigger_notify + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @frame_id : frame id for internal tracking + * @trigger : trigger point of this notification, CRM will send apply + * only to the devices which subscribe to this point. + */ +struct cam_req_mgr_trigger_notify { + int32_t link_hdl; + int32_t dev_hdl; + int64_t frame_id; + uint32_t trigger; +}; + +/** + * struct cam_req_mgr_error_notify + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @req_id : req id which hit error + * @error : what error device hit while processing this req + */ +struct cam_req_mgr_error_notify { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t req_id; + enum cam_req_mgr_device_error error; +}; + +/** + * struct cam_req_mgr_add_request + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @req_id : req id which device is ready to process + * @skip_before_applying : before applying req mgr introduce bubble + * by not sending request to device/s. + * ex: IFE and Flash + */ +struct cam_req_mgr_add_request { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t req_id; + uint32_t skip_before_applying; +}; + + +/* CRM to KMD devices */ +/** + * struct cam_req_mgr_device_info + * @dev_hdl : Input_param : device handle for reference + * @name : link link or unlink + * @dev_id : device id info + * @p_delay : delay between time settings applied and take effect + * @trigger : Trigger point for the client + * + */ +struct cam_req_mgr_device_info { + int32_t dev_hdl; + char name[256]; + enum cam_req_mgr_device_id dev_id; + enum cam_pipeline_delay p_delay; + uint32_t trigger; +}; + +/** + * struct cam_req_mgr_core_dev_link_setup + * @link_enable : link link or unlink + * @link_hdl : link identifier + * @dev_hdl : device handle for reference + * @max_delay : max pipeline delay on this link + * @crm_cb : callback funcs to communicate with req mgr + * @subscribe_event : the mask of trigger points this link subscribes + * + */ +struct cam_req_mgr_core_dev_link_setup { + int32_t link_enable; + int32_t link_hdl; + int32_t dev_hdl; + enum cam_pipeline_delay max_delay; + struct cam_req_mgr_crm_cb *crm_cb; + uint32_t subscribe_event; +}; + +/** + * struct cam_req_mgr_apply_request + * @link_hdl : link identifier + * @dev_hdl : device handle for cross check + * @request_id : request id settings to apply + * @report_if_bubble : report to crm if failure in applying + * @trigger_point : the trigger point of this apply + * + */ +struct cam_req_mgr_apply_request { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t request_id; + int32_t report_if_bubble; + uint32_t trigger_point; +}; + +/** + * struct cam_req_mgr_flush_request + * @link_hdl : link identifier + * @dev_hdl : device handle for cross check + * @type : cancel request type flush all or a request + * @request_id : request id to cancel + * + */ +struct cam_req_mgr_flush_request { + int32_t link_hdl; + int32_t dev_hdl; + uint32_t type; + uint64_t req_id; +}; + +/** + * struct cam_req_mgr_event_data + * @link_hdl : link handle + * @req_id : request id + * + */ +struct cam_req_mgr_link_evt_data { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t req_id; + + enum cam_req_mgr_link_evt_type evt_type; + union { + enum cam_req_mgr_device_error error; + } u; +}; + +/** + * struct cam_req_mgr_send_request + * @link_hdl : link identifier + * @idx : slot idx + * + */ +struct cam_req_mgr_send_request { + int32_t link_hdl; + struct cam_req_mgr_req_queue *in_q; +}; +#endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.c b/drivers/cam_req_mgr/cam_req_mgr_timer.c new file mode 100644 index 000000000000..ba44534fa48d --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_req_mgr_timer.h" +#include "cam_debug_util.h" + +void crm_timer_reset(struct cam_req_mgr_timer *crm_timer) +{ + if (!crm_timer) + return; + CAM_DBG(CAM_CRM, "Starting timer to fire in %d ms. (jiffies=%lu)\n", + crm_timer->expires, jiffies); + mod_timer(&crm_timer->sys_timer, + (jiffies + msecs_to_jiffies(crm_timer->expires))); +} + +void crm_timer_callback(struct timer_list *timer_data) +{ + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + if (!timer) { + CAM_ERR(CAM_CRM, "NULL timer"); + return; + } + CAM_DBG(CAM_CRM, "timer %pK parent %pK", timer, timer->parent); + crm_timer_reset(timer); +} + +void crm_timer_modify(struct cam_req_mgr_timer *crm_timer, + int32_t expires) +{ + CAM_DBG(CAM_CRM, "new time %d", expires); + if (crm_timer) { + crm_timer->expires = expires; + crm_timer_reset(crm_timer); + } +} + +int crm_timer_init(struct cam_req_mgr_timer **timer, + int32_t expires, void *parent, void (*timer_cb)(struct timer_list *)) +{ + int ret = 0; + struct cam_req_mgr_timer *crm_timer = NULL; + + CAM_DBG(CAM_CRM, "init timer %d %pK", expires, *timer); + if (*timer == NULL) { + if (g_cam_req_mgr_timer_cachep) { + crm_timer = kmem_cache_alloc(g_cam_req_mgr_timer_cachep, + __GFP_ZERO | GFP_KERNEL); + if (!crm_timer) { + ret = -ENOMEM; + goto end; + } + } + + else { + ret = -ENOMEM; + goto end; + } + + if (timer_cb != NULL) + crm_timer->timer_cb = timer_cb; + else + crm_timer->timer_cb = crm_timer_callback; + + crm_timer->expires = expires; + crm_timer->parent = parent; + timer_setup(&crm_timer->sys_timer, + crm_timer->timer_cb, 0); + crm_timer_reset(crm_timer); + *timer = crm_timer; + } else { + CAM_WARN(CAM_CRM, "Timer already exists!!"); + ret = -EINVAL; + } +end: + return ret; +} +void crm_timer_exit(struct cam_req_mgr_timer **crm_timer) +{ + CAM_DBG(CAM_CRM, "destroy timer %pK @ %pK", *crm_timer, crm_timer); + if (*crm_timer) { + del_timer_sync(&(*crm_timer)->sys_timer); + if (g_cam_req_mgr_timer_cachep) + kmem_cache_free(g_cam_req_mgr_timer_cachep, *crm_timer); + *crm_timer = NULL; + } +} diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.h b/drivers/cam_req_mgr/cam_req_mgr_timer.h new file mode 100644 index 000000000000..9f9ba71a3879 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_TIMER_H_ +#define _CAM_REQ_MGR_TIMER_H_ + +#include +#include + +#include "cam_req_mgr_core_defs.h" + +/** struct cam_req_mgr_timer + * @expires : timeout value for timer + * @sys_timer : system timer variable + * @parent : priv data - link pointer + * @timer_cb : callback func which will be called when timeout expires + */ +struct cam_req_mgr_timer { + int32_t expires; + struct timer_list sys_timer; + void *parent; + void (*timer_cb)(struct timer_list *timer_data); +}; + +/** + * crm_timer_modify() + * @brief : allows ser to modify expiry time. + * @timer : timer which will be reset to expires values + */ +void crm_timer_modify(struct cam_req_mgr_timer *crm_timer, + int32_t expires); + +/** + * crm_timer_reset() + * @brief : destroys the timer allocated. + * @timer : timer which will be reset to expires values + */ +void crm_timer_reset(struct cam_req_mgr_timer *timer); + +/** + * crm_timer_init() + * @brief : create a new general purpose timer. + * timer utility takes care of allocating memory and deleting + * @timer : double pointer to new timer allocated + * @expires : Timeout value to fire callback + * @parent : void pointer which caller can use for book keeping + * @timer_cb : caller can chose to use its own callback function when + * timer fires the timeout. If no value is set timer util + * will use default. + */ +int crm_timer_init(struct cam_req_mgr_timer **timer, + int32_t expires, void *parent, void (*timer_cb)(struct timer_list *)); + +/** + * crm_timer_exit() + * @brief : destroys the timer allocated. + * @timer : timer pointer which will be freed + */ +void crm_timer_exit(struct cam_req_mgr_timer **timer); + +extern struct kmem_cache *g_cam_req_mgr_timer_cachep; +#endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c new file mode 100644 index 000000000000..54ab1680b112 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "CAM-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include "cam_req_mgr_util.h" +#include "cam_debug_util.h" + +static struct cam_req_mgr_util_hdl_tbl *hdl_tbl; +static DEFINE_SPINLOCK(hdl_tbl_lock); + +int cam_req_mgr_util_init(void) +{ + int rc = 0; + int bitmap_size; + static struct cam_req_mgr_util_hdl_tbl *hdl_tbl_local; + + if (hdl_tbl) { + rc = -EINVAL; + CAM_ERR(CAM_CRM, "Hdl_tbl is already present"); + goto hdl_tbl_check_failed; + } + + hdl_tbl_local = kzalloc(sizeof(*hdl_tbl), GFP_KERNEL); + if (!hdl_tbl_local) { + rc = -ENOMEM; + goto hdl_tbl_alloc_failed; + } + spin_lock_bh(&hdl_tbl_lock); + if (hdl_tbl) { + spin_unlock_bh(&hdl_tbl_lock); + rc = -EEXIST; + kfree(hdl_tbl_local); + goto hdl_tbl_check_failed; + } + hdl_tbl = hdl_tbl_local; + spin_unlock_bh(&hdl_tbl_lock); + + bitmap_size = BITS_TO_LONGS(CAM_REQ_MGR_MAX_HANDLES) * sizeof(long); + hdl_tbl->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!hdl_tbl->bitmap) { + rc = -ENOMEM; + goto bitmap_alloc_fail; + } + hdl_tbl->bits = bitmap_size * BITS_PER_BYTE; + + return rc; + +bitmap_alloc_fail: + kfree(hdl_tbl); + hdl_tbl = NULL; +hdl_tbl_alloc_failed: +hdl_tbl_check_failed: + return rc; +} + +int cam_req_mgr_util_deinit(void) +{ + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + kfree(hdl_tbl->bitmap); + hdl_tbl->bitmap = NULL; + kfree(hdl_tbl); + hdl_tbl = NULL; + spin_unlock_bh(&hdl_tbl_lock); + + return 0; +} + +int cam_req_mgr_util_free_hdls(void) +{ + int i = 0; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++) { + if (hdl_tbl->hdl[i].state == HDL_ACTIVE) { + CAM_ERR(CAM_CRM, "Dev handle = %x session_handle = %x", + hdl_tbl->hdl[i].hdl_value, + hdl_tbl->hdl[i].session_hdl); + hdl_tbl->hdl[i].state = HDL_FREE; + clear_bit(i, hdl_tbl->bitmap); + } + } + bitmap_zero(hdl_tbl->bitmap, CAM_REQ_MGR_MAX_HANDLES); + spin_unlock_bh(&hdl_tbl_lock); + + return 0; +} + +static int32_t cam_get_free_handle_index(void) +{ + int idx; + + idx = find_first_zero_bit(hdl_tbl->bitmap, hdl_tbl->bits); + + if (idx >= CAM_REQ_MGR_MAX_HANDLES || idx < 0) + return -ENOSR; + + set_bit(idx, hdl_tbl->bitmap); + + return idx; +} + +int32_t cam_create_session_hdl(void *priv) +{ + int idx; + int rand = 0; + int32_t handle = 0; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + idx = cam_get_free_handle_index(); + if (idx < 0) { + CAM_ERR(CAM_CRM, "Unable to create session handle"); + spin_unlock_bh(&hdl_tbl_lock); + return idx; + } + + get_random_bytes(&rand, CAM_REQ_MGR_RND1_BYTES); + handle = GET_DEV_HANDLE(rand, HDL_TYPE_SESSION, idx); + hdl_tbl->hdl[idx].session_hdl = handle; + hdl_tbl->hdl[idx].hdl_value = handle; + hdl_tbl->hdl[idx].type = HDL_TYPE_SESSION; + hdl_tbl->hdl[idx].state = HDL_ACTIVE; + hdl_tbl->hdl[idx].priv = priv; + hdl_tbl->hdl[idx].ops = NULL; + spin_unlock_bh(&hdl_tbl_lock); + + return handle; +} + +int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) +{ + int idx; + int rand = 0; + int32_t handle; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + idx = cam_get_free_handle_index(); + if (idx < 0) { + CAM_ERR(CAM_CRM, "Unable to create device handle"); + spin_unlock_bh(&hdl_tbl_lock); + return idx; + } + + get_random_bytes(&rand, CAM_REQ_MGR_RND1_BYTES); + handle = GET_DEV_HANDLE(rand, HDL_TYPE_DEV, idx); + hdl_tbl->hdl[idx].session_hdl = hdl_data->session_hdl; + hdl_tbl->hdl[idx].hdl_value = handle; + hdl_tbl->hdl[idx].type = HDL_TYPE_DEV; + hdl_tbl->hdl[idx].state = HDL_ACTIVE; + hdl_tbl->hdl[idx].priv = hdl_data->priv; + hdl_tbl->hdl[idx].ops = hdl_data->ops; + spin_unlock_bh(&hdl_tbl_lock); + + pr_debug("%s: handle = %x", __func__, handle); + return handle; +} + +void *cam_get_device_priv(int32_t dev_hdl) +{ + int idx; + int type; + void *priv; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Hdl tbl is NULL"); + goto device_priv_fail; + } + + idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); + if (idx >= CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid idx"); + goto device_priv_fail; + } + + if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid state"); + goto device_priv_fail; + } + + type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl); + if (HDL_TYPE_DEV != type && HDL_TYPE_SESSION != type) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid type"); + goto device_priv_fail; + } + + if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid hdl"); + goto device_priv_fail; + } + + priv = hdl_tbl->hdl[idx].priv; + spin_unlock_bh(&hdl_tbl_lock); + + return priv; + +device_priv_fail: + spin_unlock_bh(&hdl_tbl_lock); + return NULL; +} + +void *cam_get_device_ops(int32_t dev_hdl) +{ + int idx; + int type; + void *ops; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + goto device_ops_fail; + } + + idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); + if (idx >= CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid idx"); + goto device_ops_fail; + } + + if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) { + CAM_ERR(CAM_CRM, "Invalid state"); + goto device_ops_fail; + } + + type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl); + if (HDL_TYPE_DEV != type && HDL_TYPE_SESSION != type) { + CAM_ERR(CAM_CRM, "Invalid type"); + goto device_ops_fail; + } + + if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) { + CAM_ERR(CAM_CRM, "Invalid hdl"); + goto device_ops_fail; + } + + ops = hdl_tbl->hdl[idx].ops; + spin_unlock_bh(&hdl_tbl_lock); + + return ops; + +device_ops_fail: + spin_unlock_bh(&hdl_tbl_lock); + return NULL; +} + +static int cam_destroy_hdl(int32_t dev_hdl, int dev_hdl_type) +{ + int idx; + int type; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + goto destroy_hdl_fail; + } + + idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); + if (idx >= CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid idx %d", idx); + goto destroy_hdl_fail; + } + + if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) { + CAM_ERR(CAM_CRM, "Invalid state"); + goto destroy_hdl_fail; + } + + type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl); + if (type != dev_hdl_type) { + CAM_ERR(CAM_CRM, "Invalid type %d, %d", type, dev_hdl_type); + goto destroy_hdl_fail; + } + + if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) { + CAM_ERR(CAM_CRM, "Invalid hdl"); + goto destroy_hdl_fail; + } + + hdl_tbl->hdl[idx].state = HDL_FREE; + hdl_tbl->hdl[idx].ops = NULL; + hdl_tbl->hdl[idx].priv = NULL; + clear_bit(idx, hdl_tbl->bitmap); + spin_unlock_bh(&hdl_tbl_lock); + + return 0; + +destroy_hdl_fail: + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; +} + +int cam_destroy_device_hdl(int32_t dev_hdl) +{ + return cam_destroy_hdl(dev_hdl, HDL_TYPE_DEV); +} + +int cam_destroy_session_hdl(int32_t dev_hdl) +{ + return cam_destroy_hdl(dev_hdl, HDL_TYPE_SESSION); +} diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.h b/drivers/cam_req_mgr/cam_req_mgr_util.h new file mode 100644 index 000000000000..f22c6cbae8ef --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_util.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_UTIL_API_H_ +#define _CAM_REQ_MGR_UTIL_API_H_ + +#include +#include "cam_req_mgr_util_priv.h" + +/** + * state of a handle(session/device) + * @HDL_FREE: free handle + * @HDL_ACTIVE: active handles + */ +enum hdl_state { + HDL_FREE, + HDL_ACTIVE +}; + +/** + * handle type + * @HDL_TYPE_DEV: for device and link + * @HDL_TYPE_SESSION: for session + */ +enum hdl_type { + HDL_TYPE_DEV = 1, + HDL_TYPE_SESSION +}; + +/** + * struct handle + * @session_hdl: session handle + * @hdl_value: Allocated handle + * @type: session/device handle + * @state: free/used + * @ops: ops structure + * @priv: private data of a handle + */ +struct handle { + int32_t session_hdl; + uint32_t hdl_value; + enum hdl_type type; + enum hdl_state state; + void *ops; + void *priv; +}; + +/** + * struct cam_req_mgr_util_hdl_tbl + * @hdl: row of handles + * @bitmap: bit map to get free hdl row idx + * @bits: size of bit map in bits + */ +struct cam_req_mgr_util_hdl_tbl { + struct handle hdl[CAM_REQ_MGR_MAX_HANDLES]; + void *bitmap; + size_t bits; +}; + +/** + * cam_req_mgr_util APIs for KMD drivers and cam_req_mgr + * @session_hdl: session_hdl info + * @v4l2_sub_dev_flag: flag to create v4l2 sub device + * @media_entity_flag: flag for media entity + * @reserved: reserved field + * @ops: ops pointer for a device handle + * @priv: private data for a device handle + */ +struct cam_create_dev_hdl { + int32_t session_hdl; + int32_t v4l2_sub_dev_flag; + int32_t media_entity_flag; + int32_t reserved; + void *ops; + void *priv; +}; + +/** + * cam_create_session_hdl() - create a session handle + * @priv: private data for a session handle + * + * cam_req_mgr core calls this function to get + * a unique session handle. Returns a unique session + * handle + */ +int32_t cam_create_session_hdl(void *priv); + +/** + * cam_create_device_hdl() - create a device handle + * @hdl_data: session hdl, flags, ops and priv dara as input + * + * cam_req_mgr_core calls this function to get + * session and link handles + * KMD drivers calls this function to create + * a device handle. Returns a unique device handle + */ +int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data); + +/** + * cam_get_device_priv() - get private data of a handle + * @dev_hdl: handle for a session/link/device + * + * cam_req_mgr_core and KMD drivers use this function to + * get private data of a handle. Returns a private data + * structure pointer. + */ +void *cam_get_device_priv(int32_t dev_hdl); + +/** + * cam_get_device_ops() - get ops of a handle + * @dev_hdl: handle for a session/link/device + * + * cam_req_mgr_core and KMD drivers use this function to + * get ops of a handle. Returns a pointer to ops. + */ +void *cam_get_device_ops(int32_t dev_hdl); + +/** + * cam_destroy_device_hdl() - destroy device handle + * @dev_hdl: handle for a link/device. + * + * Returns success/failure + */ +int32_t cam_destroy_device_hdl(int32_t dev_hdl); + +/** + * cam_destroy_session_hdl() - destroy device handle + * @dev_hdl: handle for a session + * + * Returns success/failure + */ +int32_t cam_destroy_session_hdl(int32_t dev_hdl); + + +/* Internal functions */ +/** + * cam_req_mgr_util_init() - init function of cam_req_mgr_util + * + * This is called as part of probe function to initialize + * handle table, bitmap, locks + */ +int cam_req_mgr_util_init(void); + +/** + * cam_req_mgr_util_deinit() - deinit function of cam_req_mgr_util + * + * This function is called in case of probe failure + */ +int32_t cam_req_mgr_util_deinit(void); + +/** + * cam_req_mgr_util_free_hdls() - free handles in case of crash + * + * Called from cam_req_mgr_dev release function to make sure + * all data structures are cleaned to avoid leaks + * + * cam_req_mgr core can call this function at the end of + * camera to make sure all stale entries are printed and + * cleaned + */ +int32_t cam_req_mgr_util_free_hdls(void); + +#endif /* _CAM_REQ_MGR_UTIL_API_H_ */ diff --git a/drivers/cam_req_mgr/cam_req_mgr_util_priv.h b/drivers/cam_req_mgr/cam_req_mgr_util_priv.h new file mode 100644 index 000000000000..075f5c34702d --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_util_priv.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_UTIL_PRIV_H_ +#define _CAM_REQ_MGR_UTIL_PRIV_H_ + +/** + * handle format: + * @bits (0-7): handle index + * @bits (8-11): handle type + * @bits (12-15): reserved + * @bits (16-23): random bits + * @bits (24-31): zeros + */ + +#define CAM_REQ_MGR_HDL_SIZE 32 +#define CAM_REQ_MGR_RND1_SIZE 8 +#define CAM_REQ_MGR_RVD_SIZE 4 +#define CAM_REQ_MGR_HDL_TYPE_SIZE 4 +#define CAM_REQ_MGR_HDL_IDX_SIZE 8 + +#define CAM_REQ_MGR_RND1_POS 24 +#define CAM_REQ_MGR_RVD_POS 16 +#define CAM_REQ_MGR_HDL_TYPE_POS 12 + +#define CAM_REQ_MGR_RND1_BYTES 1 + +#define CAM_REQ_MGR_HDL_TYPE_MASK ((1 << CAM_REQ_MGR_HDL_TYPE_SIZE) - 1) + +#define GET_DEV_HANDLE(rnd1, type, idx) \ + ((rnd1 << (CAM_REQ_MGR_RND1_POS - CAM_REQ_MGR_RND1_SIZE)) | \ + (0x0 << (CAM_REQ_MGR_RVD_POS - CAM_REQ_MGR_RVD_SIZE)) | \ + (type << (CAM_REQ_MGR_HDL_TYPE_POS - CAM_REQ_MGR_HDL_TYPE_SIZE)) | \ + (idx << (CAM_REQ_MGR_HDL_IDX_POS - CAM_REQ_MGR_HDL_IDX_SIZE))) \ + +#define CAM_REQ_MGR_GET_HDL_IDX(hdl) (hdl & CAM_REQ_MGR_HDL_IDX_MASK) +#define CAM_REQ_MGR_GET_HDL_TYPE(hdl) \ + ((hdl >> CAM_REQ_MGR_HDL_IDX_POS) & CAM_REQ_MGR_HDL_TYPE_MASK) + +#endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.c b/drivers/cam_req_mgr/cam_req_mgr_workq.c new file mode 100644 index 000000000000..29d98503f305 --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_req_mgr_workq.h" +#include "cam_debug_util.h" + +#define WORKQ_ACQUIRE_LOCK(workq, flags) {\ + if ((workq)->in_irq) \ + spin_lock_irqsave(&(workq)->lock_bh, (flags)); \ + else \ + spin_lock_bh(&(workq)->lock_bh); \ +} + +#define WORKQ_RELEASE_LOCK(workq, flags) {\ + if ((workq)->in_irq) \ + spin_unlock_irqrestore(&(workq)->lock_bh, (flags)); \ + else \ + spin_unlock_bh(&(workq)->lock_bh); \ +} + +struct crm_workq_task *cam_req_mgr_workq_get_task( + struct cam_req_mgr_core_workq *workq) +{ + struct crm_workq_task *task = NULL; + unsigned long flags = 0; + + if (!workq) + return NULL; + + WORKQ_ACQUIRE_LOCK(workq, flags); + if (list_empty(&workq->task.empty_head)) + goto end; + + task = list_first_entry(&workq->task.empty_head, + struct crm_workq_task, entry); + if (task) { + atomic_sub(1, &workq->task.free_cnt); + list_del_init(&task->entry); + } + +end: + WORKQ_RELEASE_LOCK(workq, flags); + + return task; +} + +static void cam_req_mgr_workq_put_task(struct crm_workq_task *task) +{ + struct cam_req_mgr_core_workq *workq = + (struct cam_req_mgr_core_workq *)task->parent; + unsigned long flags = 0; + + list_del_init(&task->entry); + task->cancel = 0; + task->process_cb = NULL; + task->priv = NULL; + WORKQ_ACQUIRE_LOCK(workq, flags); + list_add_tail(&task->entry, + &workq->task.empty_head); + atomic_add(1, &workq->task.free_cnt); + WORKQ_RELEASE_LOCK(workq, flags); +} + +/** + * cam_req_mgr_process_task() - Process the enqueued task + * @task: pointer to task workq thread shall process + */ +static int cam_req_mgr_process_task(struct crm_workq_task *task) +{ + struct cam_req_mgr_core_workq *workq = NULL; + + if (!task) + return -EINVAL; + + workq = (struct cam_req_mgr_core_workq *)task->parent; + if (task->process_cb) + task->process_cb(task->priv, task->payload); + else + CAM_WARN(CAM_CRM, "FATAL:no task handler registered for workq"); + cam_req_mgr_workq_put_task(task); + + return 0; +} + +/** + * cam_req_mgr_process_workq() - main loop handling + * @w: workqueue task pointer + */ +static void cam_req_mgr_process_workq(struct work_struct *w) +{ + struct cam_req_mgr_core_workq *workq = NULL; + struct crm_workq_task *task; + int32_t i = CRM_TASK_PRIORITY_0; + unsigned long flags = 0; + + if (!w) { + CAM_ERR(CAM_CRM, "NULL task pointer can not schedule"); + return; + } + workq = (struct cam_req_mgr_core_workq *) + container_of(w, struct cam_req_mgr_core_workq, work); + + while (i < CRM_TASK_PRIORITY_MAX) { + WORKQ_ACQUIRE_LOCK(workq, flags); + while (!list_empty(&workq->task.process_head[i])) { + task = list_first_entry(&workq->task.process_head[i], + struct crm_workq_task, entry); + atomic_sub(1, &workq->task.pending_cnt); + list_del_init(&task->entry); + WORKQ_RELEASE_LOCK(workq, flags); + cam_req_mgr_process_task(task); + CAM_DBG(CAM_CRM, "processed task %pK free_cnt %d", + task, atomic_read(&workq->task.free_cnt)); + WORKQ_ACQUIRE_LOCK(workq, flags); + } + WORKQ_RELEASE_LOCK(workq, flags); + i++; + } +} + +int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, + void *priv, int32_t prio) +{ + int rc = 0; + struct cam_req_mgr_core_workq *workq = NULL; + unsigned long flags = 0; + + if (!task) { + CAM_WARN(CAM_CRM, "NULL task pointer can not schedule"); + rc = -EINVAL; + goto end; + } + workq = (struct cam_req_mgr_core_workq *)task->parent; + if (!workq) { + CAM_DBG(CAM_CRM, "NULL workq pointer suspect mem corruption"); + rc = -EINVAL; + goto end; + } + + if (task->cancel == 1) { + cam_req_mgr_workq_put_task(task); + CAM_WARN(CAM_CRM, "task aborted and queued back to pool"); + rc = 0; + goto end; + } + task->priv = priv; + task->priority = + (prio < CRM_TASK_PRIORITY_MAX && prio >= CRM_TASK_PRIORITY_0) + ? prio : CRM_TASK_PRIORITY_0; + + WORKQ_ACQUIRE_LOCK(workq, flags); + if (!workq->job) { + rc = -EINVAL; + WORKQ_RELEASE_LOCK(workq, flags); + goto end; + } + + list_add_tail(&task->entry, + &workq->task.process_head[task->priority]); + + atomic_add(1, &workq->task.pending_cnt); + CAM_DBG(CAM_CRM, "enq task %pK pending_cnt %d", + task, atomic_read(&workq->task.pending_cnt)); + + queue_work(workq->job, &workq->work); + WORKQ_RELEASE_LOCK(workq, flags); +end: + return rc; +} + +int cam_req_mgr_workq_create(char *name, int32_t num_tasks, + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags) +{ + int32_t i, wq_flags = 0, max_active_tasks = 0; + struct crm_workq_task *task; + struct cam_req_mgr_core_workq *crm_workq = NULL; + char buf[128] = "crm_workq-"; + + if (!*workq) { + crm_workq = kzalloc(sizeof(struct cam_req_mgr_core_workq), + GFP_KERNEL); + if (crm_workq == NULL) + return -ENOMEM; + + wq_flags |= WQ_UNBOUND; + if (flags & CAM_WORKQ_FLAG_HIGH_PRIORITY) + wq_flags |= WQ_HIGHPRI; + + if (flags & CAM_WORKQ_FLAG_SERIAL) + max_active_tasks = 1; + + strlcat(buf, name, sizeof(buf)); + CAM_DBG(CAM_CRM, "create workque crm_workq-%s", name); + crm_workq->job = alloc_workqueue(buf, + wq_flags, max_active_tasks, NULL); + if (!crm_workq->job) { + kfree(crm_workq); + return -ENOMEM; + } + + /* Workq attributes initialization */ + INIT_WORK(&crm_workq->work, cam_req_mgr_process_workq); + spin_lock_init(&crm_workq->lock_bh); + CAM_DBG(CAM_CRM, "LOCK_DBG workq %s lock %pK", + name, &crm_workq->lock_bh); + + /* Task attributes initialization */ + atomic_set(&crm_workq->task.pending_cnt, 0); + atomic_set(&crm_workq->task.free_cnt, 0); + for (i = CRM_TASK_PRIORITY_0; i < CRM_TASK_PRIORITY_MAX; i++) + INIT_LIST_HEAD(&crm_workq->task.process_head[i]); + INIT_LIST_HEAD(&crm_workq->task.empty_head); + crm_workq->in_irq = in_irq; + crm_workq->task.num_task = num_tasks; + crm_workq->task.pool = kcalloc(crm_workq->task.num_task, + sizeof(struct crm_workq_task), GFP_KERNEL); + if (!crm_workq->task.pool) { + CAM_WARN(CAM_CRM, "Insufficient memory %zu", + sizeof(struct crm_workq_task) * + crm_workq->task.num_task); + kfree(crm_workq); + return -ENOMEM; + } + + for (i = 0; i < crm_workq->task.num_task; i++) { + task = &crm_workq->task.pool[i]; + task->parent = (void *)crm_workq; + /* Put all tasks in free pool */ + INIT_LIST_HEAD(&task->entry); + cam_req_mgr_workq_put_task(task); + } + *workq = crm_workq; + CAM_DBG(CAM_CRM, "free tasks %d", + atomic_read(&crm_workq->task.free_cnt)); + } + + return 0; +} + +void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq) +{ + unsigned long flags = 0; + struct workqueue_struct *job; + + CAM_DBG(CAM_CRM, "destroy workque %pK", crm_workq); + if (*crm_workq) { + WORKQ_ACQUIRE_LOCK(*crm_workq, flags); + if ((*crm_workq)->job) { + job = (*crm_workq)->job; + (*crm_workq)->job = NULL; + WORKQ_RELEASE_LOCK(*crm_workq, flags); + destroy_workqueue(job); + } else { + WORKQ_RELEASE_LOCK(*crm_workq, flags); + } + + /* Destroy workq payload data */ + kfree((*crm_workq)->task.pool[0].payload); + (*crm_workq)->task.pool[0].payload = NULL; + kfree((*crm_workq)->task.pool); + kfree(*crm_workq); + *crm_workq = NULL; + } +} diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.h b/drivers/cam_req_mgr/cam_req_mgr_workq.h new file mode 100644 index 000000000000..f938710b69ae --- /dev/null +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_WORKQ_H_ +#define _CAM_REQ_MGR_WORKQ_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_req_mgr_core.h" + +/* Flag to create a high priority workq */ +#define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0) + +/* + * This flag ensures only one task from a given + * workq will execute at any given point on any + * given CPU. + */ +#define CAM_WORKQ_FLAG_SERIAL (1 << 1) + +/* Task priorities, lower the number higher the priority*/ +enum crm_task_priority { + CRM_TASK_PRIORITY_0, + CRM_TASK_PRIORITY_1, + CRM_TASK_PRIORITY_MAX, +}; + +/* workqueue will be used from irq context or not */ +enum crm_workq_context { + CRM_WORKQ_USAGE_NON_IRQ, + CRM_WORKQ_USAGE_IRQ, + CRM_WORKQ_USAGE_INVALID, +}; + +/** struct crm_workq_task + * @priority : caller can assign priority to task based on type. + * @payload : depending of user of task this payload type will change + * @process_cb : registered callback called by workq when task enqueued is + * ready for processing in workq thread context + * @parent : workq's parent is link which is enqqueing taks to this workq + * @entry : list head of this list entry is worker's empty_head + * @cancel : if caller has got free task from pool but wants to abort + * or put back without using it + * @priv : when task is enqueuer caller can attach priv along which + * it will get in process callback + * @ret : return value in future to use for blocking calls + */ +struct crm_workq_task { + int32_t priority; + void *payload; + int32_t (*process_cb)(void *priv, void *data); + void *parent; + struct list_head entry; + uint8_t cancel; + void *priv; + int32_t ret; +}; + +/** struct cam_req_mgr_core_workq + * @work : work token used by workqueue + * @job : workqueue internal job struct + * task - + * @lock_bh : lock for task structs + * @in_irq : set true if workque can be used in irq context + * @free_cnt : num of free/available tasks + * @empty_head : list head of available taska which can be used + * or acquired in order to enqueue a task to workq + * @pool : pool of tasks used for handling events in workq context + * @num_task : size of tasks pool + * - + */ +struct cam_req_mgr_core_workq { + struct work_struct work; + struct workqueue_struct *job; + spinlock_t lock_bh; + uint32_t in_irq; + + /* tasks */ + struct { + struct mutex lock; + atomic_t pending_cnt; + atomic_t free_cnt; + + struct list_head process_head[CRM_TASK_PRIORITY_MAX]; + struct list_head empty_head; + struct crm_workq_task *pool; + uint32_t num_task; + } task; +}; + +/** + * cam_req_mgr_workq_create() + * @brief : create a workqueue + * @name : Name of the workque to be allocated, it is combination + * of session handle and link handle + * @num_task : Num_tasks to be allocated for workq + * @workq : Double pointer worker + * @in_irq : Set to one if workq might be used in irq context + * @flags : Bitwise OR of Flags for workq behavior. + * e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL + * This function will allocate and create workqueue and pass + * the workq pointer to caller. + */ +int cam_req_mgr_workq_create(char *name, int32_t num_tasks, + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags); + +/** + * cam_req_mgr_workq_destroy() + * @brief: destroy workqueue + * @workq: pointer to worker data struct + * this function will destroy workqueue and clean up resources + * associated with worker such as tasks. + */ +void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **workq); + +/** + * cam_req_mgr_workq_enqueue_task() + * @brief: Enqueue task in worker queue + * @task : task to be processed by worker + * @priv : clients private data + * @prio : task priority + * process callback func + */ +int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, + void *priv, int32_t prio); + +/** + * cam_req_mgr_workq_get_task() + * @brief: Returns empty task pointer for use + * @workq: workque used for processing + */ +struct crm_workq_task *cam_req_mgr_workq_get_task( + struct cam_req_mgr_core_workq *workq); + +#endif diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h new file mode 100644 index 000000000000..385643d5e532 --- /dev/null +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SUBDEV_H_ +#define _CAM_SUBDEV_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define CAM_SUBDEVICE_EVENT_MAX 30 + +/** + * struct cam_subdev - describes a camera sub-device + * + * @pdev: Pointer to the platform device + * @sd: V4l2 subdevice + * @ops: V4l2 subdecie operations + * @internal_ops: V4l2 subdevice internal operations + * @name: Name of the sub-device. Please notice that the name + * must be unique. + * @sd_flags: Subdev flags. Can be: + * %V4L2_SUBDEV_FL_HAS_DEVNODE - Set this flag if + * this subdev needs a device node. + * %V4L2_SUBDEV_FL_HAS_EVENTS - Set this flag if + * this subdev generates events. + * @token: Pointer to cookie of the client driver + * @ent_function: Media entity function type. Can be: + * %CAM_IFE_DEVICE_TYPE - identifies as IFE device. + * %CAM_ICP_DEVICE_TYPE - identifies as ICP device. + * + * Each instance of a subdev driver should create this struct, either + * stand-alone or embedded in a larger struct. This structure should be + * initialized/registered by cam_register_subdev + * + */ +struct cam_subdev { + struct platform_device *pdev; + struct v4l2_subdev sd; + const struct v4l2_subdev_ops *ops; + const struct v4l2_subdev_internal_ops *internal_ops; + char *name; + u32 sd_flags; + void *token; + u32 ent_function; +}; + +/** + * cam_subdev_probe() + * + * @brief: Camera Subdevice node probe function for v4l2 setup + * + * @sd: Camera subdevice object + * @name: Name of the subdevice node + * @dev_type: Subdevice node type + * + */ +int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev, + char *name, uint32_t dev_type); + +/** + * cam_subdev_remove() + * + * @brief: Called when subdevice node is unloaded + * + * @sd: Camera subdevice node object + * + */ +int cam_subdev_remove(struct cam_subdev *sd); + +/** + * cam_register_subdev_fops() + * + * @brief: This common utility function assigns subdev ops + * + * @fops: v4l file operations + */ +void cam_register_subdev_fops(struct v4l2_file_operations *fops); + +/** + * cam_register_subdev() + * + * @brief: This is the common utility function to be called by each camera + * subdevice node when it tries to register itself to the camera + * request manager + * + * @sd: Pointer to struct cam_subdev. + */ +int cam_register_subdev(struct cam_subdev *sd); + +/** + * cam_unregister_subdev() + * + * @brief: This is the common utility function to be called by each camera + * subdevice node when it tries to unregister itself from the + * camera request manger + * + * @sd: Pointer to struct cam_subdev. + */ +int cam_unregister_subdev(struct cam_subdev *sd); + +#endif /* _CAM_SUBDEV_H_ */ diff --git a/drivers/cam_sensor_module/Makefile b/drivers/cam_sensor_module/Makefile new file mode 100644 index 000000000000..6925b3aba80f --- /dev/null +++ b/drivers/cam_sensor_module/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_res_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_utils/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/ diff --git a/drivers/cam_sensor_module/cam_actuator/Makefile b/drivers/cam_sensor_module/cam_actuator/Makefile new file mode 100644 index 000000000000..a51b8fea65bb --- /dev/null +++ b/drivers/cam_sensor_module/cam_actuator/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator_dev.o cam_actuator_core.o cam_actuator_soc.o diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c new file mode 100644 index 000000000000..c609b8f85015 --- /dev/null +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -0,0 +1,981 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_actuator_core.h" +#include "cam_sensor_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +int32_t cam_actuator_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0; + + power_info->power_setting_size = 1; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_setting[0].seq_type = SENSOR_VAF; + power_info->power_setting[0].seq_val = CAM_VAF; + power_info->power_setting[0].config_val = 1; + power_info->power_setting[0].delay = 2; + + power_info->power_down_setting_size = 1; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + + power_info->power_down_setting[0].seq_type = SENSOR_VAF; + power_info->power_down_setting[0].seq_val = CAM_VAF; + power_info->power_down_setting[0].config_val = 0; + + return rc; + +free_power_settings: + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return rc; +} + +static int32_t cam_actuator_power_up(struct cam_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = + &a_ctrl->soc_info; + struct cam_actuator_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + if ((power_info->power_setting == NULL) && + (power_info->power_down_setting == NULL)) { + CAM_INFO(CAM_ACTUATOR, + "Using default power settings"); + rc = cam_actuator_construct_default_power_setting(power_info); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Construct default actuator power setting failed."); + return rc; + } + } + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params( + &a_ctrl->soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "failed to fill vreg params for power up rc:%d", rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + &a_ctrl->soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "failed to fill vreg params power down rc:%d", rc); + return rc; + } + + power_info->dev = soc_info->dev; + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "failed in actuator power up rc %d", rc); + return rc; + } + + rc = camera_io_init(&a_ctrl->io_master_info); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "cci init failed: rc: %d", rc); + + return rc; +} + +static int32_t cam_actuator_power_down(struct cam_actuator_ctrl_t *a_ctrl) +{ + int32_t rc = 0; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info = &a_ctrl->soc_info; + struct cam_actuator_soc_private *soc_private; + + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "failed: a_ctrl %pK", a_ctrl); + return -EINVAL; + } + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + soc_info = &a_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_ACTUATOR, "failed: power_info %pK", power_info); + return -EINVAL; + } + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_ACTUATOR, "power down the core is failed:%d", rc); + return rc; + } + + camera_io_release(&a_ctrl->io_master_info); + + return rc; +} + +static int32_t cam_actuator_i2c_modes_util( + struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list) +{ + int32_t rc = 0; + uint32_t i, size; + + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { + rc = camera_io_dev_write(io_master_info, + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to random write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 0); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to seq write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_BURST) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to burst write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + io_master_info, + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "i2c poll apply setting Fail: %d", rc); + return rc; + } + } + } + + return rc; +} + +int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl, + uint32_t *cmd_buf, size_t len) +{ + int32_t rc = 0; + struct cam_cmd_i2c_info *i2c_info; + + if (!a_ctrl || !cmd_buf || (len < sizeof(struct cam_cmd_i2c_info))) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if (a_ctrl->io_master_info.master_type == CCI_MASTER) { + a_ctrl->io_master_info.cci_client->cci_i2c_master = + a_ctrl->cci_i2c_master; + a_ctrl->io_master_info.cci_client->i2c_freq_mode = + i2c_info->i2c_freq_mode; + a_ctrl->io_master_info.cci_client->sid = + i2c_info->slave_addr >> 1; + CAM_DBG(CAM_ACTUATOR, "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, i2c_info->i2c_freq_mode); + } else if (a_ctrl->io_master_info.master_type == I2C_MASTER) { + a_ctrl->io_master_info.client->addr = i2c_info->slave_addr; + CAM_DBG(CAM_ACTUATOR, "Slave addr: 0x%x", i2c_info->slave_addr); + } else { + CAM_ERR(CAM_ACTUATOR, "Invalid Master type: %d", + a_ctrl->io_master_info.master_type); + rc = -EINVAL; + } + + return rc; +} + +int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl, + struct i2c_settings_array *i2c_set) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0; + + if (a_ctrl == NULL || i2c_set == NULL) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + if (i2c_set->is_settings_valid != 1) { + CAM_ERR(CAM_ACTUATOR, " Invalid settings"); + return -EINVAL; + } + + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_actuator_i2c_modes_util( + &(a_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to apply settings: %d", + rc); + } else { + CAM_DBG(CAM_ACTUATOR, + "Success:request ID: %d", + i2c_set->request_id); + } + } + + return rc; +} + +int32_t cam_actuator_apply_request(struct cam_req_mgr_apply_request *apply) +{ + int32_t rc = 0, request_id, del_req_id; + struct cam_actuator_ctrl_t *a_ctrl = NULL; + + if (!apply) { + CAM_ERR(CAM_ACTUATOR, "Invalid Input Args"); + return -EINVAL; + } + + a_ctrl = (struct cam_actuator_ctrl_t *) + cam_get_device_priv(apply->dev_hdl); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Device data is NULL"); + return -EINVAL; + } + request_id = apply->request_id % MAX_PER_FRAME_ARRAY; + + trace_cam_apply_req("Actuator", apply->request_id); + + CAM_DBG(CAM_ACTUATOR, "Request Id: %lld", apply->request_id); + mutex_lock(&(a_ctrl->actuator_mutex)); + if ((apply->request_id == + a_ctrl->i2c_data.per_frame[request_id].request_id) && + (a_ctrl->i2c_data.per_frame[request_id].is_settings_valid) + == 1) { + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.per_frame[request_id]); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed in applying the request: %lld\n", + apply->request_id); + goto release_mutex; + } + } + del_req_id = (request_id + + MAX_PER_FRAME_ARRAY - MAX_SYSTEM_PIPELINE_DELAY) % + MAX_PER_FRAME_ARRAY; + + if (apply->request_id > + a_ctrl->i2c_data.per_frame[del_req_id].request_id) { + a_ctrl->i2c_data.per_frame[del_req_id].request_id = 0; + rc = delete_request(&a_ctrl->i2c_data.per_frame[del_req_id]); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Fail deleting the req: %d err: %d\n", + del_req_id, rc); + goto release_mutex; + } + } else { + CAM_DBG(CAM_ACTUATOR, "No Valid Req to clean Up"); + } + +release_mutex: + mutex_unlock(&(a_ctrl->actuator_mutex)); + return rc; +} + +int32_t cam_actuator_establish_link( + struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_actuator_ctrl_t *a_ctrl = NULL; + + if (!link) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + a_ctrl = (struct cam_actuator_ctrl_t *) + cam_get_device_priv(link->dev_hdl); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + if (link->link_enable) { + a_ctrl->bridge_intf.link_hdl = link->link_hdl; + a_ctrl->bridge_intf.crm_cb = link->crm_cb; + } else { + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.crm_cb = NULL; + } + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return 0; +} + +static void cam_actuator_update_req_mgr( + struct cam_actuator_ctrl_t *a_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_req_mgr_add_request add_req; + + add_req.link_hdl = a_ctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl; + add_req.skip_before_applying = 0; + + if (a_ctrl->bridge_intf.crm_cb && + a_ctrl->bridge_intf.crm_cb->add_req) { + a_ctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_ACTUATOR, "Request Id: %lld added to CRM", + add_req.req_id); + } else { + CAM_ERR(CAM_ACTUATOR, "Can't add Request ID: %lld to CRM", + csl_packet->header.request_id); + } +} + +int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info) +{ + if (!info) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + info->dev_id = CAM_REQ_MGR_DEVICE_ACTUATOR; + strlcpy(info->name, CAM_ACTUATOR_NAME, sizeof(info->name)); + info->p_delay = 1; + info->trigger = CAM_TRIGGER_POINT_SOF; + + return 0; +} + +int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, + void *arg) +{ + int32_t rc = 0; + int32_t i = 0; + uint32_t total_cmd_buf_in_bytes = 0; + size_t len_of_buff = 0; + size_t remain_len = 0; + uint32_t *offset = NULL; + uint32_t *cmd_buf = NULL; + uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; + struct common_header *cmm_hdr = NULL; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_config_dev_cmd config; + struct i2c_data_settings *i2c_data = NULL; + struct i2c_settings_array *i2c_reg_settings = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_actuator_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + + if (!a_ctrl || !arg) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + + power_info = &soc_private->power_info; + + ioctl_ctrl = (struct cam_control *)arg; + if (copy_from_user(&config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) + return -EFAULT; + rc = cam_mem_get_cpu_buf(config.packet_handle, + &generic_pkt_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Error in converting command Handle %d", + rc); + return rc; + } + + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_ACTUATOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto end; + } + + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_ACTUATOR, "Invalid packet params"); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_ACTUATOR_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= a_ctrl->last_flush_req + && a_ctrl->last_flush_req != 0) { + CAM_DBG(CAM_ACTUATOR, + "reject request %lld, last request to flush %lld", + csl_packet->header.request_id, a_ctrl->last_flush_req); + rc = -EINVAL; + goto end; + } + + if (csl_packet->header.request_id > a_ctrl->last_flush_req) + a_ctrl->last_flush_req = 0; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_ACTUATOR_PACKET_OPCODE_INIT: + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + if (!total_cmd_buf_in_bytes) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf"); + goto end; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_ACTUATOR, "invalid cmd buf"); + rc = -EINVAL; + goto end; + } + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_ACTUATOR, + "Invalid length for sensor cmd"); + rc = -EINVAL; + goto end; + } + remain_len = len_of_buff - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + cmm_hdr = (struct common_header *)cmd_buf; + + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + CAM_DBG(CAM_ACTUATOR, + "Received slave info buffer"); + rc = cam_actuator_slaveInfo_pkt_parser( + a_ctrl, cmd_buf, remain_len); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to parse slave info: %d", rc); + goto end; + } + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + CAM_DBG(CAM_ACTUATOR, + "Received power settings buffer"); + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + power_info, remain_len); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "Failed:parse power settings: %d", + rc); + goto end; + } + break; + default: + CAM_DBG(CAM_ACTUATOR, + "Received initSettings buffer"); + i2c_data = &(a_ctrl->i2c_data); + i2c_reg_settings = + &i2c_data->init_settings; + + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + rc = cam_sensor_i2c_command_parser( + &a_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed:parse init settings: %d", + rc); + goto end; + } + break; + } + } + + if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE) { + rc = cam_actuator_power_up(a_ctrl); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + " Actuator Power up failed"); + goto end; + } + a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG; + } + + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Cannot apply Init settings"); + goto end; + } + + /* Delete the request even if the apply is failed */ + rc = delete_request(&a_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_WARN(CAM_ACTUATOR, + "Fail in deleting the Init settings"); + rc = 0; + } + break; + case CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to move lens: %d", + a_ctrl->cam_act_state); + goto end; + } + a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_NOW; + + i2c_data = &(a_ctrl->i2c_data); + i2c_reg_settings = &i2c_data->init_settings; + + i2c_data->init_settings.request_id = + csl_packet->header.request_id; + i2c_reg_settings->is_settings_valid = 1; + offset = (uint32_t *)&csl_packet->payload; + offset += csl_packet->cmd_buf_offset / sizeof(uint32_t); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &a_ctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Auto move lens parsing failed: %d", rc); + goto end; + } + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; + case CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to move lens: %d", + a_ctrl->cam_act_state); + goto end; + } + + a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_LATER; + i2c_data = &(a_ctrl->i2c_data); + i2c_reg_settings = &i2c_data->per_frame[ + csl_packet->header.request_id % MAX_PER_FRAME_ARRAY]; + + i2c_reg_settings->request_id = + csl_packet->header.request_id; + i2c_reg_settings->is_settings_valid = 1; + offset = (uint32_t *)&csl_packet->payload; + offset += csl_packet->cmd_buf_offset / sizeof(uint32_t); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &a_ctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Manual move lens parsing failed: %d", rc); + goto end; + } + + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; + case CAM_PKT_NOP_OPCODE: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + CAM_WARN(CAM_ACTUATOR, + "Received NOP packets in invalid state: %d", + a_ctrl->cam_act_state); + rc = -EINVAL; + goto end; + } + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; + default: + CAM_ERR(CAM_ACTUATOR, "Wrong Opcode: %d", + csl_packet->header.op_code & 0xFFFFFF); + rc = -EINVAL; + goto end; + } + +end: + return rc; +} + +void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + struct cam_actuator_soc_private *soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = + &soc_private->power_info; + + if (a_ctrl->cam_act_state == CAM_ACTUATOR_INIT) + return; + + if (a_ctrl->cam_act_state >= CAM_ACTUATOR_CONFIG) { + rc = cam_actuator_power_down(a_ctrl); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "Actuator Power down failed"); + a_ctrl->cam_act_state = CAM_ACTUATOR_ACQUIRE; + } + + if (a_ctrl->cam_act_state >= CAM_ACTUATOR_ACQUIRE) { + rc = cam_destroy_device_hdl(a_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "destroying dhdl failed"); + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.session_hdl = -1; + } + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; +} + +int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, + void *arg) +{ + int rc = 0; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_actuator_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + + if (!a_ctrl || !cmd) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + + power_info = &soc_private->power_info; + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_ACTUATOR, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + CAM_DBG(CAM_ACTUATOR, "Opcode to Actuator: %d", cmd->op_code); + + mutex_lock(&(a_ctrl->actuator_mutex)); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev actuator_acq_dev; + struct cam_create_dev_hdl bridge_params; + + if (a_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_ACTUATOR, "Device is already acquired"); + rc = -EINVAL; + goto release_mutex; + } + rc = copy_from_user(&actuator_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(actuator_acq_dev)); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed Copying from user\n"); + goto release_mutex; + } + + bridge_params.session_hdl = actuator_acq_dev.session_handle; + bridge_params.ops = &a_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = a_ctrl; + + actuator_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle; + a_ctrl->bridge_intf.session_hdl = + actuator_acq_dev.session_handle; + + CAM_DBG(CAM_ACTUATOR, "Device Handle: %d", + actuator_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &actuator_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_ACTUATOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + + a_ctrl->cam_act_state = CAM_ACTUATOR_ACQUIRE; + } + break; + case CAM_RELEASE_DEV: { + if (a_ctrl->cam_act_state == CAM_ACTUATOR_START) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Cant release actuator: in start state"); + goto release_mutex; + } + + if (a_ctrl->cam_act_state == CAM_ACTUATOR_CONFIG) { + rc = cam_actuator_power_down(a_ctrl); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Actuator Power down failed"); + goto release_mutex; + } + } + + if (a_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_ACTUATOR, "link hdl: %d device hdl: %d", + a_ctrl->bridge_intf.device_hdl, + a_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + + if (a_ctrl->bridge_intf.link_hdl != -1) { + CAM_ERR(CAM_ACTUATOR, + "Device [%d] still active on link 0x%x", + a_ctrl->cam_act_state, + a_ctrl->bridge_intf.link_hdl); + rc = -EAGAIN; + goto release_mutex; + } + + rc = cam_destroy_device_hdl(a_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "destroying the device hdl"); + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.session_hdl = -1; + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + a_ctrl->last_flush_req = 0; + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + } + break; + case CAM_QUERY_CAP: { + struct cam_actuator_query_cap actuator_cap = {0}; + + actuator_cap.slot_info = a_ctrl->soc_info.index; + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &actuator_cap, + sizeof(struct cam_actuator_query_cap))) { + CAM_ERR(CAM_ACTUATOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + } + break; + case CAM_START_DEV: { + if (a_ctrl->cam_act_state != CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to start : %d", + a_ctrl->cam_act_state); + goto release_mutex; + } + a_ctrl->cam_act_state = CAM_ACTUATOR_START; + a_ctrl->last_flush_req = 0; + } + break; + case CAM_STOP_DEV: { + struct i2c_settings_array *i2c_set = NULL; + int i; + + if (a_ctrl->cam_act_state != CAM_ACTUATOR_START) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to stop : %d", + a_ctrl->cam_act_state); + goto release_mutex; + } + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(a_ctrl->i2c_data.per_frame[i]); + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + } + } + a_ctrl->last_flush_req = 0; + a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG; + } + break; + case CAM_CONFIG_DEV: { + a_ctrl->setting_apply_state = + ACT_APPLY_SETTINGS_LATER; + rc = cam_actuator_i2c_pkt_parse(a_ctrl, arg); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed in actuator Parsing"); + goto release_mutex; + } + + if (a_ctrl->setting_apply_state == + ACT_APPLY_SETTINGS_NOW) { + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, + "Cannot apply Update settings"); + + /* Delete the request even if the apply is failed */ + rc = delete_request(&a_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed in Deleting the Init Pkt: %d", + rc); + goto release_mutex; + } + } + } + break; + default: + CAM_ERR(CAM_ACTUATOR, "Invalid Opcode %d", cmd->op_code); + } + +release_mutex: + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return rc; +} + +int32_t cam_actuator_flush_request(struct cam_req_mgr_flush_request *flush_req) +{ + int32_t rc = 0, i; + uint32_t cancel_req_id_found = 0; + struct cam_actuator_ctrl_t *a_ctrl = NULL; + struct i2c_settings_array *i2c_set = NULL; + + if (!flush_req) + return -EINVAL; + + a_ctrl = (struct cam_actuator_ctrl_t *) + cam_get_device_priv(flush_req->dev_hdl); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Device data is NULL"); + return -EINVAL; + } + + if (a_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_ACTUATOR, "i2c frame data is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + a_ctrl->last_flush_req = flush_req->req_id; + CAM_DBG(CAM_ACTUATOR, "last reqest to flush is %lld", + flush_req->req_id); + } + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(a_ctrl->i2c_data.per_frame[i]); + + if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) + && (i2c_set->request_id != flush_req->req_id)) + continue; + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + + if (flush_req->type == + CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + cancel_req_id_found = 1; + break; + } + } + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_ACTUATOR, + "Flush request id:%lld not found in the pending list", + flush_req->req_id); + mutex_unlock(&(a_ctrl->actuator_mutex)); + return rc; +} diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.h b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.h new file mode 100644 index 000000000000..e5636f26ce36 --- /dev/null +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ACTUATOR_CORE_H_ +#define _CAM_ACTUATOR_CORE_H_ + +#include "cam_actuator_dev.h" + +/** + * @power_info: power setting info to control the power + * + * This API construct the default actuator power setting. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int32_t cam_actuator_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info); + +/** + * @apply: Req mgr structure for applying request + * + * This API applies the request that is mentioned + */ +int32_t cam_actuator_apply_request(struct cam_req_mgr_apply_request *apply); + +/** + * @info: Sub device info to req mgr + * + * This API publish the subdevice info to req mgr + */ +int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info); + +/** + * @flush: Req mgr structure for flushing request + * + * This API flushes the request that is mentioned + */ +int cam_actuator_flush_request(struct cam_req_mgr_flush_request *flush); + + +/** + * @link: Link setup info + * + * This API establishes link actuator subdevice with req mgr + */ +int32_t cam_actuator_establish_link( + struct cam_req_mgr_core_dev_link_setup *link); + +/** + * @a_ctrl: Actuator ctrl structure + * @arg: Camera control command argument + * + * This API handles the camera control argument reached to actuator + */ +int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, void *arg); + +/** + * @a_ctrl: Actuator ctrl structure + * + * This API handles the shutdown ioctl/close + */ +void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl); + +#endif /* _CAM_ACTUATOR_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c new file mode 100644 index 000000000000..46bd99fc9e29 --- /dev/null +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_actuator_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_actuator_soc.h" +#include "cam_actuator_core.h" +#include "cam_trace.h" + +static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_actuator_ctrl_t *a_ctrl = + v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_actuator_driver_cmd(a_ctrl, arg); + break; + default: + CAM_ERR(CAM_ACTUATOR, "Invalid ioctl cmd"); + rc = -EINVAL; + break; + } + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_actuator_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_ACTUATOR, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + cmd = VIDIOC_CAM_CONTROL; + rc = cam_actuator_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "Failed in actuator subdev handling rc: %d", + rc); + return rc; + } + break; + default: + CAM_ERR(CAM_ACTUATOR, "Invalid compat ioctl: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_ACTUATOR, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + return rc; +} +#endif + +static int cam_actuator_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_actuator_ctrl_t *a_ctrl = + v4l2_get_subdevdata(sd); + + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "a_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return 0; +} + +static struct v4l2_subdev_core_ops cam_actuator_subdev_core_ops = { + .ioctl = cam_actuator_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_actuator_init_subdev_do_ioctl, +#endif +}; + +static struct v4l2_subdev_ops cam_actuator_subdev_ops = { + .core = &cam_actuator_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_actuator_internal_ops = { + .close = cam_actuator_subdev_close, +}; + +static int cam_actuator_init_subdev(struct cam_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + + a_ctrl->v4l2_dev_str.internal_ops = + &cam_actuator_internal_ops; + a_ctrl->v4l2_dev_str.ops = + &cam_actuator_subdev_ops; + strlcpy(a_ctrl->device_name, CAMX_ACTUATOR_DEV_NAME, + sizeof(a_ctrl->device_name)); + a_ctrl->v4l2_dev_str.name = + a_ctrl->device_name; + a_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + a_ctrl->v4l2_dev_str.ent_function = + CAM_ACTUATOR_DEVICE_TYPE; + a_ctrl->v4l2_dev_str.token = a_ctrl; + + rc = cam_register_subdev(&(a_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev rc: %d", rc); + + return rc; +} + +static int32_t cam_actuator_driver_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0; + int32_t i = 0; + struct cam_actuator_ctrl_t *a_ctrl; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_actuator_soc_private *soc_private = NULL; + + if (client == NULL || id == NULL) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args client: %pK id: %pK", + client, id); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_ACTUATOR, "%s :: i2c_check_functionality failed", + client->name); + rc = -EFAULT; + return rc; + } + + /* Create sensor control structure */ + a_ctrl = kzalloc(sizeof(*a_ctrl), GFP_KERNEL); + if (!a_ctrl) + return -ENOMEM; + + i2c_set_clientdata(client, a_ctrl); + + soc_private = kzalloc(sizeof(struct cam_actuator_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_ctrl; + } + a_ctrl->soc_info.soc_private = soc_private; + + a_ctrl->io_master_info.client = client; + soc_info = &a_ctrl->soc_info; + soc_info->dev = &client->dev; + soc_info->dev_name = client->name; + a_ctrl->io_master_info.master_type = I2C_MASTER; + + rc = cam_actuator_parse_dt(a_ctrl, &client->dev); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "failed: cam_sensor_parse_dt rc %d", rc); + goto free_soc; + } + + rc = cam_actuator_init_subdev(a_ctrl); + if (rc) + goto free_soc; + + if (soc_private->i2c_info.slave_addr != 0) + a_ctrl->io_master_info.client->addr = + soc_private->i2c_info.slave_addr; + + a_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (a_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(a_ctrl->i2c_data.per_frame[i].list_head)); + + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.ops.get_dev_info = + cam_actuator_publish_dev_info; + a_ctrl->bridge_intf.ops.link_setup = + cam_actuator_establish_link; + a_ctrl->bridge_intf.ops.apply_req = + cam_actuator_apply_request; + a_ctrl->last_flush_req = 0; + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + + return rc; + +unreg_subdev: + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); +free_soc: + kfree(soc_private); +free_ctrl: + kfree(a_ctrl); + return rc; +} + +static int32_t cam_actuator_platform_remove(struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_actuator_ctrl_t *a_ctrl; + struct cam_actuator_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + a_ctrl = platform_get_drvdata(pdev); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Actuator device is NULL"); + return 0; + } + + CAM_INFO(CAM_ACTUATOR, "platform remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + kfree(a_ctrl->io_master_info.cci_client); + a_ctrl->io_master_info.cci_client = NULL; + kfree(a_ctrl->soc_info.soc_private); + a_ctrl->soc_info.soc_private = NULL; + kfree(a_ctrl->i2c_data.per_frame); + a_ctrl->i2c_data.per_frame = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, a_ctrl); + + return rc; +} + +static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) +{ + struct cam_actuator_ctrl_t *a_ctrl = + i2c_get_clientdata(client); + struct cam_actuator_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + /* Handle I2C Devices */ + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Actuator device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_ACTUATOR, "i2c remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + /*Free Allocated Mem */ + kfree(a_ctrl->i2c_data.per_frame); + a_ctrl->i2c_data.per_frame = NULL; + a_ctrl->soc_info.soc_private = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); + kfree(a_ctrl); + + return 0; +} + +static const struct of_device_id cam_actuator_driver_dt_match[] = { + {.compatible = "qcom,actuator"}, + {} +}; + +static int32_t cam_actuator_driver_platform_probe( + struct platform_device *pdev) +{ + int32_t rc = 0; + int32_t i = 0; + struct cam_actuator_ctrl_t *a_ctrl = NULL; + struct cam_actuator_soc_private *soc_private = NULL; + + /* Create actuator control structure */ + a_ctrl = devm_kzalloc(&pdev->dev, + sizeof(struct cam_actuator_ctrl_t), GFP_KERNEL); + if (!a_ctrl) + return -ENOMEM; + + /*fill in platform device*/ + a_ctrl->v4l2_dev_str.pdev = pdev; + a_ctrl->soc_info.pdev = pdev; + a_ctrl->soc_info.dev = &pdev->dev; + a_ctrl->soc_info.dev_name = pdev->name; + a_ctrl->io_master_info.master_type = CCI_MASTER; + + a_ctrl->io_master_info.cci_client = kzalloc(sizeof( + struct cam_sensor_cci_client), GFP_KERNEL); + if (!(a_ctrl->io_master_info.cci_client)) { + rc = -ENOMEM; + goto free_ctrl; + } + + soc_private = kzalloc(sizeof(struct cam_actuator_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_cci_client; + } + a_ctrl->soc_info.soc_private = soc_private; + soc_private->power_info.dev = &pdev->dev; + + a_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (a_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto free_soc; + } + + INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(a_ctrl->i2c_data.per_frame[i].list_head)); + + rc = cam_actuator_parse_dt(a_ctrl, &(pdev->dev)); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Paring actuator dt failed rc %d", rc); + goto free_mem; + } + + /* Fill platform device id*/ + pdev->id = a_ctrl->soc_info.index; + + rc = cam_actuator_init_subdev(a_ctrl); + if (rc) + goto free_mem; + + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.ops.get_dev_info = + cam_actuator_publish_dev_info; + a_ctrl->bridge_intf.ops.link_setup = + cam_actuator_establish_link; + a_ctrl->bridge_intf.ops.apply_req = + cam_actuator_apply_request; + a_ctrl->bridge_intf.ops.flush_req = + cam_actuator_flush_request; + a_ctrl->last_flush_req = 0; + + platform_set_drvdata(pdev, a_ctrl); + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + + return rc; + +free_mem: + kfree(a_ctrl->i2c_data.per_frame); +free_soc: + kfree(soc_private); +free_cci_client: + kfree(a_ctrl->io_master_info.cci_client); +free_ctrl: + devm_kfree(&pdev->dev, a_ctrl); + return rc; +} + +MODULE_DEVICE_TABLE(of, cam_actuator_driver_dt_match); + +static struct platform_driver cam_actuator_platform_driver = { + .probe = cam_actuator_driver_platform_probe, + .driver = { + .name = "qcom,actuator", + .owner = THIS_MODULE, + .of_match_table = cam_actuator_driver_dt_match, + .suppress_bind_attrs = true, + }, + .remove = cam_actuator_platform_remove, +}; + +static const struct i2c_device_id i2c_id[] = { + {ACTUATOR_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_actuator_driver_i2c = { + .id_table = i2c_id, + .probe = cam_actuator_driver_i2c_probe, + .remove = cam_actuator_driver_i2c_remove, + .driver = { + .name = ACTUATOR_DRIVER_I2C, + }, +}; + +static int __init cam_actuator_driver_init(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_actuator_platform_driver); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "platform_driver_register failed rc = %d", rc); + return rc; + } + rc = i2c_add_driver(&cam_actuator_driver_i2c); + if (rc) + CAM_ERR(CAM_ACTUATOR, "i2c_add_driver failed rc = %d", rc); + + return rc; +} + +static void __exit cam_actuator_driver_exit(void) +{ + platform_driver_unregister(&cam_actuator_platform_driver); + i2c_del_driver(&cam_actuator_driver_i2c); +} + +module_init(cam_actuator_driver_init); +module_exit(cam_actuator_driver_exit); +MODULE_DESCRIPTION("cam_actuator_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h new file mode 100644 index 000000000000..9c704c0cd48e --- /dev/null +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_ACTUATOR_DEV_H_ +#define _CAM_ACTUATOR_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_sensor_util.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#define ACTUATOR_DRIVER_I2C "i2c_actuator" +#define CAMX_ACTUATOR_DEV_NAME "cam-actuator-driver" + +#define MSM_ACTUATOR_MAX_VREGS (10) +#define ACTUATOR_MAX_POLL_COUNT 10 + + +enum cam_actuator_apply_state_t { + ACT_APPLY_SETTINGS_NOW, + ACT_APPLY_SETTINGS_LATER, +}; + +enum cam_actuator_state { + CAM_ACTUATOR_INIT, + CAM_ACTUATOR_ACQUIRE, + CAM_ACTUATOR_CONFIG, + CAM_ACTUATOR_START, +}; + +/** + * struct cam_actuator_i2c_info_t - I2C info + * @slave_addr : slave address + * @i2c_freq_mode : i2c frequency mode + */ +struct cam_actuator_i2c_info_t { + uint16_t slave_addr; + uint8_t i2c_freq_mode; +}; + +struct cam_actuator_soc_private { + struct cam_actuator_i2c_info_t i2c_info; + struct cam_sensor_power_ctrl_t power_info; +}; + +/** + * struct intf_params + * @device_hdl: Device Handle + * @session_hdl: Session Handle + * @ops: KMD operations + * @crm_cb: Callback API pointers + */ +struct intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_actuator_ctrl_t + * @i2c_driver: I2C device info + * @pdev: Platform device + * @cci_i2c_master: I2C structure + * @io_master_info: Information about the communication master + * @actuator_mutex: Actuator mutex + * @act_apply_state: Actuator settings aRegulator config + * @id: Cell Index + * @res_apply_state: Actuator settings apply state + * @cam_act_state: Actuator state + * @gconf: GPIO config + * @pinctrl_info: Pinctrl information + * @v4l2_dev_str: V4L2 device structure + * @i2c_data: I2C register settings structure + * @act_info: Sensor query cap structure + * @of_node: Node ptr + * @device_name: Device name + * @last_flush_req: Last request to flush + */ +struct cam_actuator_ctrl_t { + struct i2c_driver *i2c_driver; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct camera_io_master io_master_info; + struct cam_hw_soc_info soc_info; + struct mutex actuator_mutex; + uint32_t id; + enum cam_actuator_apply_state_t setting_apply_state; + enum cam_actuator_state cam_act_state; + uint8_t cam_pinctrl_status; + struct cam_subdev v4l2_dev_str; + struct i2c_data_settings i2c_data; + struct cam_actuator_query_cap act_info; + struct intf_params bridge_intf; + char device_name[20]; + uint32_t last_flush_req; +}; + +#endif /* _CAM_ACTUATOR_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c new file mode 100644 index 000000000000..3ee629e3f1ca --- /dev/null +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_actuator_soc.h" +#include "cam_soc_util.h" + +int32_t cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl, + struct device *dev) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info = &a_ctrl->soc_info; + struct cam_actuator_soc_private *soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + struct device_node *of_node = NULL; + struct device_node *of_parent = NULL; + + /* Initialize mutex */ + mutex_init(&(a_ctrl->actuator_mutex)); + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "parsing common soc dt(rc %d)", rc); + return rc; + } + + of_node = soc_info->dev->of_node; + + if (a_ctrl->io_master_info.master_type == CCI_MASTER) { + rc = of_property_read_u32(of_node, "cci-master", + &(a_ctrl->cci_i2c_master)); + CAM_DBG(CAM_ACTUATOR, "cci-master %d, rc %d", + a_ctrl->cci_i2c_master, rc); + if ((rc < 0) || (a_ctrl->cci_i2c_master >= MASTER_MAX)) { + CAM_ERR(CAM_ACTUATOR, + "Wrong info: rc: %d, dt CCI master:%d", + rc, a_ctrl->cci_i2c_master); + rc = -EFAULT; + return rc; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &a_ctrl->cci_num) < 0) + /* Set default master 0 */ + a_ctrl->cci_num = CCI_DEVICE_0; + a_ctrl->io_master_info.cci_client->cci_device = a_ctrl->cci_num; + CAM_DBG(CAM_ACTUATOR, "cci-device %d", a_ctrl->cci_num); + } + + if (!soc_info->gpio_data) { + CAM_INFO(CAM_ACTUATOR, "No GPIO found"); + rc = 0; + return rc; + } + + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_INFO(CAM_ACTUATOR, "No GPIO found"); + return -EINVAL; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &power_info->gpio_num_info); + if ((rc < 0) || (!power_info->gpio_num_info)) { + CAM_ERR(CAM_ACTUATOR, "No/Error Actuator GPIOs"); + return -EINVAL; + } + return rc; +} diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.h b/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.h new file mode 100644 index 000000000000..65b4fb99fa03 --- /dev/null +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ACTUATOR_SOC_H_ +#define _CAM_ACTUATOR_SOC_H_ + +#include "cam_actuator_dev.h" + +/** + * @a_ctrl: Actuator ctrl structure + * + * This API parses actuator device tree + */ +int cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl, + struct device *dev); + +#endif /* _CAM_ACTUATOR_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_cci/Makefile b/drivers/cam_sensor_module/cam_cci/Makefile new file mode 100644 index 000000000000..82734cb81445 --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/camera/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci_dev.o cam_cci_core.o cam_cci_soc.o diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c new file mode 100644 index 000000000000..8701c6b9d62e --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -0,0 +1,1727 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_cci_core.h" +#include "cam_cci_dev.h" + +static int32_t cam_cci_convert_type_to_num_bytes( + enum camera_sensor_i2c_type type) +{ + int32_t num_bytes; + + switch (type) { + case CAMERA_SENSOR_I2C_TYPE_BYTE: + num_bytes = 1; + break; + case CAMERA_SENSOR_I2C_TYPE_WORD: + num_bytes = 2; + break; + case CAMERA_SENSOR_I2C_TYPE_3B: + num_bytes = 3; + break; + case CAMERA_SENSOR_I2C_TYPE_DWORD: + num_bytes = 4; + break; + default: + CAM_ERR(CAM_CCI, "failed: %d", type); + num_bytes = 0; + break; + } + return num_bytes; +} + +static void cam_cci_flush_queue(struct cci_device *cci_dev, + enum cci_i2c_master_t master) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + cam_io_w_mb(1 << master, base + CCI_HALT_REQ_ADDR); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc < 0) { + CAM_ERR(CAM_CCI, "wait failed"); + } else if (rc == 0) { + CAM_ERR(CAM_CCI, "wait timeout"); + + /* Set reset pending flag to TRUE */ + cci_dev->cci_master_info[master].reset_pending = TRUE; + + /* Set proper mask to RESET CMD address based on MASTER */ + if (master == MASTER_0) + cam_io_w_mb(CCI_M0_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + else + cam_io_w_mb(CCI_M1_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + + /* wait for reset done irq */ + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) + CAM_ERR(CAM_CCI, "wait failed %d", rc); + } +} + +static int32_t cam_cci_validate_queue(struct cci_device *cci_dev, + uint32_t len, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t read_val = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + unsigned long flags; + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d", + read_val, len, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); + if ((read_val + len + 1) > + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size) { + uint32_t reg_val = 0; + uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); + + CAM_DBG(CAM_CCI, "CCI_I2C_REPORT_CMD"); + cam_io_w_mb(report_val, + base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + read_val++; + CAM_DBG(CAM_CCI, + "CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d, queue: %d", + read_val, queue); + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + reg_val = 1 << ((master * 2) + queue); + CAM_DBG(CAM_CCI, "CCI_QUEUE_START_ADDR"); + spin_lock_irqsave( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + atomic_set( + &cci_dev->cci_master_info[master].done_pending[queue], + 1); + cam_io_w_mb(reg_val, base + + CCI_QUEUE_START_ADDR); + CAM_DBG(CAM_CCI, "wait_for_completion_timeout"); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].report_q[queue], + CCI_TIMEOUT); + if (rc <= 0) { + CAM_ERR(CAM_CCI, "Wait_for_completion_timeout: rc: %d", + rc); + if (rc == 0) + rc = -ETIMEDOUT; + cam_cci_flush_queue(cci_dev, master); + return rc; + } + rc = cci_dev->cci_master_info[master].status; + if (rc < 0) + CAM_ERR(CAM_CCI, "Failed rc %d", rc); + } + + return rc; +} + +static int32_t cam_cci_write_i2c_queue(struct cci_device *cci_dev, + uint32_t val, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + if (!cci_dev) { + CAM_ERR(CAM_CCI, "Failed"); + return -EINVAL; + } + + rc = cam_cci_validate_queue(cci_dev, 1, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Failed %d", rc); + return rc; + } + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x", + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset, val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + return rc; +} + +static int32_t cam_cci_lock_queue(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue, uint32_t en) +{ + uint32_t val; + + if (queue != PRIORITY_QUEUE) + return 0; + + val = en ? CCI_I2C_LOCK_CMD : CCI_I2C_UNLOCK_CMD; + return cam_cci_write_i2c_queue(cci_dev, val, master, queue); +} + +#ifdef DUMP_CCI_REGISTERS +static void cam_cci_dump_registers(struct cci_device *cci_dev, + enum cci_i2c_master_t master, enum cci_i2c_queue_t queue) +{ + uint32_t read_val = 0; + uint32_t i = 0; + uint32_t reg_offset = 0; + void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base; + + /* CCI Top Registers */ + CAM_INFO(CAM_CCI, "****CCI TOP Registers ****"); + for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) { + reg_offset = DEBUG_TOP_REG_START + i * 4; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } + + /* CCI Master registers */ + CAM_INFO(CAM_CCI, "****CCI MASTER %d Registers ****", + master); + for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) { + reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } + + /* CCI Master Queue registers */ + CAM_INFO(CAM_CCI, " **** CCI MASTER%d QUEUE%d Registers ****", + master, queue); + for (i = 0; i < DEBUG_MASTER_QUEUE_REG_COUNT; i++) { + reg_offset = DEBUG_MASTER_QUEUE_REG_START + master*0x200 + + queue*0x100 + i * 4; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } + + /* CCI Interrupt registers */ + CAM_INFO(CAM_CCI, " ****CCI Interrupt Registers ****"); + for (i = 0; i < DEBUG_INTR_REG_COUNT; i++) { + reg_offset = DEBUG_INTR_REG_START + i * 4; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } +} +#endif + +static uint32_t cam_cci_wait(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + + if (!cci_dev) { + CAM_ERR(CAM_CCI, "failed"); + return -EINVAL; + } + + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].report_q[queue], CCI_TIMEOUT); + CAM_DBG(CAM_CCI, "wait DONE_for_completion_timeout"); + + if (rc <= 0) { +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + CAM_ERR(CAM_CCI, "wait for queue: %d", queue); + if (rc == 0) + rc = -ETIMEDOUT; + cam_cci_flush_queue(cci_dev, master); + return rc; + } + rc = cci_dev->cci_master_info[master].status; + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + + return 0; +} + +static void cam_cci_load_report_cmd(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + uint32_t reg_offset = master * 0x200 + queue * 0x100; + uint32_t read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); + + CAM_DBG(CAM_CCI, "CCI_I2C_REPORT_CMD curr_w_cnt: %d", read_val); + cam_io_w_mb(report_val, + base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + read_val++; + + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d", read_val); + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); +} + +static int32_t cam_cci_wait_report_cmd(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + unsigned long flags; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + uint32_t reg_val = 1 << ((master * 2) + queue); + + cam_cci_load_report_cmd(cci_dev, master, queue); + spin_lock_irqsave( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); + atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + cam_io_w_mb(reg_val, base + + CCI_QUEUE_START_ADDR); + + return cam_cci_wait(cci_dev, master, queue); +} + +static int32_t cam_cci_transfer_end(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + unsigned long flags; + + spin_lock_irqsave( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) { + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_lock_queue(cci_dev, master, queue, 0); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + return rc; + } + rc = cam_cci_wait_report_cmd(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + } else { + atomic_set( + &cci_dev->cci_master_info[master].done_pending[queue], + 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_wait(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + rc = cam_cci_lock_queue(cci_dev, master, queue, 0); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + rc = cam_cci_wait_report_cmd(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Failed rc %d", rc); + return rc; + } + } + + return rc; +} + +static int32_t cam_cci_get_queue_free_size(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + uint32_t read_val = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d max %d", read_val, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); + return ((cci_dev->cci_i2c_queue_info[master][queue].max_queue_size) - + read_val); +} + +static void cam_cci_process_half_q(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + unsigned long flags; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + uint32_t reg_val = 1 << ((master * 2) + queue); + + spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) { + cam_cci_load_report_cmd(cci_dev, master, queue); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); + cam_io_w_mb(reg_val, base + + CCI_QUEUE_START_ADDR); + } + spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue], + flags); +} + +static int32_t cam_cci_process_full_q(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + unsigned long flags; + + + spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 1) { + atomic_set( + &cci_dev->cci_master_info[master].done_pending[queue], + 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_wait(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + } else { + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_wait_report_cmd(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + } + + return rc; +} + +static int32_t cam_cci_calc_cmd_len(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl, uint32_t cmd_size, + struct cam_sensor_i2c_reg_array *i2c_cmd, uint32_t *pack) +{ + uint8_t i; + uint32_t len = 0; + uint8_t data_len = 0, addr_len = 0; + uint8_t pack_max_len; + struct cam_sensor_i2c_reg_setting *msg; + struct cam_sensor_i2c_reg_array *cmd = i2c_cmd; + uint32_t size = cmd_size; + + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed"); + return -EINVAL; + } + + msg = &c_ctrl->cfg.cci_i2c_write_cfg; + *pack = 0; + + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) { + addr_len = cam_cci_convert_type_to_num_bytes(msg->addr_type); + len = (size + addr_len) <= (cci_dev->payload_size) ? + (size + addr_len):cci_dev->payload_size; + } else { + addr_len = cam_cci_convert_type_to_num_bytes(msg->addr_type); + data_len = cam_cci_convert_type_to_num_bytes(msg->data_type); + len = data_len + addr_len; + pack_max_len = size < (cci_dev->payload_size-len) ? + size : (cci_dev->payload_size-len); + for (i = 0; i < pack_max_len;) { + if (cmd->delay || ((cmd - i2c_cmd) >= (cmd_size - 1))) + break; + if (cmd->reg_addr + 1 == + (cmd+1)->reg_addr) { + len += data_len; + if (len > cci_dev->payload_size) { + len = len - data_len; + break; + } + (*pack)++; + } else { + break; + } + i += data_len; + cmd++; + } + } + + if (len > cci_dev->payload_size) { + CAM_ERR(CAM_CCI, "Len error: %d", len); + return -EINVAL; + } + + len += 1; /*add i2c WR command*/ + len = len/4 + 1; + + return len; +} + +static uint32_t cam_cci_cycles_per_ms(unsigned long clk) +{ + uint32_t cycles_per_us; + + if (clk) { + cycles_per_us = ((clk/1000)*256)/1000; + } else { + CAM_ERR(CAM_CCI, "failed: Can use default: %d", + CYCLES_PER_MICRO_SEC_DEFAULT); + cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT; + } + + return cycles_per_us; +} + +void cam_cci_get_clk_rates(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl) + +{ + int32_t src_clk_idx, j; + uint32_t cci_clk_src; + unsigned long clk; + struct cam_cci_clk_params_t *clk_params = NULL; + + enum i2c_freq_mode i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; + struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; + + if (i2c_freq_mode >= I2C_MAX_MODES || + i2c_freq_mode < I2C_STANDARD_MODE) { + CAM_ERR(CAM_CCI, "Invalid frequency mode: %d", + (int32_t)i2c_freq_mode); + cci_dev->clk_level_index = -1; + return; + } + + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; + cci_clk_src = clk_params->cci_clk_src; + + src_clk_idx = soc_info->src_clk_idx; + + if (src_clk_idx < 0) { + cci_dev->cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT; + cci_dev->clk_level_index = 0; + return; + } + + if (cci_clk_src == 0) { + clk = soc_info->clk_rate[0][src_clk_idx]; + cci_dev->cycles_per_us = cam_cci_cycles_per_ms(clk); + cci_dev->clk_level_index = 0; + return; + } + + for (j = 0; j < CAM_MAX_VOTE; j++) { + clk = soc_info->clk_rate[j][src_clk_idx]; + if (clk == cci_clk_src) { + cci_dev->cycles_per_us = cam_cci_cycles_per_ms(clk); + cci_dev->clk_level_index = j; + return; + } + } +} + +static int32_t cam_cci_set_clk_param(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl) +{ + struct cam_cci_clk_params_t *clk_params = NULL; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + enum i2c_freq_mode i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { + CAM_ERR(CAM_CCI, "invalid i2c_freq_mode = %d", i2c_freq_mode); + return -EINVAL; + } + + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; + + if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode) + return 0; + if (master == MASTER_0) { + cam_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + base + CCI_I2C_M0_SCL_CTL_ADDR); + cam_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + base + CCI_I2C_M0_SDA_CTL_0_ADDR); + cam_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + base + CCI_I2C_M0_SDA_CTL_1_ADDR); + cam_io_w_mb(clk_params->hw_tbuf, + base + CCI_I2C_M0_SDA_CTL_2_ADDR); + cam_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + base + CCI_I2C_M0_MISC_CTL_ADDR); + } else if (master == MASTER_1) { + cam_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + base + CCI_I2C_M1_SCL_CTL_ADDR); + cam_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + base + CCI_I2C_M1_SDA_CTL_0_ADDR); + cam_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + base + CCI_I2C_M1_SDA_CTL_1_ADDR); + cam_io_w_mb(clk_params->hw_tbuf, + base + CCI_I2C_M1_SDA_CTL_2_ADDR); + cam_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + base + CCI_I2C_M1_MISC_CTL_ADDR); + } + cci_dev->i2c_freq_mode[master] = i2c_freq_mode; + + return 0; +} + +static int32_t cam_cci_data_queue(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, + enum cci_i2c_sync sync_en) +{ + uint16_t i = 0, j = 0, k = 0, h = 0, len = 0; + int32_t rc = 0, free_size = 0, en_seq_write = 0; + uint8_t data[12]; + struct cam_sensor_i2c_reg_setting *i2c_msg = + &c_ctrl->cfg.cci_i2c_write_cfg; + struct cam_sensor_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + uint16_t reg_addr = 0, cmd_size = i2c_msg->size; + uint32_t read_val = 0, reg_offset, val, delay = 0; + uint32_t max_queue_size, queue_size = 0, cmd = 0; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + unsigned long flags; + + if (i2c_cmd == NULL) { + CAM_ERR(CAM_CCI, "Failed: i2c cmd is NULL"); + return -EINVAL; + } + + if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) { + CAM_ERR(CAM_CCI, "failed: invalid cmd_size %d", + cmd_size); + return -EINVAL; + } + + CAM_DBG(CAM_CCI, "addr type %d data type %d cmd_size %d", + i2c_msg->addr_type, i2c_msg->data_type, cmd_size); + + if (i2c_msg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed: invalid addr_type 0x%X", + i2c_msg->addr_type); + return -EINVAL; + } + if (i2c_msg->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed: invalid data_type 0x%X", + i2c_msg->data_type); + return -EINVAL; + } + reg_offset = master * 0x200 + queue * 0x100; + + cam_io_w_mb(cci_dev->cci_wait_sync_cfg.cid, + base + CCI_SET_CID_SYNC_TIMER_ADDR + + cci_dev->cci_wait_sync_cfg.csid * + CCI_SET_CID_SYNC_TIMER_OFFSET); + + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x", + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset, val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + + spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0); + spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + + max_queue_size = + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size; + + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) + queue_size = max_queue_size; + else + queue_size = max_queue_size/2; + reg_addr = i2c_cmd->reg_addr; + + if (sync_en == MSM_SYNC_ENABLE && cci_dev->valid_sync && + cmd_size < max_queue_size) { + val = CCI_I2C_WAIT_SYNC_CMD | + ((cci_dev->cci_wait_sync_cfg.line) << 4); + cam_io_w_mb(val, + base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + } + + rc = cam_cci_lock_queue(cci_dev, master, queue, 1); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed line %d", rc); + return rc; + } + + while (cmd_size) { + uint32_t pack = 0; + + len = cam_cci_calc_cmd_len(cci_dev, c_ctrl, cmd_size, + i2c_cmd, &pack); + if (len <= 0) { + CAM_ERR(CAM_CCI, "failed"); + return -EINVAL; + } + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CAM_DBG(CAM_CCI, "CUR_WORD_CNT_ADDR %d len %d max %d", + read_val, len, max_queue_size); + /* + 1 - space alocation for Report CMD */ + if ((read_val + len + 1) > queue_size) { + if ((read_val + len + 1) > max_queue_size) { + rc = cam_cci_process_full_q(cci_dev, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + return rc; + } + continue; + } + cam_cci_process_half_q(cci_dev, master, queue); + } + + CAM_DBG(CAM_CCI, "cmd_size %d addr 0x%x data 0x%x", + cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data); + delay = i2c_cmd->delay; + i = 0; + data[i++] = CCI_I2C_WRITE_CMD; + + /* + * in case of multiple command + * MSM_CCI_I2C_WRITE : address is not continuous, so update + * address for a new packet. + * MSM_CCI_I2C_WRITE_SEQ : address is continuous, need to keep + * the incremented address for a + * new packet + */ + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_ASYNC || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC_BLOCK) + reg_addr = i2c_cmd->reg_addr; + + if (en_seq_write == 0) { + /* either byte or word addr */ + if (i2c_msg->addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + data[i++] = reg_addr; + else { + data[i++] = (reg_addr & 0xFF00) >> 8; + data[i++] = reg_addr & 0x00FF; + } + } + /* max of 10 data bytes */ + do { + if (i2c_msg->data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + data[i++] = i2c_cmd->reg_data; + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) + reg_addr++; + } else { + if ((i + 1) <= cci_dev->payload_size) { + switch (i2c_msg->data_type) { + case CAMERA_SENSOR_I2C_TYPE_DWORD: + data[i++] = (i2c_cmd->reg_data & + 0xFF000000) >> 24; + /* fallthrough */ + case CAMERA_SENSOR_I2C_TYPE_3B: + data[i++] = (i2c_cmd->reg_data & + 0x00FF0000) >> 16; + /* fallthrough */ + case CAMERA_SENSOR_I2C_TYPE_WORD: + data[i++] = (i2c_cmd->reg_data & + 0x0000FF00) >> 8; + /* fallthrough */ + case CAMERA_SENSOR_I2C_TYPE_BYTE: + data[i++] = i2c_cmd->reg_data & + 0x000000FF; + break; + default: + CAM_ERR(CAM_CCI, + "invalid data type: %d", + i2c_msg->data_type); + return -EINVAL; + } + + if (c_ctrl->cmd == + MSM_CCI_I2C_WRITE_SEQ) + reg_addr++; + } else + break; + } + i2c_cmd++; + --cmd_size; + } while (((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) || pack--) && + (cmd_size > 0) && (i <= cci_dev->payload_size)); + free_size = cam_cci_get_queue_free_size(cci_dev, master, + queue); + if ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) && + ((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) && + cci_dev->support_seq_write && cmd_size > 0 && + free_size > BURST_MIN_FREE_SIZE) { + data[0] |= 0xF0; + en_seq_write = 1; + } else { + data[0] |= ((i-1) << 4); + en_seq_write = 0; + } + len = ((i-1)/4) + 1; + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + for (h = 0, k = 0; h < len; h++) { + cmd = 0; + for (j = 0; (j < 4 && k < i); j++) + cmd |= (data[k++] << (j * 8)); + CAM_DBG(CAM_CCI, + "LOAD_DATA_ADDR 0x%x, q: %d, len:%d, cnt: %d", + cmd, queue, len, read_val); + cam_io_w_mb(cmd, base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + + read_val += 1; + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + } + + if ((delay > 0) && (delay < CCI_MAX_DELAY) && + en_seq_write == 0) { + cmd = (uint32_t)((delay * cci_dev->cycles_per_us) / + 0x100); + cmd <<= 4; + cmd |= CCI_I2C_WAIT_CMD; + CAM_DBG(CAM_CCI, + "CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x", cmd); + cam_io_w_mb(cmd, base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + read_val += 1; + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + } + } + + rc = cam_cci_transfer_end(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + + return rc; +} + +static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + uint32_t val = 0, i = 0, j = 0, irq_mask_update = 0; + unsigned long rem_jiffies, flags; + int32_t read_words = 0, exp_words = 0; + int32_t index = 0, first_byte = 0, total_read_words = 0; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_1; + struct cci_device *cci_dev = NULL; + struct cam_cci_read_cfg *read_cfg = NULL; + struct cam_hw_soc_info *soc_info = NULL; + void __iomem *base = NULL; + + cci_dev = v4l2_get_subdevdata(sd); + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + + /* Set the I2C Frequency */ + rc = cam_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto rel_master; + } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_read call. This is to + * avoid overflow / underflow of queue + */ + rc = cam_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); + goto rel_mutex_q; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto rel_mutex_q; + } + + if (read_cfg->data == NULL) { + CAM_ERR(CAM_CCI, "Data ptr is NULL"); + goto rel_mutex_q; + } + + if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", + read_cfg->addr_type); + rc = -EINVAL; + goto rel_mutex_q; + } + + CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_LOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); + for (i = 0; i < read_cfg->addr_type; i++) { + val |= ((read_cfg->addr >> (i << 3)) & 0xFF) << + ((read_cfg->addr_type - i) << 3); + } + + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_UNLOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CAM_DBG(CAM_CCI, "cur word cnt 0x%x", val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); + + exp_words = ((read_cfg->num_byte / 4) + 1); + CAM_DBG(CAM_CCI, "waiting for threshold [exp_words %d]", exp_words); + + while (total_read_words != exp_words) { + rem_jiffies = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].th_complete, + CCI_TIMEOUT); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + + master * 0x100); + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d FIFO buf_lvl:0x%x", + rc, val); +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex_q; + } + + read_words = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + if (read_words <= 0) { + CAM_DBG(CAM_CCI, "FIFO Buffer lvl is 0"); + continue; + } + + j++; + CAM_DBG(CAM_CCI, "Iteration: %u read_words %d", j, read_words); + + total_read_words += read_words; + while (read_words > 0) { + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); + for (i = 0; (i < 4) && + (index < read_cfg->num_byte); i++) { + CAM_DBG(CAM_CCI, "i:%d index:%d", i, index); + if (!first_byte) { + CAM_DBG(CAM_CCI, "sid 0x%x", + val & 0xFF); + first_byte++; + } else { + read_cfg->data[index] = + (val >> (i * 8)) & 0xFF; + CAM_DBG(CAM_CCI, "data[%d] 0x%x", index, + read_cfg->data[index]); + index++; + } + } + read_words--; + } + + CAM_DBG(CAM_CCI, "Iteraion:%u total_read_words %d", + j, total_read_words); + + spin_lock_irqsave(&cci_dev->lock_status, flags); + if (cci_dev->irqs_disabled) { + irq_mask_update = + cam_io_r_mb(base + CCI_IRQ_MASK_1_ADDR) | + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + if (master == MASTER_0 && cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) + irq_mask_update |= + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + else if (master == MASTER_1 && cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) + irq_mask_update |= + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + cam_io_w_mb(irq_mask_update, + base + CCI_IRQ_MASK_1_ADDR); + } + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + + if (total_read_words == exp_words) { + /* + * This wait is for RD_DONE irq, if RD_DONE is + * triggered we will call complete on both threshold + * & read done waits. As part of the threshold wait + * we will be draining the entire buffer out. This + * wait is to compensate for the complete invoked for + * RD_DONE exclusively. + */ + rem_jiffies = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].rd_done, + CCI_TIMEOUT); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + + master * 0x100); + CAM_ERR(CAM_CCI, + "Failed to receive RD_DONE irq rc = %d FIFO buf_lvl:0x%x", + rc, val); + #ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, + master, queue); + #endif + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex_q; + } + break; + } + } + + CAM_DBG(CAM_CCI, "Burst read successful words_read %d", + total_read_words); + +rel_mutex_q: + mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + return rc; +} + +static int32_t cam_cci_read(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + uint32_t val = 0; + int32_t read_words = 0, exp_words = 0; + int32_t index = 0, first_byte = 0; + uint32_t i = 0; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_1; + struct cci_device *cci_dev = NULL; + struct cam_cci_read_cfg *read_cfg = NULL; + struct cam_hw_soc_info *soc_info = NULL; + void __iomem *base = NULL; + + cci_dev = v4l2_get_subdevdata(sd); + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + + /* Set the I2C Frequency */ + rc = cam_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); + goto rel_master; + } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_read call. This is to + * avoid overflow / underflow of queue + */ + rc = cam_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); + goto rel_mutex_q; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto rel_mutex_q; + } + + if (read_cfg->data == NULL) { + CAM_ERR(CAM_CCI, "Data ptr is NULL"); + goto rel_mutex_q; + } + + CAM_DBG(CAM_CCI, "master %d, queue %d", master, queue); + CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_LOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", + read_cfg->addr_type); + rc = -EINVAL; + goto rel_mutex_q; + } + + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); + for (i = 0; i < read_cfg->addr_type; i++) { + val |= ((read_cfg->addr >> (i << 3)) & 0xFF) << + ((read_cfg->addr_type - i) << 3); + } + + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_UNLOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CAM_DBG(CAM_CCI, "cur word cnt 0x%x", val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); + CAM_DBG(CAM_CCI, + "waiting_for_rd_done [exp_words: %d]", + ((read_cfg->num_byte / 4) + 1)); + + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); + if (rc <= 0) { +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + if (rc == 0) + rc = -ETIMEDOUT; + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d FIFO buf_lvl: 0x%x", + rc, val); + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex_q; + } else { + rc = 0; + } + + read_words = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + exp_words = ((read_cfg->num_byte / 4) + 1); + if (read_words != exp_words) { + CAM_ERR(CAM_CCI, "read_words = %d, exp words = %d", + read_words, exp_words); + memset(read_cfg->data, 0, read_cfg->num_byte); + rc = -EINVAL; + goto rel_mutex_q; + } + index = 0; + CAM_DBG(CAM_CCI, "index %d num_type %d", index, read_cfg->num_byte); + first_byte = 0; + while (read_words > 0) { + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); + CAM_DBG(CAM_CCI, "read val 0x%x", val); + for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) { + CAM_DBG(CAM_CCI, "i:%d index:%d", i, index); + if (!first_byte) { + CAM_DBG(CAM_CCI, "sid 0x%x", val & 0xFF); + first_byte++; + } else { + read_cfg->data[index] = + (val >> (i * 8)) & 0xFF; + CAM_DBG(CAM_CCI, "data[%d] 0x%x", index, + read_cfg->data[index]); + index++; + } + } + read_words--; + } +rel_mutex_q: + mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + return rc; +} + +static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, + enum cci_i2c_sync sync_en) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master; + + cci_dev = v4l2_get_subdevdata(sd); + + if (cci_dev->cci_state != CCI_STATE_ENABLED) { + CAM_ERR(CAM_CCI, "invalid cci state %d", + cci_dev->cci_state); + return -EINVAL; + } + master = c_ctrl->cci_info->cci_i2c_master; + CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + + /* Set the I2C Frequency */ + rc = cam_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto ERROR; + } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_write call. This is to + * avoid overflow / underflow of queue + */ + rc = cam_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size-1, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", + rc); + goto ERROR; + } + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto ERROR; + } + rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + goto ERROR; + } + +ERROR: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + return rc; +} + +static void cam_cci_write_async_helper(struct work_struct *work) +{ + int rc; + struct cci_device *cci_dev; + struct cci_write_async *write_async = + container_of(work, struct cci_write_async, work); + struct cam_sensor_i2c_reg_setting *i2c_msg; + enum cci_i2c_master_t master; + struct cam_cci_master_info *cci_master_info; + + cci_dev = write_async->cci_dev; + i2c_msg = &write_async->c_ctrl.cfg.cci_i2c_write_cfg; + master = write_async->c_ctrl.cci_info->cci_i2c_master; + cci_master_info = &cci_dev->cci_master_info[master]; + + mutex_lock(&cci_master_info->mutex_q[write_async->queue]); + rc = cam_cci_i2c_write(&(cci_dev->v4l2_dev_str.sd), + &write_async->c_ctrl, write_async->queue, write_async->sync_en); + mutex_unlock(&cci_master_info->mutex_q[write_async->queue]); + if (rc < 0) + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + + kfree(write_async->c_ctrl.cfg.cci_i2c_write_cfg.reg_setting); + kfree(write_async); +} + +static int32_t cam_cci_i2c_write_async(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, + enum cci_i2c_sync sync_en) +{ + int32_t rc = 0; + struct cci_write_async *write_async; + struct cci_device *cci_dev; + struct cam_sensor_i2c_reg_setting *cci_i2c_write_cfg; + struct cam_sensor_i2c_reg_setting *cci_i2c_write_cfg_w; + + cci_dev = v4l2_get_subdevdata(sd); + + write_async = kzalloc(sizeof(*write_async), GFP_KERNEL); + if (!write_async) + return -ENOMEM; + + + INIT_WORK(&write_async->work, cam_cci_write_async_helper); + write_async->cci_dev = cci_dev; + write_async->c_ctrl = *c_ctrl; + write_async->queue = queue; + write_async->sync_en = sync_en; + + cci_i2c_write_cfg = &c_ctrl->cfg.cci_i2c_write_cfg; + cci_i2c_write_cfg_w = &write_async->c_ctrl.cfg.cci_i2c_write_cfg; + + if (cci_i2c_write_cfg->size == 0) { + kfree(write_async); + return -EINVAL; + } + + cci_i2c_write_cfg_w->reg_setting = + kzalloc(sizeof(struct cam_sensor_i2c_reg_array)* + cci_i2c_write_cfg->size, GFP_KERNEL); + if (!cci_i2c_write_cfg_w->reg_setting) { + CAM_ERR(CAM_CCI, "Couldn't allocate memory"); + kfree(write_async); + return -ENOMEM; + } + memcpy(cci_i2c_write_cfg_w->reg_setting, + cci_i2c_write_cfg->reg_setting, + (sizeof(struct cam_sensor_i2c_reg_array)* + cci_i2c_write_cfg->size)); + + cci_i2c_write_cfg_w->addr_type = cci_i2c_write_cfg->addr_type; + cci_i2c_write_cfg_w->addr_type = cci_i2c_write_cfg->addr_type; + cci_i2c_write_cfg_w->data_type = cci_i2c_write_cfg->data_type; + cci_i2c_write_cfg_w->size = cci_i2c_write_cfg->size; + cci_i2c_write_cfg_w->delay = cci_i2c_write_cfg->delay; + + queue_work(cci_dev->write_wq[write_async->queue], &write_async->work); + + return rc; +} + +static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev = NULL; + enum cci_i2c_master_t master; + struct cam_cci_read_cfg *read_cfg = NULL; + uint16_t read_bytes = 0; + + if (!sd || !c_ctrl) { + CAM_ERR(CAM_CCI, "sd %pK c_ctrl %pK", sd, c_ctrl); + return -EINVAL; + } + if (!c_ctrl->cci_info) { + CAM_ERR(CAM_CCI, "cci_info NULL"); + return -EINVAL; + } + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev) { + CAM_ERR(CAM_CCI, "cci_dev NULL"); + return -EINVAL; + } + if (cci_dev->cci_state != CCI_STATE_ENABLED) { + CAM_ERR(CAM_CCI, "invalid cci state %d", cci_dev->cci_state); + return -EINVAL; + } + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) { + CAM_ERR(CAM_CCI, "read num bytes 0"); + rc = -EINVAL; + goto ERROR; + } + + read_bytes = read_cfg->num_byte; + + /* + * To avoid any conflicts due to back to back trigger of + * THRESHOLD irq's, we reinit the threshold wait before + * we load the burst read cmd. + */ + reinit_completion(&cci_dev->cci_master_info[master].th_complete); + + CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes); + do { + if (read_bytes >= CCI_I2C_MAX_BYTE_COUNT) + read_cfg->num_byte = CCI_I2C_MAX_BYTE_COUNT; + else + read_cfg->num_byte = read_bytes; + + if (read_cfg->num_byte >= CCI_READ_MAX) { + cci_dev->is_burst_read = true; + rc = cam_cci_burst_read(sd, c_ctrl); + } else { + cci_dev->is_burst_read = false; + rc = cam_cci_read(sd, c_ctrl); + } + if (rc) { + CAM_ERR(CAM_CCI, "failed to read rc:%d", rc); + goto ERROR; + } + + if (read_bytes >= CCI_I2C_MAX_BYTE_COUNT) { + read_cfg->addr += (CCI_I2C_MAX_BYTE_COUNT / + read_cfg->data_type); + read_cfg->data += CCI_I2C_MAX_BYTE_COUNT; + read_bytes -= CCI_I2C_MAX_BYTE_COUNT; + } else { + read_bytes = 0; + } + } while (read_bytes); + +ERROR: + cci_dev->is_burst_read = false; + return rc; +} + +static int32_t cam_cci_i2c_set_sync_prms(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + cci_dev, c_ctrl); + rc = -EINVAL; + return rc; + } + cci_dev->cci_wait_sync_cfg = c_ctrl->cfg.cci_wait_sync_cfg; + cci_dev->valid_sync = cci_dev->cci_wait_sync_cfg.csid < 0 ? 0 : 1; + + return rc; +} + +static int32_t cam_cci_release(struct v4l2_subdev *sd) +{ + uint8_t rc = 0; + struct cci_device *cci_dev; + + cci_dev = v4l2_get_subdevdata(sd); + + rc = cam_cci_soc_release(cci_dev); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Failed in releasing the cci: %d", rc); + return rc; + } + + return rc; +} + +static int32_t cam_cci_write(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master; + struct cam_cci_master_info *cci_master_info; + uint32_t i; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + cci_dev, c_ctrl); + rc = -EINVAL; + return rc; + } + + master = c_ctrl->cci_info->cci_i2c_master; + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + cci_master_info = &cci_dev->cci_master_info[master]; + + switch (c_ctrl->cmd) { + case MSM_CCI_I2C_WRITE_SYNC_BLOCK: + mutex_lock(&cci_master_info->mutex_q[SYNC_QUEUE]); + rc = cam_cci_i2c_write(sd, c_ctrl, + SYNC_QUEUE, MSM_SYNC_ENABLE); + mutex_unlock(&cci_master_info->mutex_q[SYNC_QUEUE]); + break; + case MSM_CCI_I2C_WRITE_SYNC: + rc = cam_cci_i2c_write_async(sd, c_ctrl, + SYNC_QUEUE, MSM_SYNC_ENABLE); + break; + case MSM_CCI_I2C_WRITE: + case MSM_CCI_I2C_WRITE_SEQ: + case MSM_CCI_I2C_WRITE_BURST: + for (i = 0; i < NUM_QUEUES; i++) { + if (mutex_trylock(&cci_master_info->mutex_q[i])) { + rc = cam_cci_i2c_write(sd, c_ctrl, i, + MSM_SYNC_DISABLE); + mutex_unlock(&cci_master_info->mutex_q[i]); + return rc; + } + } + mutex_lock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); + rc = cam_cci_i2c_write(sd, c_ctrl, + PRIORITY_QUEUE, MSM_SYNC_DISABLE); + mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); + break; + case MSM_CCI_I2C_WRITE_ASYNC: + rc = cam_cci_i2c_write_async(sd, c_ctrl, + PRIORITY_QUEUE, MSM_SYNC_DISABLE); + break; + default: + rc = -ENOIOCTLCMD; + } + + return rc; +} + +int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, + struct cam_cci_ctrl *cci_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + + switch (cci_ctrl->cmd) { + case MSM_CCI_INIT: + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_init(sd, cci_ctrl); + mutex_unlock(&cci_dev->init_mutex); + break; + case MSM_CCI_RELEASE: + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_release(sd); + mutex_unlock(&cci_dev->init_mutex); + break; + case MSM_CCI_I2C_READ: + rc = cam_cci_read_bytes(sd, cci_ctrl); + break; + case MSM_CCI_I2C_WRITE: + case MSM_CCI_I2C_WRITE_SEQ: + case MSM_CCI_I2C_WRITE_BURST: + case MSM_CCI_I2C_WRITE_SYNC: + case MSM_CCI_I2C_WRITE_ASYNC: + case MSM_CCI_I2C_WRITE_SYNC_BLOCK: + rc = cam_cci_write(sd, cci_ctrl); + break; + case MSM_CCI_GPIO_WRITE: + break; + case MSM_CCI_SET_SYNC_CID: + rc = cam_cci_i2c_set_sync_prms(sd, cci_ctrl); + break; + + default: + rc = -ENOIOCTLCMD; + } + + cci_ctrl->status = rc; + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.h b/drivers/cam_sensor_module/cam_cci/cam_cci_core.h new file mode 100644 index 000000000000..aeaee32502ec --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_CCI_CORE_H_ +#define _CAM_CCI_CORE_H_ + +#include +#include +#include "cam_cci_dev.h" +#include "cam_cci_soc.h" + +/** + * @cci_dev: CCI device structure + * @c_ctrl: CCI control structure + * + * This API gets CCI clk rates + */ +void cam_cci_get_clk_rates(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl); + +/** + * @sd: V4L2 sub device + * @c_ctrl: CCI control structure + * + * This API handles I2C operations for CCI + */ +int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, + struct cam_cci_ctrl *cci_ctrl); + +/** + * @irq_num: IRQ number + * @data: CCI private structure + * + * This API handles CCI IRQs + */ +irqreturn_t cam_cci_irq(int irq_num, void *data); + +#endif /* _CAM_CCI_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c new file mode 100644 index 000000000000..5f155df4dc44 --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_cci_dev.h" +#include "../../cam_req_mgr/cam_req_mgr_dev.h" +#include "cam_cci_soc.h" +#include "cam_cci_core.h" + +#define CCI_MAX_DELAY 1000000 + +static struct v4l2_subdev *g_cci_subdev[MAX_CCI]; + +struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) +{ + if (cci_dev_index < MAX_CCI) + return g_cci_subdev[cci_dev_index]; + return NULL; +} + +static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + + if (arg == NULL) { + CAM_ERR(CAM_CCI, "Invalid Args"); + return rc; + } + + switch (cmd) { + case VIDIOC_MSM_CCI_CFG: + rc = cam_cci_core_cfg(sd, arg); + break; + case VIDIOC_CAM_CONTROL: + break; + default: + CAM_ERR(CAM_CCI, "Invalid ioctl cmd: %d", cmd); + rc = -ENOIOCTLCMD; + } + + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_cci_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + return cam_cci_subdev_ioctl(sd, cmd, NULL); +} +#endif + +irqreturn_t cam_cci_irq(int irq_num, void *data) +{ + uint32_t irq_status0, irq_status1, reg_bmsk; + uint32_t irq_update_rd_done = 0; + struct cci_device *cci_dev = data; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + unsigned long flags; + bool rd_done_th_assert = false; + + irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); + irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR); + CAM_DBG(CAM_CCI, "BASE: %pK", base); + CAM_DBG(CAM_CCI, "irq0:%x irq1:%x", irq_status0, irq_status1); + + if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + struct cam_cci_master_info *cci_master_info; + if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; + cci_dev->cci_master_info[MASTER_0].reset_pending = + FALSE; + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; + } + if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; + cci_dev->cci_master_info[MASTER_1].reset_pending = + FALSE; + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; + } + } + + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && + (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + rd_done_th_assert = true; + complete(&cci_dev->cci_master_info[MASTER_0].th_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); + } + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + rd_done_th_assert = true; + if (cci_dev->is_burst_read) + complete( + &cci_dev->cci_master_info[MASTER_0].th_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); + } + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + complete(&cci_dev->cci_master_info[MASTER_0].th_complete); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_0], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) { + complete(&cci_master_info->report_q[QUEUE_0]); + atomic_set(&cci_master_info->done_pending[QUEUE_0], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0], + flags); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_1], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) { + complete(&cci_master_info->report_q[QUEUE_1]); + atomic_set(&cci_master_info->done_pending[QUEUE_1], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1], + flags); + } + rd_done_th_assert = false; + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && + (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + rd_done_th_assert = true; + complete(&cci_dev->cci_master_info[MASTER_1].th_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); + } + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + rd_done_th_assert = true; + if (cci_dev->is_burst_read) + complete( + &cci_dev->cci_master_info[MASTER_1].th_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); + } + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + complete(&cci_dev->cci_master_info[MASTER_1].th_complete); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_0], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) { + complete(&cci_master_info->report_q[QUEUE_0]); + atomic_set(&cci_master_info->done_pending[QUEUE_0], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0], + flags); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_1], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) { + complete(&cci_master_info->report_q[QUEUE_1]); + atomic_set(&cci_master_info->done_pending[QUEUE_1], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1], + flags); + } + if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE) + CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_0"); + + if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_PAUSE) + CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_1"); + + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + cam_io_w_mb(CCI_M0_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; + cam_io_w_mb(CCI_M1_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { + cci_dev->cci_master_info[MASTER_0].status = -EINVAL; + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { + cci_dev->cci_master_info[MASTER_1].status = -EINVAL; + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) + CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + } + + cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); + + reg_bmsk = CCI_IRQ_MASK_1_RMSK; + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && + !(irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK)) { + reg_bmsk &= ~CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + spin_lock_irqsave(&cci_dev->lock_status, flags); + cci_dev->irqs_disabled |= + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && + !(irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK)) { + reg_bmsk &= ~CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + spin_lock_irqsave(&cci_dev->lock_status, flags); + cci_dev->irqs_disabled |= + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + + if (reg_bmsk != CCI_IRQ_MASK_1_RMSK) { + cam_io_w_mb(reg_bmsk, base + CCI_IRQ_MASK_1_ADDR); + CAM_DBG(CAM_CCI, "Updating the reg mask for irq1: 0x%x", + reg_bmsk); + } else if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK || + irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) { + spin_lock_irqsave(&cci_dev->lock_status, flags); + if (cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) { + irq_update_rd_done |= + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + cci_dev->irqs_disabled &= + ~CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + } + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) { + spin_lock_irqsave(&cci_dev->lock_status, flags); + if (cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) { + irq_update_rd_done |= + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + cci_dev->irqs_disabled &= + ~CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + } + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + } + + if (irq_update_rd_done != 0) { + irq_update_rd_done |= cam_io_r_mb(base + CCI_IRQ_MASK_1_ADDR); + cam_io_w_mb(irq_update_rd_done, base + CCI_IRQ_MASK_1_ADDR); + } + + + cam_io_w_mb(irq_status1, base + CCI_IRQ_CLEAR_1_ADDR); + cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + return IRQ_HANDLED; +} + +static int cam_cci_irq_routine(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + irqreturn_t ret; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + + ret = cam_cci_irq(soc_info->irq_line->start, cci_dev); + *handled = TRUE; + return 0; +} + +static struct v4l2_subdev_core_ops cci_subdev_core_ops = { + .ioctl = cam_cci_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_cci_subdev_compat_ioctl, +#endif + .interrupt_service_routine = cam_cci_irq_routine, +}; + +static const struct v4l2_subdev_ops cci_subdev_ops = { + .core = &cci_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cci_subdev_intern_ops; + +static struct v4l2_file_operations cci_v4l2_subdev_fops; + +static long cam_cci_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return cam_cci_subdev_ioctl(sd, cmd, NULL); +} + +static long cam_cci_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, cam_cci_subdev_do_ioctl); +} + +#ifdef CONFIG_COMPAT +static long cam_cci_subdev_fops_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return v4l2_subdev_call(sd, core, ioctl, cmd, NULL); +} +#endif + +static int cam_cci_platform_probe(struct platform_device *pdev) +{ + struct cam_cpas_register_params cpas_parms; + struct cci_device *new_cci_dev; + struct cam_hw_soc_info *soc_info = NULL; + int rc = 0; + + new_cci_dev = kzalloc(sizeof(struct cci_device), + GFP_KERNEL); + if (!new_cci_dev) + return -ENOMEM; + + soc_info = &new_cci_dev->soc_info; + + new_cci_dev->v4l2_dev_str.pdev = pdev; + + soc_info->pdev = pdev; + soc_info->dev = &pdev->dev; + soc_info->dev_name = pdev->name; + + rc = cam_cci_parse_dt_info(pdev, new_cci_dev); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Resource get Failed: %d", rc); + goto cci_no_resource; + } + + new_cci_dev->v4l2_dev_str.internal_ops = + &cci_subdev_intern_ops; + new_cci_dev->v4l2_dev_str.ops = + &cci_subdev_ops; + strlcpy(new_cci_dev->device_name, CAMX_CCI_DEV_NAME, + sizeof(new_cci_dev->device_name)); + new_cci_dev->v4l2_dev_str.name = + new_cci_dev->device_name; + new_cci_dev->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + new_cci_dev->v4l2_dev_str.ent_function = + CAM_CCI_DEVICE_TYPE; + new_cci_dev->v4l2_dev_str.token = + new_cci_dev; + + rc = cam_register_subdev(&(new_cci_dev->v4l2_dev_str)); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Fail with cam_register_subdev"); + goto cci_no_resource; + } + + platform_set_drvdata(pdev, &(new_cci_dev->v4l2_dev_str.sd)); + v4l2_set_subdevdata(&new_cci_dev->v4l2_dev_str.sd, new_cci_dev); + if (soc_info->index >= MAX_CCI) { + CAM_ERR(CAM_CCI, "Invalid index: %d max supported:%d", + soc_info->index, MAX_CCI-1); + goto cci_no_resource; + } + + g_cci_subdev[soc_info->index] = &new_cci_dev->v4l2_dev_str.sd; + mutex_init(&(new_cci_dev->init_mutex)); + CAM_INFO(CAM_CCI, "Device Type :%d", soc_info->index); + + cam_register_subdev_fops(&cci_v4l2_subdev_fops); + cci_v4l2_subdev_fops.unlocked_ioctl = cam_cci_subdev_fops_ioctl; +#ifdef CONFIG_COMPAT + cci_v4l2_subdev_fops.compat_ioctl32 = + cam_cci_subdev_fops_compat_ioctl; +#endif + + cpas_parms.cam_cpas_client_cb = NULL; + cpas_parms.cell_index = soc_info->index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = new_cci_dev; + strlcpy(cpas_parms.identifier, "cci", CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CCI, "CPAS registration failed"); + goto cci_no_resource; + } + CAM_DBG(CAM_CCI, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + new_cci_dev->cpas_handle = cpas_parms.client_handle; + + return rc; +cci_no_resource: + kfree(new_cci_dev); + return rc; +} + +static int cam_cci_device_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev = platform_get_drvdata(pdev); + struct cci_device *cci_dev = + v4l2_get_subdevdata(subdev); + + cam_cpas_unregister_client(cci_dev->cpas_handle); + cam_cci_soc_remove(pdev, cci_dev); + devm_kfree(&pdev->dev, cci_dev); + return 0; +} + +static const struct of_device_id cam_cci_dt_match[] = { + {.compatible = "qcom,cci"}, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_cci_dt_match); + +static struct platform_driver cci_driver = { + .probe = cam_cci_platform_probe, + .remove = cam_cci_device_remove, + .driver = { + .name = CAMX_CCI_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_cci_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int cam_cci_assign_fops(void) +{ + struct v4l2_subdev *sd; + int i = 0; + + for (; i < MAX_CCI; i++) { + sd = g_cci_subdev[i]; + if (!sd) + return 0; + if (!(sd->devnode)) { + CAM_ERR(CAM_CCI, + "Invalid dev node:%pK offset: %d", + sd->devnode, i); + return -EINVAL; + } + sd->devnode->fops = &cci_v4l2_subdev_fops; + } + + return 0; +} + +static int __init cam_cci_late_init(void) +{ + return cam_cci_assign_fops(); +} + +static int __init cam_cci_init_module(void) +{ + return platform_driver_register(&cci_driver); +} + +static void __exit cam_cci_exit_module(void) +{ + platform_driver_unregister(&cci_driver); +} + +module_init(cam_cci_init_module); +late_initcall(cam_cci_late_init); +module_exit(cam_cci_exit_module); +MODULE_DESCRIPTION("MSM CCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h new file mode 100644 index 000000000000..4bc1d34af3d2 --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -0,0 +1,313 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CCI_DEV_H_ +#define _CAM_CCI_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../cam_req_mgr/cam_subdev.h" +#include +#include "cam_cci_hwreg.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +#define V4L2_IDENT_CCI 50005 +#define CCI_I2C_QUEUE_0_SIZE 128 +#define CCI_I2C_QUEUE_1_SIZE 32 +#define CYCLES_PER_MICRO_SEC_DEFAULT 4915 +#define CCI_MAX_DELAY 1000000 + +#define CCI_TIMEOUT msecs_to_jiffies(1500) + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#define CCI_PINCTRL_STATE_DEFAULT "cci_default" +#define CCI_PINCTRL_STATE_SLEEP "cci_suspend" + +#define CCI_NUM_CLK_MAX 16 +#define CCI_NUM_CLK_CASES 5 +#define CCI_CLK_SRC_NAME "cci_src_clk" +#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_10 10 +#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 11 +#define BURST_MIN_FREE_SIZE 8 +#define MAX_LRME_V4l2_EVENTS 30 + +/* Max bytes that can be read per CCI read transaction */ +#define CCI_READ_MAX 256 +#define CCI_I2C_READ_MAX_RETRIES 3 +#define CCI_I2C_MAX_READ 8192 +#define CCI_I2C_MAX_WRITE 8192 +#define CCI_I2C_MAX_BYTE_COUNT 65535 + +#define CAMX_CCI_DEV_NAME "cam-cci-driver" + +#define MAX_CCI 2 + +#define PRIORITY_QUEUE (QUEUE_0) +#define SYNC_QUEUE (QUEUE_1) + +enum cci_i2c_sync { + MSM_SYNC_DISABLE, + MSM_SYNC_ENABLE, +}; + +enum cam_cci_cmd_type { + MSM_CCI_INIT, + MSM_CCI_RELEASE, + MSM_CCI_SET_SID, + MSM_CCI_SET_FREQ, + MSM_CCI_SET_SYNC_CID, + MSM_CCI_I2C_READ, + MSM_CCI_I2C_WRITE, + MSM_CCI_I2C_WRITE_SEQ, + MSM_CCI_I2C_WRITE_BURST, + MSM_CCI_I2C_WRITE_ASYNC, + MSM_CCI_GPIO_WRITE, + MSM_CCI_I2C_WRITE_SYNC, + MSM_CCI_I2C_WRITE_SYNC_BLOCK, +}; + +enum cci_i2c_queue_t { + QUEUE_0, + QUEUE_1, + QUEUE_INVALID, +}; + +struct cam_cci_wait_sync_cfg { + uint16_t cid; + int16_t csid; + uint16_t line; + uint16_t delay; +}; + +struct cam_cci_gpio_cfg { + uint16_t gpio_queue; + uint16_t i2c_queue; +}; + +struct cam_cci_read_cfg { + uint32_t addr; + uint16_t addr_type; + uint8_t *data; + uint16_t num_byte; + uint16_t data_type; +}; + +struct cam_cci_i2c_queue_info { + uint32_t max_queue_size; + uint32_t report_id; + uint32_t irq_en; + uint32_t capture_rep_data; +}; + +struct cam_cci_master_info { + uint32_t status; + atomic_t q_free[NUM_QUEUES]; + uint8_t q_lock[NUM_QUEUES]; + uint8_t reset_pending; + struct mutex mutex; + struct completion reset_complete; + struct completion rd_done; + struct completion th_complete; + struct mutex mutex_q[NUM_QUEUES]; + struct completion report_q[NUM_QUEUES]; + atomic_t done_pending[NUM_QUEUES]; + spinlock_t lock_q[NUM_QUEUES]; + spinlock_t freq_cnt; + struct semaphore master_sem; + bool is_first_req; + uint16_t freq_ref_cnt; +}; + +struct cam_cci_clk_params_t { + uint16_t hw_thigh; + uint16_t hw_tlow; + uint16_t hw_tsu_sto; + uint16_t hw_tsu_sta; + uint16_t hw_thd_dat; + uint16_t hw_thd_sta; + uint16_t hw_tbuf; + uint8_t hw_scl_stretch_en; + uint8_t hw_trdhld; + uint8_t hw_tsp; + uint32_t cci_clk_src; +}; + +enum cam_cci_state_t { + CCI_STATE_ENABLED, + CCI_STATE_DISABLED, +}; + +/** + * struct cci_device + * @pdev: Platform device + * @subdev: V4L2 sub device + * @base: Base address of CCI device + * @hw_version: Hardware version + * @ref_count: Reference Count + * @cci_state: CCI state machine + * @num_clk: Number of CCI clock + * @cci_clk: CCI clock structure + * @cci_clk_info: CCI clock information + * @cam_cci_i2c_queue_info: CCI queue information + * @i2c_freq_mode: I2C frequency of operations + * @cci_clk_params: CCI hw clk params + * @cci_gpio_tbl: CCI GPIO table + * @cci_gpio_tbl_size: GPIO table size + * @cci_pinctrl: Pinctrl structure + * @cci_pinctrl_status: CCI pinctrl status + * @cci_clk_src: CCI clk src rate + * @cci_vreg: CCI regulator structure + * @cci_reg_ptr: CCI individual regulator structure + * @regulator_count: Regulator count + * @support_seq_write: Set this flag when sequential write is enabled + * @write_wq: Work queue structure + * @valid_sync: Is it a valid sync with CSID + * @v4l2_dev_str: V4L2 device structure + * @cci_wait_sync_cfg: CCI sync config + * @cycles_per_us: Cycles per micro sec + * @payload_size: CCI packet payload size + * @irq_status1: Store irq_status1 to be cleared after + * draining FIFO buffer for burst read + * @lock_status: to protect changes to irq_status1 + * @is_burst_read: Flag to determine if we are performing + * a burst read operation or not + * @irqs_disabled: Mask for IRQs that are disabled + * @init_mutex: Mutex for maintaining refcount for attached + * devices to cci during init/deinit. + */ +struct cci_device { + struct v4l2_subdev subdev; + struct cam_hw_soc_info soc_info; + uint32_t hw_version; + uint8_t ref_count; + enum cam_cci_state_t cci_state; + struct cam_cci_i2c_queue_info + cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; + struct cam_cci_master_info cci_master_info[NUM_MASTERS]; + enum i2c_freq_mode i2c_freq_mode[NUM_MASTERS]; + struct cam_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; + struct msm_pinctrl_info cci_pinctrl; + uint8_t cci_pinctrl_status; + uint8_t support_seq_write; + struct workqueue_struct *write_wq[MASTER_MAX]; + struct cam_cci_wait_sync_cfg cci_wait_sync_cfg; + uint8_t valid_sync; + struct cam_subdev v4l2_dev_str; + uint32_t cycles_per_us; + int32_t clk_level_index; + uint8_t payload_size; + char device_name[20]; + uint32_t cpas_handle; + uint32_t irq_status1; + spinlock_t lock_status; + bool is_burst_read; + uint32_t irqs_disabled; + struct mutex init_mutex; +}; + +enum cam_cci_i2c_cmd_type { + CCI_I2C_SET_PARAM_CMD = 1, + CCI_I2C_WAIT_CMD, + CCI_I2C_WAIT_SYNC_CMD, + CCI_I2C_WAIT_GPIO_EVENT_CMD, + CCI_I2C_TRIG_I2C_EVENT_CMD, + CCI_I2C_LOCK_CMD, + CCI_I2C_UNLOCK_CMD, + CCI_I2C_REPORT_CMD, + CCI_I2C_WRITE_CMD, + CCI_I2C_READ_CMD, + CCI_I2C_WRITE_DISABLE_P_CMD, + CCI_I2C_READ_DISABLE_P_CMD, + CCI_I2C_WRITE_CMD2, + CCI_I2C_WRITE_CMD3, + CCI_I2C_REPEAT_CMD, + CCI_I2C_INVALID_CMD, +}; + +enum cam_cci_gpio_cmd_type { + CCI_GPIO_SET_PARAM_CMD = 1, + CCI_GPIO_WAIT_CMD, + CCI_GPIO_WAIT_SYNC_CMD, + CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD, + CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD, + CCI_GPIO_OUT_CMD, + CCI_GPIO_TRIG_EVENT_CMD, + CCI_GPIO_REPORT_CMD, + CCI_GPIO_REPEAT_CMD, + CCI_GPIO_CONTINUE_CMD, + CCI_GPIO_INVALID_CMD, +}; + +struct cam_sensor_cci_client { + struct v4l2_subdev *cci_subdev; + uint32_t freq; + enum i2c_freq_mode i2c_freq_mode; + enum cci_i2c_master_t cci_i2c_master; + uint16_t sid; + uint16_t cid; + uint32_t timeout; + uint16_t retries; + uint16_t id_map; + uint16_t cci_device; +}; + +struct cam_cci_ctrl { + int32_t status; + struct cam_sensor_cci_client *cci_info; + enum cam_cci_cmd_type cmd; + union { + struct cam_sensor_i2c_reg_setting cci_i2c_write_cfg; + struct cam_cci_read_cfg cci_i2c_read_cfg; + struct cam_cci_wait_sync_cfg cci_wait_sync_cfg; + struct cam_cci_gpio_cfg gpio_cfg; + } cfg; +}; + +struct cci_write_async { + struct cci_device *cci_dev; + struct cam_cci_ctrl c_ctrl; + enum cci_i2c_queue_t queue; + struct work_struct work; + enum cci_i2c_sync sync_en; +}; + +irqreturn_t cam_cci_irq(int irq_num, void *data); + +#ifdef CONFIG_SPECTRA_CAMERA +extern struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); +#else +static inline struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) +{ + return NULL; +} +#endif + +#define VIDIOC_MSM_CCI_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) + +#endif /* _CAM_CCI_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h new file mode 100644 index 000000000000..f00b854e9533 --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2015, 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CCI_HWREG_ +#define _CAM_CCI_HWREG_ + +#define CCI_HW_VERSION_ADDR 0x00000000 +#define CCI_RESET_CMD_ADDR 0x00000004 +#define CCI_RESET_CMD_RMSK 0x0f73f3f7 +#define CCI_M0_RESET_RMSK 0x3F1 +#define CCI_M1_RESET_RMSK 0x3F001 +#define CCI_QUEUE_START_ADDR 0x00000008 +#define CCI_SET_CID_SYNC_TIMER_ADDR 0x00000010 +#define CCI_SET_CID_SYNC_TIMER_OFFSET 0x00000004 +#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100 +#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104 +#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108 +#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c +#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118 +#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110 +#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C +#define CCI_HALT_REQ_ADDR 0x00000034 +#define CCI_M0_HALT_REQ_RMSK 0x1 +#define CCI_M1_HALT_REQ_RMSK 0x2 +#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200 +#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204 +#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208 +#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c +#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210 +#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304 +#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308 +#define CCI_I2C_M0_Q0_REPORT_STATUS_ADDR 0x0000030c +#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300 +#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310 +#define CCI_IRQ_MASK_0_ADDR 0x00000c04 +#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7 +#define CCI_IRQ_MASK_1_ADDR 0x00000c10 +#define CCI_IRQ_MASK_1_RMSK 0x00110000 +#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08 +#define CCI_IRQ_CLEAR_1_ADDR 0x00000c14 +#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c +#define CCI_IRQ_STATUS_1_ADDR 0x00000c18 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000 +#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000 +#define CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD 0x100000 +#define CCI_IRQ_STATUS_1_I2C_M1_RD_PAUSE 0x200000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 +#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 +#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 +#define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK 0x18000000 +#define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK 0x60000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK 0x6000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 +#define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD 0x10000 +#define CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE 0x20000 +#define CCI_I2C_M0_RD_THRESHOLD_ADDR 0x00000120 +#define CCI_I2C_M1_RD_THRESHOLD_ADDR 0x00000220 +#define CCI_I2C_RD_THRESHOLD_VALUE 0x30 +#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00 + +#define DEBUG_TOP_REG_START 0x0 +#define DEBUG_TOP_REG_COUNT 14 +#define DEBUG_MASTER_REG_START 0x100 +#define DEBUG_MASTER_REG_COUNT 9 +#define DEBUG_MASTER_QUEUE_REG_START 0x300 +#define DEBUG_MASTER_QUEUE_REG_COUNT 7 +#define DEBUG_INTR_REG_START 0xC00 +#define DEBUG_INTR_REG_COUNT 7 +#endif /* _CAM_CCI_HWREG_ */ diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c new file mode 100644 index 000000000000..633196c983aa --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_cci_dev.h" +#include "cam_cci_core.h" + +int cam_cci_init(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + uint8_t i = 0, j = 0; + int32_t rc = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + struct cam_hw_soc_info *soc_info = NULL; + void __iomem *base = NULL; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + cci_dev, c_ctrl); + rc = -EINVAL; + return rc; + } + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + if (!soc_info || !base) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + soc_info, base); + rc = -EINVAL; + return rc; + } + + CAM_DBG(CAM_CCI, "Base address %pK", base); + + if (cci_dev->ref_count++) { + CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); + CAM_DBG(CAM_CCI, "master %d", master); + if (master < MASTER_MAX && master >= 0) { + mutex_lock(&cci_dev->cci_master_info[master].mutex); + flush_workqueue(cci_dev->write_wq[master]); + /* Re-initialize the completion */ + reinit_completion( + &cci_dev->cci_master_info[master].reset_complete); + reinit_completion( + &cci_dev->cci_master_info[master].rd_done); + for (i = 0; i < NUM_QUEUES; i++) + reinit_completion( + &cci_dev->cci_master_info[master].report_q[i]); + /* Set reset pending flag to TRUE */ + cci_dev->cci_master_info[master].reset_pending = TRUE; + /* Set proper mask to RESET CMD address */ + if (master == MASTER_0) + cam_io_w_mb(CCI_M0_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + else + cam_io_w_mb(CCI_M1_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + /* wait for reset done irq */ + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) + CAM_ERR(CAM_CCI, "wait failed %d", rc); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + } + return 0; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = + CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(cci_dev->cpas_handle, + &ahb_vote, &axi_vote); + if (rc != 0) + CAM_ERR(CAM_CCI, "CPAS start failed"); + + cam_cci_get_clk_rates(cci_dev, c_ctrl); + + /* Re-initialize the completion */ + reinit_completion(&cci_dev->cci_master_info[master].reset_complete); + reinit_completion(&cci_dev->cci_master_info[master].rd_done); + for (i = 0; i < NUM_QUEUES; i++) + reinit_completion( + &cci_dev->cci_master_info[master].report_q[i]); + + /* Enable Regulators and IRQ*/ + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_LOWSVS_VOTE, true); + if (rc < 0) { + CAM_DBG(CAM_CCI, "request platform resources failed"); + goto platform_enable_failed; + } + + cci_dev->hw_version = cam_io_r_mb(base + + CCI_HW_VERSION_ADDR); + CAM_DBG(CAM_CCI, "hw_version = 0x%x", cci_dev->hw_version); + + cci_dev->payload_size = + MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; + cci_dev->support_seq_write = 1; + + for (i = 0; i < NUM_MASTERS; i++) { + for (j = 0; j < NUM_QUEUES; j++) { + if (j == QUEUE_0) + cci_dev->cci_i2c_queue_info[i][j].max_queue_size + = CCI_I2C_QUEUE_0_SIZE; + else + cci_dev->cci_i2c_queue_info[i][j].max_queue_size + = CCI_I2C_QUEUE_1_SIZE; + + CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0 : %d Q1 : %d", i, + cci_dev->cci_i2c_queue_info[i][j].max_queue_size, + cci_dev->cci_i2c_queue_info[i][j].max_queue_size); + } + } + + cci_dev->cci_master_info[master].reset_pending = TRUE; + cam_io_w_mb(CCI_RESET_CMD_RMSK, base + + CCI_RESET_CMD_ADDR); + cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) { + CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); + if (rc == 0) + rc = -ETIMEDOUT; + goto reset_complete_failed; + } + for (i = 0; i < MASTER_MAX; i++) + cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; + cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, + base + CCI_IRQ_MASK_0_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, + base + CCI_IRQ_CLEAR_0_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, + base + CCI_IRQ_MASK_1_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, + base + CCI_IRQ_CLEAR_1_ADDR); + cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + for (i = 0; i < MASTER_MAX; i++) { + if (!cci_dev->write_wq[i]) { + CAM_ERR(CAM_CCI, "Failed to flush write wq"); + rc = -ENOMEM; + goto reset_complete_failed; + } else { + flush_workqueue(cci_dev->write_wq[i]); + } + } + + /* Set RD FIFO threshold for M0 & M1 */ + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M0_RD_THRESHOLD_ADDR); + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M1_RD_THRESHOLD_ADDR); + + cci_dev->cci_state = CCI_STATE_ENABLED; + + return 0; + +reset_complete_failed: + cam_soc_util_disable_platform_resource(soc_info, 1, 1); + +platform_enable_failed: + cci_dev->ref_count--; + cam_cpas_stop(cci_dev->cpas_handle); + + return rc; +} + +void cam_cci_soc_remove(struct platform_device *pdev, + struct cci_device *cci_dev) +{ + struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; + + cam_soc_util_release_platform_resource(soc_info); +} + +static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) +{ + uint8_t i = 0, j = 0; + + for (i = 0; i < NUM_MASTERS; i++) { + new_cci_dev->cci_master_info[i].status = 0; + new_cci_dev->cci_master_info[i].is_first_req = true; + mutex_init(&new_cci_dev->cci_master_info[i].mutex); + sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); + spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); + init_completion( + &new_cci_dev->cci_master_info[i].reset_complete); + init_completion( + &new_cci_dev->cci_master_info[i].th_complete); + init_completion( + &new_cci_dev->cci_master_info[i].rd_done); + + for (j = 0; j < NUM_QUEUES; j++) { + mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]); + init_completion( + &new_cci_dev->cci_master_info[i].report_q[j]); + spin_lock_init( + &new_cci_dev->cci_master_info[i].lock_q[j]); + } + } + spin_lock_init(&new_cci_dev->lock_status); +} + +static void cam_cci_init_default_clk_params(struct cci_device *cci_dev, + uint8_t index) +{ + /* default clock params are for 100Khz */ + cci_dev->cci_clk_params[index].hw_thigh = 201; + cci_dev->cci_clk_params[index].hw_tlow = 174; + cci_dev->cci_clk_params[index].hw_tsu_sto = 204; + cci_dev->cci_clk_params[index].hw_tsu_sta = 231; + cci_dev->cci_clk_params[index].hw_thd_dat = 22; + cci_dev->cci_clk_params[index].hw_thd_sta = 162; + cci_dev->cci_clk_params[index].hw_tbuf = 227; + cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0; + cci_dev->cci_clk_params[index].hw_trdhld = 6; + cci_dev->cci_clk_params[index].hw_tsp = 3; + cci_dev->cci_clk_params[index].cci_clk_src = 37500000; +} + +static void cam_cci_init_clk_params(struct cci_device *cci_dev) +{ + int32_t rc = 0; + uint32_t val = 0; + uint8_t count = 0; + struct device_node *of_node = cci_dev->v4l2_dev_str.pdev->dev.of_node; + struct device_node *src_node = NULL; + + for (count = 0; count < I2C_MAX_MODES; count++) { + + if (count == I2C_STANDARD_MODE) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_standard_mode"); + else if (count == I2C_FAST_MODE) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_fast_mode"); + else if (count == I2C_FAST_PLUS_MODE) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_fast_plus_mode"); + else + src_node = of_find_node_by_name(of_node, + "qcom,i2c_custom_mode"); + + rc = of_property_read_u32(src_node, "hw-thigh", &val); + CAM_DBG(CAM_CCI, "hw-thigh %d, rc %d", val, rc); + if (!rc) { + cci_dev->cci_clk_params[count].hw_thigh = val; + rc = of_property_read_u32(src_node, "hw-tlow", + &val); + CAM_DBG(CAM_CCI, "hw-tlow %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tlow = val; + rc = of_property_read_u32(src_node, "hw-tsu-sto", + &val); + CAM_DBG(CAM_CCI, "hw-tsu-sto %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sto = val; + rc = of_property_read_u32(src_node, "hw-tsu-sta", + &val); + CAM_DBG(CAM_CCI, "hw-tsu-sta %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sta = val; + rc = of_property_read_u32(src_node, "hw-thd-dat", + &val); + CAM_DBG(CAM_CCI, "hw-thd-dat %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_dat = val; + rc = of_property_read_u32(src_node, "hw-thd-sta", + &val); + CAM_DBG(CAM_CCI, "hw-thd-sta %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_sta = val; + rc = of_property_read_u32(src_node, "hw-tbuf", + &val); + CAM_DBG(CAM_CCI, "hw-tbuf %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tbuf = val; + rc = of_property_read_u32(src_node, + "hw-scl-stretch-en", &val); + CAM_DBG(CAM_CCI, "hw-scl-stretch-en %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_scl_stretch_en = val; + rc = of_property_read_u32(src_node, "hw-trdhld", + &val); + CAM_DBG(CAM_CCI, "hw-trdhld %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_trdhld = val; + rc = of_property_read_u32(src_node, "hw-tsp", + &val); + CAM_DBG(CAM_CCI, "hw-tsp %d, rc %d", val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsp = val; + val = 0; + rc = of_property_read_u32(src_node, "cci-clk-src", + &val); + CAM_DBG(CAM_CCI, "cci-clk-src %d, rc %d", val, rc); + cci_dev->cci_clk_params[count].cci_clk_src = val; + } else + cam_cci_init_default_clk_params(cci_dev, count); + + of_node_put(src_node); + } +} + +int cam_cci_parse_dt_info(struct platform_device *pdev, + struct cci_device *new_cci_dev) +{ + int rc = 0, i = 0; + struct cam_hw_soc_info *soc_info = + &new_cci_dev->soc_info; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Parsing DT data failed:%d", rc); + return -EINVAL; + } + + new_cci_dev->ref_count = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, + cam_cci_irq, new_cci_dev); + if (rc < 0) { + CAM_ERR(CAM_CCI, "requesting platform resources failed:%d", rc); + return -EINVAL; + } + new_cci_dev->v4l2_dev_str.pdev = pdev; + cam_cci_init_cci_params(new_cci_dev); + cam_cci_init_clk_params(new_cci_dev); + + rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (rc) + CAM_ERR(CAM_CCI, "failed to add child nodes, rc=%d", rc); + + for (i = 0; i < MASTER_MAX; i++) { + new_cci_dev->write_wq[i] = create_singlethread_workqueue( + "cam_cci_wq"); + if (!new_cci_dev->write_wq[i]) + CAM_ERR(CAM_CCI, "Failed to create write wq"); + } + CAM_DBG(CAM_CCI, "Exit"); + return 0; +} + +int cam_cci_soc_release(struct cci_device *cci_dev) +{ + uint8_t i = 0, rc = 0; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + + if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { + CAM_ERR(CAM_CCI, "invalid ref count %d / cci state %d", + cci_dev->ref_count, cci_dev->cci_state); + return -EINVAL; + } + if (--cci_dev->ref_count) { + CAM_DBG(CAM_CCI, "ref_count Exit %d", cci_dev->ref_count); + return 0; + } + for (i = 0; i < MASTER_MAX; i++) + if (cci_dev->write_wq[i]) + flush_workqueue(cci_dev->write_wq[i]); + + for (i = 0; i < MASTER_MAX; i++) + cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CCI, "platform resources disable failed, rc=%d", + rc); + return rc; + } + + cci_dev->cci_state = CCI_STATE_DISABLED; + cci_dev->cycles_per_us = 0; + + cam_cpas_stop(cci_dev->cpas_handle); + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h new file mode 100644 index 000000000000..f0cdfe822cd3 --- /dev/null +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CCI_SOC_H_ +#define _CAM_CCI_SOC_H_ + +#include "cam_cci_core.h" +#include "cam_soc_util.h" + +/** + * @sd: V4L2 sub device + * @c_ctrl: CCI control structure + * + * This API initializes the CCI and acquires SOC resources + */ +int cam_cci_init(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl); + +/** + * @cci_dev: CCI device structure + * + * This API releases the CCI and its SOC resources + */ +int cam_cci_soc_release(struct cci_device *cci_dev); + +/** + * @pdev: Platform device + * @new_cci_dev: CCI device structure + * + * This API parses CCI device tree + */ +int cam_cci_parse_dt_info(struct platform_device *pdev, + struct cci_device *new_cci_dev); + +/** + * @pdev: Platform device + * @cci_dev: CCI device structure + * + * This API puts all SOC resources + */ +void cam_cci_soc_remove(struct platform_device *pdev, + struct cci_device *cci_dev); +#endif /* _CAM_CCI_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/Makefile b/drivers/cam_sensor_module/cam_csiphy/Makefile new file mode 100644 index 000000000000..88ab6ed9a1bb --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy_soc.o cam_csiphy_dev.o cam_csiphy_core.o diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c new file mode 100644 index 000000000000..adf9ef82ee45 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -0,0 +1,971 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_csiphy_core.h" +#include "cam_csiphy_dev.h" +#include "cam_csiphy_soc.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + + +#include +#include + +#define SCM_SVC_CAMERASS 0x18 +#define SECURE_SYSCALL_ID 0x6 +#define SECURE_SYSCALL_ID_2 0x7 + +#define LANE_MASK_2PH 0x1F +#define LANE_MASK_3PH 0x7 + +static int csiphy_dump; +module_param(csiphy_dump, int, 0644); + +static int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, + bool protect, int32_t offset) +{ + struct scm_desc desc = {0}; + + if (offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid CSIPHY offset"); + return -EINVAL; + } + + desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); + desc.args[0] = protect; + desc.args[1] = csiphy_dev->csiphy_cpas_cp_reg_mask[offset]; + + if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID_2), + &desc)) { + CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed"); + return -EINVAL; + } + + return 0; +} + +int32_t cam_csiphy_get_instance_offset( + struct csiphy_device *csiphy_dev, + int32_t dev_handle) +{ + int32_t i; + + if (csiphy_dev->acquire_count > + CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid acquire count"); + return -EINVAL; + } + + for (i = 0; i < csiphy_dev->acquire_count; i++) { + if (dev_handle == + csiphy_dev->bridge_intf.device_hdl[i]) + break; + } + + return i; +} + +void cam_csiphy_query_cap(struct csiphy_device *csiphy_dev, + struct cam_csiphy_query_cap *csiphy_cap) +{ + struct cam_hw_soc_info *soc_info = &csiphy_dev->soc_info; + + csiphy_cap->slot_info = soc_info->index; + csiphy_cap->version = csiphy_dev->hw_version; + csiphy_cap->clk_lane = csiphy_dev->clk_lane; +} + +void cam_csiphy_reset(struct csiphy_device *csiphy_dev) +{ + int32_t i; + void __iomem *base = NULL; + uint32_t size = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_reset_array_size; + struct cam_hw_soc_info *soc_info = &csiphy_dev->soc_info; + + base = soc_info->reg_map[0].mem_base; + + for (i = 0; i < size; i++) { + cam_io_w_mb( + csiphy_dev->ctrl_reg->csiphy_reset_reg[i].reg_data, + base + + csiphy_dev->ctrl_reg->csiphy_reset_reg[i].reg_addr); + + usleep_range(csiphy_dev->ctrl_reg->csiphy_reset_reg[i].delay + * 1000, csiphy_dev->ctrl_reg->csiphy_reset_reg[i].delay + * 1000 + 10); + } +} + +int32_t cam_csiphy_update_secure_info( + struct csiphy_device *csiphy_dev, + struct cam_csiphy_info *cam_cmd_csiphy_info, + struct cam_config_dev_cmd *cfg_dev) +{ + uint32_t clock_lane, adj_lane_mask, temp; + int32_t offset; + + if (csiphy_dev->acquire_count >= + CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid acquire count"); + return -EINVAL; + } + + offset = cam_csiphy_get_instance_offset(csiphy_dev, + cfg_dev->dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + return -EINVAL; + } + + if (cam_cmd_csiphy_info->combo_mode) + clock_lane = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_combo_ck_ln; + else + clock_lane = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_clock_lane; + + adj_lane_mask = cam_cmd_csiphy_info->lane_mask & LANE_MASK_2PH & + ~clock_lane; + temp = adj_lane_mask & (clock_lane - 1); + adj_lane_mask = + ((adj_lane_mask & (~(clock_lane - 1))) >> 1) | temp; + + if (cam_cmd_csiphy_info->csiphy_3phase) + adj_lane_mask = cam_cmd_csiphy_info->lane_mask & LANE_MASK_3PH; + + csiphy_dev->csiphy_info.secure_mode[offset] = 1; + + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = + adj_lane_mask << (csiphy_dev->soc_info.index * + (CAM_CSIPHY_MAX_DPHY_LANES + CAM_CSIPHY_MAX_CPHY_LANES) + + (!cam_cmd_csiphy_info->csiphy_3phase) * + (CAM_CSIPHY_MAX_CPHY_LANES)); + + return 0; +} + +int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, + struct cam_config_dev_cmd *cfg_dev) +{ + int32_t rc = 0; + uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uint32_t *cmd_buf = NULL; + struct cam_csiphy_info *cam_cmd_csiphy_info = NULL; + size_t len; + size_t remain_len; + + if (!cfg_dev || !csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "Invalid Args"); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle, + &generic_pkt_ptr, &len); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc); + return rc; + } + + remain_len = len; + if ((sizeof(struct cam_packet) > len) || + ((size_t)cfg_dev->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_CSIPHY, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len); + rc = -EINVAL; + return rc; + } + + remain_len -= (size_t)cfg_dev->offset; + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)cfg_dev->offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_CSIPHY, "Invalid packet params"); + rc = -EINVAL; + return rc; + } + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset / 4); + + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &generic_ptr, &len); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, + "Failed to get cmd buf Mem address : %d", rc); + return rc; + } + + if ((len < sizeof(struct cam_csiphy_info)) || + (cmd_desc->offset > (len - sizeof(struct cam_csiphy_info)))) { + CAM_ERR(CAM_CSIPHY, + "Not enough buffer provided for cam_cisphy_info"); + rc = -EINVAL; + return rc; + } + + cmd_buf = (uint32_t *)generic_ptr; + cmd_buf += cmd_desc->offset / 4; + cam_cmd_csiphy_info = (struct cam_csiphy_info *)cmd_buf; + + csiphy_dev->config_count++; + csiphy_dev->csiphy_info.lane_cnt += cam_cmd_csiphy_info->lane_cnt; + csiphy_dev->csiphy_info.lane_mask |= cam_cmd_csiphy_info->lane_mask; + csiphy_dev->csiphy_info.csiphy_3phase = + cam_cmd_csiphy_info->csiphy_3phase; + csiphy_dev->csiphy_info.combo_mode |= cam_cmd_csiphy_info->combo_mode; + if (cam_cmd_csiphy_info->combo_mode == 1) { + csiphy_dev->csiphy_info.settle_time_combo_sensor = + cam_cmd_csiphy_info->settle_time; + csiphy_dev->csiphy_info.data_rate_combo_sensor = + cam_cmd_csiphy_info->data_rate; + } else { + csiphy_dev->csiphy_info.settle_time = + cam_cmd_csiphy_info->settle_time; + csiphy_dev->csiphy_info.data_rate = + cam_cmd_csiphy_info->data_rate; + } + + + if (cam_cmd_csiphy_info->secure_mode == 1) + cam_csiphy_update_secure_info(csiphy_dev, + cam_cmd_csiphy_info, cfg_dev); + + return rc; +} + +void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev) +{ + int32_t i; + void __iomem *csiphybase = + csiphy_dev->soc_info.reg_map[0].mem_base; + + for (i = 0; i < csiphy_dev->num_irq_registers; i++) + cam_io_w_mb( + csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_data, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_addr); +} + +void cam_csiphy_cphy_data_rate_config(struct csiphy_device *csiphy_device) +{ + int i = 0, j = 0; + uint64_t phy_data_rate = 0; + void __iomem *csiphybase = NULL; + ssize_t num_table_entries = 0; + struct data_rate_settings_t *settings_table = NULL; + + if ((csiphy_device == NULL) || + (csiphy_device->ctrl_reg == NULL) || + (csiphy_device->ctrl_reg->data_rates_settings_table == NULL)) { + CAM_DBG(CAM_CSIPHY, + "Data rate specific register table not found"); + return; + } + + phy_data_rate = csiphy_device->csiphy_info.data_rate; + csiphybase = + csiphy_device->soc_info.reg_map[0].mem_base; + settings_table = + csiphy_device->ctrl_reg->data_rates_settings_table; + num_table_entries = + settings_table->num_data_rate_settings; + + CAM_DBG(CAM_CSIPHY, "required data rate : %llu", phy_data_rate); + for (i = 0; i < num_table_entries; i++) { + struct data_rate_reg_info_t *drate_settings = + settings_table->data_rate_settings; + uint64_t bandwidth = + drate_settings[i].bandwidth; + ssize_t num_reg_entries = + drate_settings[i].data_rate_reg_array_size; + + if (phy_data_rate > bandwidth) { + CAM_DBG(CAM_CSIPHY, + "Skipping table [%d] %llu required: %llu", + i, bandwidth, phy_data_rate); + continue; + } + + CAM_DBG(CAM_CSIPHY, + "table[%d] BW : %llu Selected", i, bandwidth); + for (j = 0; j < num_reg_entries; j++) { + uint32_t reg_addr = + drate_settings[i].csiphy_data_rate_regs[j].reg_addr; + + uint32_t reg_data = + drate_settings[i].csiphy_data_rate_regs[j].reg_data; + + CAM_DBG(CAM_CSIPHY, + "writing reg : %x val : %x", + reg_addr, reg_data); + cam_io_w_mb(reg_data, + csiphybase + reg_addr); + } + break; + } +} + +void cam_csiphy_cphy_irq_disable(struct csiphy_device *csiphy_dev) +{ + int32_t i; + void __iomem *csiphybase = + csiphy_dev->soc_info.reg_map[0].mem_base; + + for (i = 0; i < csiphy_dev->num_irq_registers; i++) + cam_io_w_mb(0x0, csiphybase + + csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_addr); +} + +irqreturn_t cam_csiphy_irq(int irq_num, void *data) +{ + uint32_t irq; + uint8_t i; + struct csiphy_device *csiphy_dev = + (struct csiphy_device *)data; + struct cam_hw_soc_info *soc_info = NULL; + struct csiphy_reg_parms_t *csiphy_reg = NULL; + void __iomem *base = NULL; + + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "Invalid Args"); + return IRQ_NONE; + } + + soc_info = &csiphy_dev->soc_info; + base = csiphy_dev->soc_info.reg_map[0].mem_base; + csiphy_reg = &csiphy_dev->ctrl_reg->csiphy_reg; + + for (i = 0; i < csiphy_dev->num_irq_registers; i++) { + irq = cam_io_r(base + + csiphy_reg->mipi_csiphy_interrupt_status0_addr + + (0x4 * i)); + cam_io_w_mb(irq, base + + csiphy_reg->mipi_csiphy_interrupt_clear0_addr + + (0x4 * i)); + CAM_ERR_RATE_LIMIT(CAM_CSIPHY, + "CSIPHY%d_IRQ_STATUS_ADDR%d = 0x%x", + soc_info->index, i, irq); + cam_io_w_mb(0x0, base + + csiphy_reg->mipi_csiphy_interrupt_clear0_addr + + (0x4 * i)); + } + cam_io_w_mb(0x1, base + csiphy_reg->mipi_csiphy_glbl_irq_cmd_addr); + cam_io_w_mb(0x0, base + csiphy_reg->mipi_csiphy_glbl_irq_cmd_addr); + + return IRQ_HANDLED; +} + +int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) +{ + int32_t rc = 0; + uint32_t lane_enable = 0, mask = 1, size = 0; + uint16_t lane_mask = 0, i = 0, cfg_size = 0, temp = 0; + uint8_t lane_cnt, lane_pos = 0; + uint16_t settle_cnt = 0; + void __iomem *csiphybase; + struct csiphy_reg_t *csiphy_common_reg = NULL; + struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE]; + + lane_cnt = csiphy_dev->csiphy_info.lane_cnt; + csiphybase = csiphy_dev->soc_info.reg_map[0].mem_base; + + if (!csiphybase) { + CAM_ERR(CAM_CSIPHY, "csiphybase NULL"); + return -EINVAL; + } + + if (!csiphy_dev->csiphy_info.csiphy_3phase) { + if (csiphy_dev->csiphy_info.combo_mode == 1) + reg_array = + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg; + else + reg_array = + csiphy_dev->ctrl_reg->csiphy_2ph_reg; + csiphy_dev->num_irq_registers = 11; + cfg_size = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_config_array_size; + + lane_mask = csiphy_dev->csiphy_info.lane_mask & LANE_MASK_2PH; + for (i = 0; i < MAX_DPHY_DATA_LN; i++) { + if (mask == 0x2) { + if (lane_mask & mask) + lane_enable |= 0x80; + i--; + } else if (lane_mask & mask) { + lane_enable |= 0x1 << (i<<1); + } + mask <<= 1; + } + } else { + if (csiphy_dev->csiphy_info.combo_mode == 1) { + if (csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg) + reg_array = + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg; + else { + reg_array = + csiphy_dev->ctrl_reg->csiphy_3ph_reg; + CAM_ERR(CAM_CSIPHY, + "Unsupported configuration, Falling back to CPHY mode"); + } + } else + reg_array = + csiphy_dev->ctrl_reg->csiphy_3ph_reg; + csiphy_dev->num_irq_registers = 11; + cfg_size = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_3ph_config_array_size; + + lane_mask = csiphy_dev->csiphy_info.lane_mask & LANE_MASK_3PH; + mask = lane_mask; + while (mask != 0) { + temp = (i << 1)+1; + lane_enable |= ((mask & 0x1) << temp); + mask >>= 1; + i++; + } + } + + size = csiphy_dev->ctrl_reg->csiphy_reg.csiphy_common_array_size; + + for (i = 0; i < size; i++) { + csiphy_common_reg = &csiphy_dev->ctrl_reg->csiphy_common_reg[i]; + switch (csiphy_common_reg->csiphy_param_type) { + case CSIPHY_LANE_ENABLE: + cam_io_w_mb(lane_enable, + csiphybase + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + break; + case CSIPHY_DEFAULT_PARAMS: + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + break; + case CSIPHY_2PH_REGS: + if (!csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; + case CSIPHY_3PH_REGS: + if (csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; + default: + break; + } + } + + while (lane_mask) { + if (!(lane_mask & 0x1)) { + lane_pos++; + lane_mask >>= 1; + continue; + } + + settle_cnt = (csiphy_dev->csiphy_info.settle_time / 200000000); + if (csiphy_dev->csiphy_info.combo_mode == 1 && + (lane_pos >= 3)) + settle_cnt = + (csiphy_dev->csiphy_info.settle_time_combo_sensor / + 200000000); + for (i = 0; i < cfg_size; i++) { + switch (reg_array[lane_pos][i].csiphy_param_type) { + case CSIPHY_LANE_ENABLE: + cam_io_w_mb(lane_enable, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + case CSIPHY_DEFAULT_PARAMS: + cam_io_w_mb(reg_array[lane_pos][i].reg_data, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + case CSIPHY_SETTLE_CNT_LOWER_BYTE: + cam_io_w_mb(settle_cnt & 0xFF, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + case CSIPHY_SETTLE_CNT_HIGHER_BYTE: + cam_io_w_mb((settle_cnt >> 8) & 0xFF, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + default: + CAM_DBG(CAM_CSIPHY, "Do Nothing"); + break; + } + if (reg_array[lane_pos][i].delay > 0) { + usleep_range(reg_array[lane_pos][i].delay*1000, + reg_array[lane_pos][i].delay*1000 + 10); + } + } + lane_mask >>= 1; + lane_pos++; + } + + if (csiphy_dev->csiphy_info.csiphy_3phase) + cam_csiphy_cphy_data_rate_config(csiphy_dev); + + cam_csiphy_cphy_irq_config(csiphy_dev); + + return rc; +} + +void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) +{ + struct cam_hw_soc_info *soc_info; + int32_t i = 0; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) + return; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + soc_info = &csiphy_dev->soc_info; + + for (i = 0; i < csiphy_dev->acquire_count; i++) { + if (csiphy_dev->csiphy_info.secure_mode[i]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, i); + + csiphy_dev->csiphy_info.secure_mode[i] = + CAM_SECURE_MODE_NON_SECURE; + + csiphy_dev->csiphy_cpas_cp_reg_mask[i] = 0; + } + + cam_csiphy_reset(csiphy_dev); + cam_soc_util_disable_platform_resource(soc_info, true, true); + + cam_cpas_stop(csiphy_dev->cpas_handle); + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; + } + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_ACQUIRE) { + if (csiphy_dev->bridge_intf.device_hdl[0] != -1) + cam_destroy_device_hdl( + csiphy_dev->bridge_intf.device_hdl[0]); + if (csiphy_dev->bridge_intf.device_hdl[1] != -1) + cam_destroy_device_hdl( + csiphy_dev->bridge_intf.device_hdl[1]); + csiphy_dev->bridge_intf.device_hdl[0] = -1; + csiphy_dev->bridge_intf.device_hdl[1] = -1; + csiphy_dev->bridge_intf.link_hdl[0] = -1; + csiphy_dev->bridge_intf.link_hdl[1] = -1; + csiphy_dev->bridge_intf.session_hdl[0] = -1; + csiphy_dev->bridge_intf.session_hdl[1] = -1; + } + + csiphy_dev->ref_count = 0; + csiphy_dev->is_acquired_dev_combo_mode = 0; + csiphy_dev->acquire_count = 0; + csiphy_dev->start_dev_count = 0; + csiphy_dev->csiphy_state = CAM_CSIPHY_INIT; +} + +static int32_t cam_csiphy_external_cmd(struct csiphy_device *csiphy_dev, + struct cam_config_dev_cmd *p_submit_cmd) +{ + struct cam_csiphy_info cam_cmd_csiphy_info; + int32_t rc = 0; + + if (copy_from_user(&cam_cmd_csiphy_info, + u64_to_user_ptr(p_submit_cmd->packet_handle), + sizeof(struct cam_csiphy_info))) { + CAM_ERR(CAM_CSIPHY, "failed to copy cam_csiphy_info\n"); + rc = -EFAULT; + } else { + csiphy_dev->csiphy_info.lane_cnt = + cam_cmd_csiphy_info.lane_cnt; + csiphy_dev->csiphy_info.lane_cnt = + cam_cmd_csiphy_info.lane_cnt; + csiphy_dev->csiphy_info.lane_mask = + cam_cmd_csiphy_info.lane_mask; + csiphy_dev->csiphy_info.csiphy_3phase = + cam_cmd_csiphy_info.csiphy_3phase; + csiphy_dev->csiphy_info.combo_mode = + cam_cmd_csiphy_info.combo_mode; + csiphy_dev->csiphy_info.settle_time = + cam_cmd_csiphy_info.settle_time; + csiphy_dev->csiphy_info.data_rate = + cam_cmd_csiphy_info.data_rate; + CAM_DBG(CAM_CSIPHY, + "%s CONFIG_DEV_EXT settle_time= %lld lane_cnt=%d lane_mask=0x%x", + __func__, + csiphy_dev->csiphy_info.settle_time, + csiphy_dev->csiphy_info.lane_cnt, + csiphy_dev->csiphy_info.lane_mask); + } + + return rc; +} + +int32_t cam_csiphy_core_cfg(void *phy_dev, + void *arg) +{ + struct csiphy_device *csiphy_dev = + (struct csiphy_device *)phy_dev; + struct intf_params *bridge_intf = NULL; + struct cam_control *cmd = (struct cam_control *)arg; + int32_t rc = 0; + + if (!csiphy_dev || !cmd) { + CAM_ERR(CAM_CSIPHY, "Invalid input args"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_CSIPHY, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + CAM_DBG(CAM_CSIPHY, "Opcode received: %d", cmd->op_code); + mutex_lock(&csiphy_dev->mutex); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev csiphy_acq_dev; + struct cam_csiphy_acquire_dev_info csiphy_acq_params; + + struct cam_create_dev_hdl bridge_params; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + CAM_ERR(CAM_CSIPHY, + "Not in right state to acquire : %d", + csiphy_dev->csiphy_state); + rc = -EINVAL; + goto release_mutex; + } + + rc = copy_from_user(&csiphy_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(csiphy_acq_dev)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + goto release_mutex; + } + + csiphy_acq_params.combo_mode = 0; + + if (copy_from_user(&csiphy_acq_params, + u64_to_user_ptr(csiphy_acq_dev.info_handle), + sizeof(csiphy_acq_params))) { + CAM_ERR(CAM_CSIPHY, + "Failed copying from User"); + goto release_mutex; + } + + if (csiphy_dev->acquire_count == 2) { + CAM_ERR(CAM_CSIPHY, + "CSIPHY device do not allow more than 2 acquires"); + rc = -EINVAL; + goto release_mutex; + } + + if ((csiphy_acq_params.combo_mode == 1) && + (csiphy_dev->is_acquired_dev_combo_mode == 1)) { + CAM_ERR(CAM_CSIPHY, + "Multiple Combo Acq are not allowed: cm: %d, acm: %d", + csiphy_acq_params.combo_mode, + csiphy_dev->is_acquired_dev_combo_mode); + rc = -EINVAL; + goto release_mutex; + } + + if ((csiphy_acq_params.combo_mode != 1) && + (csiphy_dev->is_acquired_dev_combo_mode != 1) && + (csiphy_dev->acquire_count == 1)) { + CAM_ERR(CAM_CSIPHY, + "Multiple Acquires are not allowed cm: %d acm: %d", + csiphy_acq_params.combo_mode, + csiphy_dev->is_acquired_dev_combo_mode); + rc = -EINVAL; + goto release_mutex; + } + + bridge_params.ops = NULL; + bridge_params.session_hdl = csiphy_acq_dev.session_handle; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = csiphy_dev; + + if (csiphy_acq_params.combo_mode >= 2) { + CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d", + csiphy_acq_params.combo_mode); + rc = -EINVAL; + goto release_mutex; + } + + csiphy_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + bridge_intf = &csiphy_dev->bridge_intf; + bridge_intf->device_hdl[csiphy_acq_params.combo_mode] + = csiphy_acq_dev.device_handle; + bridge_intf->session_hdl[csiphy_acq_params.combo_mode] = + csiphy_acq_dev.session_handle; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &csiphy_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + rc = -EINVAL; + goto release_mutex; + } + if (csiphy_acq_params.combo_mode == 1) + csiphy_dev->is_acquired_dev_combo_mode = 1; + + csiphy_dev->acquire_count++; + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; + } + break; + case CAM_QUERY_CAP: { + struct cam_csiphy_query_cap csiphy_cap = {0}; + + cam_csiphy_query_cap(csiphy_dev, &csiphy_cap); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &csiphy_cap, sizeof(struct cam_csiphy_query_cap))) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + rc = -EINVAL; + goto release_mutex; + } + } + break; + case CAM_STOP_DEV: { + int32_t offset, rc = 0; + struct cam_start_stop_dev_cmd config; + + rc = copy_from_user(&config, (void __user *)cmd->handle, + sizeof(config)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + goto release_mutex; + } + + if ((csiphy_dev->csiphy_state != CAM_CSIPHY_START) || + !csiphy_dev->start_dev_count) { + CAM_ERR(CAM_CSIPHY, "Not in right state to stop : %d", + csiphy_dev->csiphy_state); + goto release_mutex; + } + + offset = cam_csiphy_get_instance_offset(csiphy_dev, + config.dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + goto release_mutex; + } + + if (--csiphy_dev->start_dev_count) { + CAM_DBG(CAM_CSIPHY, "Stop Dev ref Cnt: %d", + csiphy_dev->start_dev_count); + if (csiphy_dev->csiphy_info.secure_mode[offset]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0; + + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode[offset]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0x0; + + rc = cam_csiphy_disable_hw(csiphy_dev); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "Failed in csiphy release"); + + rc = cam_cpas_stop(csiphy_dev->cpas_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc); + + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; + } + break; + case CAM_RELEASE_DEV: { + struct cam_release_dev_cmd release; + + if (!csiphy_dev->acquire_count) { + CAM_ERR(CAM_CSIPHY, "No valid devices to release"); + rc = -EINVAL; + goto release_mutex; + } + + if (copy_from_user(&release, + u64_to_user_ptr(cmd->handle), + sizeof(release))) { + rc = -EFAULT; + goto release_mutex; + } + + rc = cam_destroy_device_hdl(release.dev_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "destroying the device hdl"); + if (release.dev_handle == + csiphy_dev->bridge_intf.device_hdl[0]) { + csiphy_dev->bridge_intf.device_hdl[0] = -1; + csiphy_dev->bridge_intf.link_hdl[0] = -1; + csiphy_dev->bridge_intf.session_hdl[0] = -1; + } else { + csiphy_dev->bridge_intf.device_hdl[1] = -1; + csiphy_dev->bridge_intf.link_hdl[1] = -1; + csiphy_dev->bridge_intf.session_hdl[1] = -1; + csiphy_dev->is_acquired_dev_combo_mode = 0; + } + + csiphy_dev->config_count--; + csiphy_dev->acquire_count--; + + if (csiphy_dev->acquire_count == 0) + csiphy_dev->csiphy_state = CAM_CSIPHY_INIT; + + if (csiphy_dev->config_count == 0) { + CAM_DBG(CAM_CSIPHY, "reset csiphy_info"); + csiphy_dev->csiphy_info.lane_mask = 0; + csiphy_dev->csiphy_info.lane_cnt = 0; + csiphy_dev->csiphy_info.combo_mode = 0; + } + } + break; + case CAM_CONFIG_DEV: { + struct cam_config_dev_cmd config; + + if (copy_from_user(&config, + u64_to_user_ptr(cmd->handle), + sizeof(config))) { + rc = -EFAULT; + } else { + rc = cam_cmd_buf_parser(csiphy_dev, &config); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Fail in cmd buf parser"); + goto release_mutex; + } + } + break; + } + case CAM_START_DEV: { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + struct cam_start_stop_dev_cmd config; + int32_t offset; + + rc = copy_from_user(&config, (void __user *)cmd->handle, + sizeof(config)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + goto release_mutex; + } + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + csiphy_dev->start_dev_count++; + goto release_mutex; + } + + offset = cam_csiphy_get_instance_offset(csiphy_dev, + config.dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + goto release_mutex; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(csiphy_dev->cpas_handle, + &ahb_vote, &axi_vote); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "voting CPAS: %d", rc); + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode[offset] == 1) { + rc = cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_SECURE, offset); + if (rc < 0) { + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + cam_cpas_stop(csiphy_dev->cpas_handle); + goto release_mutex; + } + } + + rc = cam_csiphy_enable_hw(csiphy_dev); + if (rc != 0) { + CAM_ERR(CAM_CSIPHY, "cam_csiphy_enable_hw failed"); + cam_cpas_stop(csiphy_dev->cpas_handle); + goto release_mutex; + } + rc = cam_csiphy_config_dev(csiphy_dev); + if (csiphy_dump == 1) + cam_csiphy_mem_dmp(&csiphy_dev->soc_info); + + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "cam_csiphy_config_dev failed"); + cam_csiphy_disable_hw(csiphy_dev); + cam_cpas_stop(csiphy_dev->cpas_handle); + goto release_mutex; + } + csiphy_dev->start_dev_count++; + csiphy_dev->csiphy_state = CAM_CSIPHY_START; + } + break; + case CAM_CONFIG_DEV_EXTERNAL: { + struct cam_config_dev_cmd submit_cmd; + + if (copy_from_user(&submit_cmd, + u64_to_user_ptr(cmd->handle), + sizeof(struct cam_config_dev_cmd))) { + CAM_ERR(CAM_CSIPHY, "failed copy config ext\n"); + rc = -EFAULT; + } else { + rc = cam_csiphy_external_cmd(csiphy_dev, &submit_cmd); + } + break; + } + default: + CAM_ERR(CAM_CSIPHY, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + goto release_mutex; + } + +release_mutex: + mutex_unlock(&csiphy_dev->mutex); + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h new file mode 100644 index 000000000000..237fa787f226 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_CORE_H_ +#define _CAM_CSIPHY_CORE_H_ + +#include +#include "cam_csiphy_dev.h" +#include +#include +#include + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API programs CSIPhy IRQ registers + */ +void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API resets CSIPhy hardware + */ +void cam_csiphy_reset(struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * @arg: Camera control command argument + * + * This API handles the camera control argument reached to CSIPhy + */ +int cam_csiphy_core_cfg(void *csiphy_dev, void *arg); + +/** + * @irq_num: IRQ number + * @data: CSIPhy device structure + * + * This API handles CSIPhy IRQs + */ +irqreturn_t cam_csiphy_irq(int irq_num, void *data); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API handles the CSIPhy close + */ +void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev); + +#endif /* _CAM_CSIPHY_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c new file mode 100644 index 000000000000..3325071905ba --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_csiphy_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_csiphy_soc.h" +#include "cam_csiphy_core.h" +#include + +static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_csiphy_core_cfg(csiphy_dev, arg); + if (rc != 0) { + CAM_ERR(CAM_CSIPHY, "in configuring the device"); + return rc; + } + break; + default: + CAM_ERR(CAM_CSIPHY, "Wrong ioctl : %d", cmd); + break; + } + + return rc; +} + +static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct csiphy_device *csiphy_dev = + v4l2_get_subdevdata(sd); + + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "csiphy_dev ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&csiphy_dev->mutex); + cam_csiphy_shutdown(csiphy_dev); + mutex_unlock(&csiphy_dev->mutex); + + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_csiphy_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + int32_t rc = 0; + struct cam_control cmd_data; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_CSIPHY, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + /* All the arguments converted to 64 bit here + * Passed to the api in core.c + */ + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_csiphy_subdev_ioctl(sd, cmd, &cmd_data); + break; + default: + CAM_ERR(CAM_CSIPHY, "Invalid compat ioctl cmd: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_CSIPHY, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static struct v4l2_subdev_core_ops csiphy_subdev_core_ops = { + .ioctl = cam_csiphy_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_csiphy_subdev_compat_ioctl, +#endif +}; + +static const struct v4l2_subdev_ops csiphy_subdev_ops = { + .core = &csiphy_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops csiphy_subdev_intern_ops = { + .close = cam_csiphy_subdev_close, +}; + +static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) +{ + struct cam_cpas_register_params cpas_parms; + struct csiphy_device *new_csiphy_dev; + int32_t rc = 0; + + new_csiphy_dev = devm_kzalloc(&pdev->dev, + sizeof(struct csiphy_device), GFP_KERNEL); + if (!new_csiphy_dev) + return -ENOMEM; + + new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t), + GFP_KERNEL); + if (!new_csiphy_dev->ctrl_reg) { + devm_kfree(&pdev->dev, new_csiphy_dev); + return -ENOMEM; + } + + mutex_init(&new_csiphy_dev->mutex); + new_csiphy_dev->v4l2_dev_str.pdev = pdev; + + new_csiphy_dev->soc_info.pdev = pdev; + new_csiphy_dev->soc_info.dev = &pdev->dev; + new_csiphy_dev->soc_info.dev_name = pdev->name; + new_csiphy_dev->ref_count = 0; + + rc = cam_csiphy_parse_dt_info(pdev, new_csiphy_dev); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "DT parsing failed: %d", rc); + goto csiphy_no_resource; + } + + new_csiphy_dev->v4l2_dev_str.internal_ops = + &csiphy_subdev_intern_ops; + new_csiphy_dev->v4l2_dev_str.ops = + &csiphy_subdev_ops; + strlcpy(new_csiphy_dev->device_name, CAMX_CSIPHY_DEV_NAME, + sizeof(new_csiphy_dev->device_name)); + new_csiphy_dev->v4l2_dev_str.name = + new_csiphy_dev->device_name; + new_csiphy_dev->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + new_csiphy_dev->v4l2_dev_str.ent_function = + CAM_CSIPHY_DEVICE_TYPE; + new_csiphy_dev->v4l2_dev_str.token = + new_csiphy_dev; + + rc = cam_register_subdev(&(new_csiphy_dev->v4l2_dev_str)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "cam_register_subdev Failed rc: %d", rc); + goto csiphy_no_resource; + } + + platform_set_drvdata(pdev, &(new_csiphy_dev->v4l2_dev_str.sd)); + + new_csiphy_dev->bridge_intf.device_hdl[0] = -1; + new_csiphy_dev->bridge_intf.device_hdl[1] = -1; + new_csiphy_dev->bridge_intf.ops.get_dev_info = + NULL; + new_csiphy_dev->bridge_intf.ops.link_setup = + NULL; + new_csiphy_dev->bridge_intf.ops.apply_req = + NULL; + + new_csiphy_dev->acquire_count = 0; + new_csiphy_dev->start_dev_count = 0; + new_csiphy_dev->is_acquired_dev_combo_mode = 0; + + cpas_parms.cam_cpas_client_cb = NULL; + cpas_parms.cell_index = new_csiphy_dev->soc_info.index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = new_csiphy_dev; + + strlcpy(cpas_parms.identifier, "csiphy", CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CSIPHY, "CPAS registration failed rc: %d", rc); + goto csiphy_no_resource; + } + CAM_DBG(CAM_CSIPHY, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + new_csiphy_dev->cpas_handle = cpas_parms.client_handle; + + return rc; +csiphy_no_resource: + mutex_destroy(&new_csiphy_dev->mutex); + kfree(new_csiphy_dev->ctrl_reg); + devm_kfree(&pdev->dev, new_csiphy_dev); + return rc; +} + + +static int32_t cam_csiphy_device_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev = + platform_get_drvdata(pdev); + struct csiphy_device *csiphy_dev = + v4l2_get_subdevdata(subdev); + + CAM_INFO(CAM_CSIPHY, "device remove invoked"); + cam_cpas_unregister_client(csiphy_dev->cpas_handle); + cam_csiphy_soc_release(csiphy_dev); + mutex_lock(&csiphy_dev->mutex); + cam_csiphy_shutdown(csiphy_dev); + mutex_unlock(&csiphy_dev->mutex); + cam_unregister_subdev(&(csiphy_dev->v4l2_dev_str)); + kfree(csiphy_dev->ctrl_reg); + csiphy_dev->ctrl_reg = NULL; + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(csiphy_dev->v4l2_dev_str.sd), NULL); + devm_kfree(&pdev->dev, csiphy_dev); + + return 0; +} + +static const struct of_device_id cam_csiphy_dt_match[] = { + {.compatible = "qcom,csiphy"}, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_csiphy_dt_match); + +static struct platform_driver csiphy_driver = { + .probe = cam_csiphy_platform_probe, + .remove = cam_csiphy_device_remove, + .driver = { + .name = CAMX_CSIPHY_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_csiphy_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int32_t __init cam_csiphy_init_module(void) +{ + return platform_driver_register(&csiphy_driver); +} + +static void __exit cam_csiphy_exit_module(void) +{ + platform_driver_unregister(&csiphy_driver); +} + +module_init(cam_csiphy_init_module); +module_exit(cam_csiphy_exit_module); +MODULE_DESCRIPTION("CAM CSIPHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h new file mode 100644 index 000000000000..7453db1e0658 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_DEV_H_ +#define _CAM_CSIPHY_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +#define MAX_CSIPHY 6 +#define MAX_DPHY_DATA_LN 4 +#define MAX_LRME_V4l2_EVENTS 30 +#define CSIPHY_NUM_CLK_MAX 16 +#define MAX_CSIPHY_REG_ARRAY 70 +#define MAX_CSIPHY_CMN_REG_ARRAY 5 + +#define MAX_LANES 5 +#define MAX_SETTINGS_PER_LANE 43 +#define MAX_DATA_RATES 3 +#define MAX_DATA_RATE_REGS 30 + +#define MAX_REGULATOR 5 +#define CAMX_CSIPHY_DEV_NAME "cam-csiphy-driver" + +#define CSIPHY_POWER_UP 0 +#define CSIPHY_POWER_DOWN 1 + +#define CSIPHY_DEFAULT_PARAMS 0 +#define CSIPHY_LANE_ENABLE 1 +#define CSIPHY_SETTLE_CNT_LOWER_BYTE 2 +#define CSIPHY_SETTLE_CNT_HIGHER_BYTE 3 +#define CSIPHY_DNP_PARAMS 4 +#define CSIPHY_2PH_REGS 5 +#define CSIPHY_3PH_REGS 6 + +#define CSIPHY_MAX_INSTANCES 2 + +#define CAM_CSIPHY_MAX_DPHY_LANES 4 +#define CAM_CSIPHY_MAX_CPHY_LANES 3 + +#define ENABLE_IRQ false + +#undef CDBG +#ifdef CAM_CSIPHY_CORE_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +enum cam_csiphy_state { + CAM_CSIPHY_INIT, + CAM_CSIPHY_ACQUIRE, + CAM_CSIPHY_START, +}; + +/** + * struct csiphy_reg_parms_t + * @mipi_csiphy_glbl_irq_cmd_addr: CSIPhy irq addr + * @mipi_csiphy_interrupt_status0_addr: + * CSIPhy interrupt status addr + * @mipi_csiphy_interrupt_mask0_addr: + * CSIPhy interrupt mask addr + * @mipi_csiphy_interrupt_mask_val: + * CSIPhy interrupt mask val + * @mipi_csiphy_interrupt_clear0_addr: + * CSIPhy interrupt clear addr + * @csiphy_version: CSIPhy Version + * @csiphy_common_array_size: CSIPhy common array size + * @csiphy_reset_array_size: CSIPhy reset array size + * @csiphy_2ph_config_array_size: 2ph settings size + * @csiphy_3ph_config_array_size: 3ph settings size + * @csiphy_cpas_cp_bits_per_phy: CP bits per phy + * @csiphy_cpas_cp_is_interleaved: checks whether cp bits + * are interleaved or not + * @csiphy_cpas_cp_2ph_offset: cp register 2ph offset + * @csiphy_cpas_cp_3ph_offset: cp register 3ph offset + * @csiphy_2ph_clock_lane: clock lane in 2ph + * @csiphy_2ph_combo_ck_ln: clk lane in combo 2ph + */ +struct csiphy_reg_parms_t { +/*MIPI CSI PHY registers*/ + uint32_t mipi_csiphy_glbl_irq_cmd_addr; + uint32_t mipi_csiphy_interrupt_status0_addr; + uint32_t mipi_csiphy_interrupt_mask0_addr; + uint32_t mipi_csiphy_interrupt_mask_val; + uint32_t mipi_csiphy_interrupt_mask_addr; + uint32_t mipi_csiphy_interrupt_clear0_addr; + uint32_t csiphy_version; + uint32_t csiphy_common_array_size; + uint32_t csiphy_reset_array_size; + uint32_t csiphy_2ph_config_array_size; + uint32_t csiphy_3ph_config_array_size; + uint32_t csiphy_cpas_cp_bits_per_phy; + uint32_t csiphy_cpas_cp_is_interleaved; + uint32_t csiphy_cpas_cp_2ph_offset; + uint32_t csiphy_cpas_cp_3ph_offset; + uint32_t csiphy_2ph_clock_lane; + uint32_t csiphy_2ph_combo_ck_ln; +}; + +/** + * struct intf_params + * @device_hdl: Device Handle + * @session_hdl: Session Handle + * @ops: KMD operations + * @crm_cb: Callback API pointers + */ +struct intf_params { + int32_t device_hdl[CSIPHY_MAX_INSTANCES]; + int32_t session_hdl[CSIPHY_MAX_INSTANCES]; + int32_t link_hdl[CSIPHY_MAX_INSTANCES]; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct csiphy_reg_t + * @reg_addr: Register address + * @reg_data: Register data + * @delay: Delay + * @csiphy_param_type: CSIPhy parameter type + */ +struct csiphy_reg_t { + int32_t reg_addr; + int32_t reg_data; + int32_t delay; + uint32_t csiphy_param_type; +}; + +struct csiphy_device; + +/* + * struct data_rate_reg_info_t + * @bandwidth: max bandwidth supported by this reg settings + * @data_rate_reg_array_size: number of reg value pairs in the array + * @csiphy_data_rate_regs: array of data rate specific reg value pairs + */ +struct data_rate_reg_info_t { + uint64_t bandwidth; + ssize_t data_rate_reg_array_size; + struct csiphy_reg_t csiphy_data_rate_regs[MAX_DATA_RATE_REGS]; +}; + +/** + * struct data_rate_settings_t + * @num_data_rate_settings: number of valid settings + * present in the data rate settings array + * @data_rate_settings: array of regsettings which are specific to + * data rate + */ +struct data_rate_settings_t { + ssize_t num_data_rate_settings; + struct data_rate_reg_info_t data_rate_settings[MAX_DATA_RATES]; +}; + +/** + * struct csiphy_ctrl_t + * @csiphy_reg: Register address + * @csiphy_common_reg: Common register set + * @csiphy_reset_reg: Reset register set + * @csiphy_2ph_reg: 2phase register set + * @csiphy_2ph_combo_mode_reg: + * 2phase combo register set + * @csiphy_3ph_reg: 3phase register set + * @csiphy_2ph_3ph_mode_reg: + * 2 phase 3phase combo register set + * @getclockvoting: function pointer which + * is used to find the clock voting + * for the sensor output data rate + * @data_rate_settings_table: + * Table which maintains the resgister + * settings specific to data rate + */ +struct csiphy_ctrl_t { + struct csiphy_reg_parms_t csiphy_reg; + struct csiphy_reg_t *csiphy_common_reg; + struct csiphy_reg_t *csiphy_irq_reg; + struct csiphy_reg_t *csiphy_reset_reg; + struct csiphy_reg_t (*csiphy_2ph_reg)[MAX_SETTINGS_PER_LANE]; + struct csiphy_reg_t (*csiphy_2ph_combo_mode_reg)[MAX_SETTINGS_PER_LANE]; + struct csiphy_reg_t (*csiphy_3ph_reg)[MAX_SETTINGS_PER_LANE]; + struct csiphy_reg_t (*csiphy_2ph_3ph_mode_reg)[MAX_SETTINGS_PER_LANE]; + enum cam_vote_level (*getclockvoting)(struct csiphy_device *phy_dev); + struct data_rate_settings_t *data_rates_settings_table; +}; + +/** + * cam_csiphy_param: Provides cmdbuffer structre + * @lane_mask : Lane mask details + * @lane_assign : Lane sensor will be using + * @csiphy_3phase : Mentions DPHY or CPHY + * @combo_mode : Info regarding combo_mode is enable / disable + * @lane_cnt : Total number of lanes + * @reserved + * @3phase : Details whether 3Phase / 2Phase operation + * @settle_time : Settling time in ms + * @settle_time_combo_sensor : Settling time in ms + * @data_rate : Data rate in mbps + * @data_rate_combo_sensor: data rate of combo sensor + * in the the same phy + * + */ +struct cam_csiphy_param { + uint16_t lane_mask; + uint16_t lane_assign; + uint8_t csiphy_3phase; + uint8_t combo_mode; + uint8_t lane_cnt; + uint8_t secure_mode[CSIPHY_MAX_INSTANCES]; + uint64_t settle_time; + uint64_t settle_time_combo_sensor; + uint64_t data_rate; + uint64_t data_rate_combo_sensor; +}; + +/** + * struct csiphy_device + * @pdev: Platform device + * @irq: Interrupt structure + * @base: Base address + * @hw_version: Hardware Version + * @csiphy_state: CSIPhy state + * @ctrl_reg: CSIPhy control registers + * @num_clk: Number of clocks + * @csiphy_max_clk: Max timer clock rate + * @num_vreg: Number of regulators + * @csiphy_clk: Clock structure + * @csiphy_clk_info: Clock information structure + * @csiphy_vreg: Regulator structure + * @csiphy_reg_ptr: Regulator structure + * @csiphy_3p_clk_info: 3Phase clock information + * @csiphy_3p_clk: 3Phase clocks structure + * @csi_3phase: Is it a 3Phase mode + * @ref_count: Reference count + * @clk_lane: Clock lane + * @acquire_count: Acquire device count + * @start_dev_count: Start count + * @is_acquired_dev_combo_mode: Flag that mentions whether already acquired + * device is for combo mode + * @soc_info: SOC information + * @cpas_handle: CPAS handle + * @config_count: Config reg count + * @csiphy_cpas_cp_reg_mask: CP reg mask for phy instance + */ +struct csiphy_device { + struct mutex mutex; + uint32_t hw_version; + enum cam_csiphy_state csiphy_state; + struct csiphy_ctrl_t *ctrl_reg; + uint32_t csiphy_max_clk; + struct msm_cam_clk_info csiphy_3p_clk_info[2]; + struct clk *csiphy_3p_clk[2]; + unsigned char csi_3phase; + int32_t ref_count; + uint16_t lane_mask[MAX_CSIPHY]; + uint8_t is_csiphy_3phase_hw; + uint8_t is_divisor_32_comp; + uint8_t num_irq_registers; + struct cam_subdev v4l2_dev_str; + struct cam_csiphy_param csiphy_info; + struct intf_params bridge_intf; + uint32_t clk_lane; + uint32_t acquire_count; + uint32_t start_dev_count; + char device_name[20]; + uint32_t is_acquired_dev_combo_mode; + struct cam_hw_soc_info soc_info; + uint32_t cpas_handle; + uint32_t config_count; + uint64_t csiphy_cpas_cp_reg_mask[CSIPHY_MAX_INSTANCES]; +}; + +#endif /* _CAM_CSIPHY_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c new file mode 100644 index 000000000000..4dd5273e0438 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_csiphy_soc.h" +#include "cam_csiphy_core.h" +#include "include/cam_csiphy_1_1_hwreg.h" +#include "include/cam_csiphy_1_0_hwreg.h" +#include "include/cam_csiphy_1_2_hwreg.h" +#include "include/cam_csiphy_1_2_1_hwreg.h" +#include "include/cam_csiphy_2_0_hwreg.h" + +#define CSIPHY_DIVISOR_16 16 +#define CSIPHY_DIVISOR_32 32 +#define CSIPHY_DIVISOR_8 8 +#define BYTES_PER_REGISTER 4 +#define NUM_REGISTER_PER_LINE 4 +#define REG_OFFSET(__start, __i) ((__start) + ((__i) * BYTES_PER_REGISTER)) + +static int cam_io_phy_dump(void __iomem *base_addr, + uint32_t start_offset, int size) +{ + char line_str[128]; + char *p_str; + int i; + uint32_t data; + + CAM_INFO(CAM_CSIPHY, "addr=%pK offset=0x%x size=%d", + base_addr, start_offset, size); + + if (!base_addr || (size <= 0)) + return -EINVAL; + + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size; i++) { + if (i % NUM_REGISTER_PER_LINE == 0) { + snprintf(p_str, 12, "0x%08x: ", + REG_OFFSET(start_offset, i)); + p_str += 11; + } + data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i)); + snprintf(p_str, 9, "%08x ", data); + p_str += 8; + if ((i + 1) % NUM_REGISTER_PER_LINE == 0) { + CAM_ERR(CAM_CSIPHY, "%s", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CAM_ERR(CAM_CSIPHY, "%s", line_str); + + return 0; +} + +int32_t cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0; + resource_size_t size = 0; + void __iomem *addr = NULL; + + if (!soc_info) { + rc = -EINVAL; + CAM_ERR(CAM_CSIPHY, "invalid input %d", rc); + return rc; + } + addr = soc_info->reg_map[0].mem_base; + size = resource_size(soc_info->mem_block[0]); + rc = cam_io_phy_dump(addr, 0, (size >> 2)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "generating dump failed %d", rc); + return rc; + } + return rc; +} + +enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev) +{ + CAM_DBG(CAM_CSIPHY, "voting for SVS"); + return CAM_SVS_VOTE; +} + +enum cam_vote_level get_clk_voting_dynamic(struct csiphy_device *csiphy_dev) +{ + uint32_t cam_vote_level = 0; + uint32_t last_valid_vote = 0; + struct cam_hw_soc_info *soc_info; + uint64_t phy_data_rate = csiphy_dev->csiphy_info.data_rate; + + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->is_acquired_dev_combo_mode) + phy_data_rate = max(phy_data_rate, + csiphy_dev->csiphy_info.data_rate_combo_sensor); + + if (csiphy_dev->csiphy_info.csiphy_3phase) { + if (csiphy_dev->is_divisor_32_comp) + do_div(phy_data_rate, CSIPHY_DIVISOR_32); + else + do_div(phy_data_rate, CSIPHY_DIVISOR_16); + } else { + do_div(phy_data_rate, CSIPHY_DIVISOR_8); + } + + /* round off to next integer */ + phy_data_rate += 1; + + for (cam_vote_level = 0; + cam_vote_level < CAM_MAX_VOTE; cam_vote_level++) { + if (soc_info->clk_level_valid[cam_vote_level] != true) + continue; + + if (soc_info->clk_rate[cam_vote_level][0] > + phy_data_rate) { + CAM_DBG(CAM_CSIPHY, + "match detected %s : %llu:%d level : %d", + soc_info->clk_name[0], + phy_data_rate, + soc_info->clk_rate[cam_vote_level][0], + cam_vote_level); + return cam_vote_level; + } + last_valid_vote = cam_vote_level; + } + return last_valid_vote; +} + +int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info; + enum cam_vote_level vote_level = CAM_SVS_VOTE; + + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->ref_count++) { + CAM_ERR(CAM_CSIPHY, "csiphy refcount = %d", + csiphy_dev->ref_count); + return rc; + } + + vote_level = csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev); + rc = cam_soc_util_enable_platform_resource(soc_info, true, + vote_level, ENABLE_IRQ); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "failed to enable platform resources %d", + rc); + return rc; + } + + rc = cam_soc_util_set_src_clk_rate(soc_info, + soc_info->clk_rate[0][soc_info->src_clk_idx]); + + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "csiphy_clk_set_rate failed rc: %d", rc); + goto csiphy_disable_platform_resource; + } + + cam_csiphy_reset(csiphy_dev); + + return rc; + + +csiphy_disable_platform_resource: + cam_soc_util_disable_platform_resource(soc_info, true, true); + + return rc; +} + +int32_t cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev) +{ + struct cam_hw_soc_info *soc_info; + + if (!csiphy_dev || !csiphy_dev->ref_count) { + CAM_ERR(CAM_CSIPHY, "csiphy dev NULL / ref_count ZERO"); + return 0; + } + soc_info = &csiphy_dev->soc_info; + + if (--csiphy_dev->ref_count) { + CAM_ERR(CAM_CSIPHY, "csiphy refcount = %d", + csiphy_dev->ref_count); + return 0; + } + + cam_csiphy_reset(csiphy_dev); + + cam_soc_util_disable_platform_resource(soc_info, true, true); + + return 0; +} + +int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, + struct csiphy_device *csiphy_dev) +{ + int32_t rc = 0, i = 0; + uint32_t clk_cnt = 0; + char *csi_3p_clk_name = "csi_phy_3p_clk"; + char *csi_3p_clk_src_name = "csiphy_3p_clk_src"; + struct cam_hw_soc_info *soc_info; + + csiphy_dev->is_csiphy_3phase_hw = 0; + soc_info = &csiphy_dev->soc_info; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "parsing common soc dt(rc %d)", rc); + return rc; + } + + csiphy_dev->is_csiphy_3phase_hw = 0; + + if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.0")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = + csiphy_3ph_v1_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_0; + csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_1_0; + csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_0; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->hw_version = CSIPHY_VERSION_V10; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.1")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_1_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = + csiphy_3ph_v1_1_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_1; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_1; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_1; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_1; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->hw_version = CSIPHY_VERSION_V11; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = true; + csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2.1")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_1_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2_1; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2_1; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2_1; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2_1; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = true; + csiphy_dev->hw_version = CSIPHY_VERSION_V121; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2_1; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2.2")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->clk_lane = 0; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v2.0")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v2_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->hw_version = CSIPHY_VERSION_V20; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + } else { + CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", + csiphy_dev->hw_version); + rc = -EINVAL; + return rc; + } + + if (soc_info->num_clk > CSIPHY_NUM_CLK_MAX) { + CAM_ERR(CAM_CSIPHY, "invalid clk count=%d, max is %d", + soc_info->num_clk, CSIPHY_NUM_CLK_MAX); + return -EINVAL; + } + for (i = 0; i < soc_info->num_clk; i++) { + if (!strcmp(soc_info->clk_name[i], + csi_3p_clk_src_name)) { + csiphy_dev->csiphy_3p_clk_info[0].clk_name = + soc_info->clk_name[i]; + csiphy_dev->csiphy_3p_clk_info[0].clk_rate = + soc_info->clk_rate[0][i]; + csiphy_dev->csiphy_3p_clk[0] = + soc_info->clk[i]; + continue; + } else if (!strcmp(soc_info->clk_name[i], + csi_3p_clk_name)) { + csiphy_dev->csiphy_3p_clk_info[1].clk_name = + soc_info->clk_name[i]; + csiphy_dev->csiphy_3p_clk_info[1].clk_rate = + soc_info->clk_rate[0][i]; + csiphy_dev->csiphy_3p_clk[1] = + soc_info->clk[i]; + continue; + } + + CAM_DBG(CAM_CSIPHY, "clk_rate[%d] = %d", clk_cnt, + soc_info->clk_rate[0][clk_cnt]); + clk_cnt++; + } + + csiphy_dev->csiphy_max_clk = + soc_info->clk_rate[0][soc_info->src_clk_idx]; + + rc = cam_soc_util_request_platform_resource(&csiphy_dev->soc_info, + cam_csiphy_irq, csiphy_dev); + + return rc; +} + +int32_t cam_csiphy_soc_release(struct csiphy_device *csiphy_dev) +{ + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "csiphy dev NULL"); + return 0; + } + + cam_soc_util_release_platform_resource(&csiphy_dev->soc_info); + + return 0; +} diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h new file mode 100644 index 000000000000..c02b9556add4 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_SOC_H_ +#define _CAM_CSIPHY_SOC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_csiphy_dev.h" +#include "cam_csiphy_core.h" + +#undef CDBG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) + +#define CSI_3PHASE_HW 1 +#define CSIPHY_VERSION_V35 0x35 +#define CSIPHY_VERSION_V10 0x10 +#define CSIPHY_VERSION_V11 0x11 +#define CSIPHY_VERSION_V12 0x12 +#define CSIPHY_VERSION_V121 0x121 +#define CSIPHY_VERSION_V20 0x20 + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API release SOC related parameters + */ +int cam_csiphy_soc_release(struct csiphy_device *csiphy_dev); + +/** + * @pdev: Platform device + * @csiphy_dev: CSIPhy device structure + * + * This API parses csiphy device tree information + */ +int cam_csiphy_parse_dt_info(struct platform_device *pdev, + struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API enables SOC related parameters + */ +int cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API disables SOC related parameters + */ +int cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev); + +/** + * @soc_info: Soc info of cam hw driver module + * + * This API dumps memory for the entire mapped region + * (needs to be macro enabled before use) + */ +int cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_CSIPHY_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h new file mode 100644 index 000000000000..e910162858b3 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h @@ -0,0 +1,348 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_0_HWREG_H_ +#define _CAM_CSIPHY_1_0_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_0 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 5, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 14, + .csiphy_3ph_config_array_size = 19, +}; + +struct csiphy_reg_t csiphy_common_reg_1_0[] = { + {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_0[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_0[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_2ph_v1_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v1_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x0A, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x0A, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t csiphy_3ph_v1_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_3ph_v1_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_1_0_HWREG_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h new file mode 100644 index 000000000000..30b61067a792 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h @@ -0,0 +1,499 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_1_HWREG_H_ +#define _CAM_CSIPHY_1_1_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_1 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 5, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 14, + .csiphy_3ph_config_array_size = 43, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_1[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_1[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_1[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct +csiphy_reg_t csiphy_2ph_v1_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v1_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct +csiphy_reg_t csiphy_3ph_v1_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0144, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x24, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09AC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0344, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x24, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0544, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x24, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_3ph_v1_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0144, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09AC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0344, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0544, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_D5_0_HWREG_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h new file mode 100644 index 000000000000..4f9fd086a97d --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -0,0 +1,491 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_2_1_HWREG_H_ +#define _CAM_CSIPHY_1_2_1_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_2_1 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 21, + .csiphy_3ph_config_array_size = 34, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_2_1[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_2_1[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_2_1[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct +csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v1_2_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +struct +csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct data_rate_settings_t data_rate_delta_table_1_2_1 = { + .num_data_rate_settings = 3, + .data_rate_settings = { + { + /* (2.5 * 10**3 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 12, + .csiphy_data_rate_regs = { + {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (3.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 7980000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + }, + { + /* (4.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 10260000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + } + } +}; + +#endif /* _CAM_CSIPHY_1_2_1_HWREG_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h new file mode 100644 index 000000000000..6ee9e155b93d --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -0,0 +1,512 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_2_HWREG_H_ +#define _CAM_CSIPHY_1_2_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_2 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 22, + .csiphy_3ph_config_array_size = 38, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_2[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_2[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_2[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct +csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +struct +csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct data_rate_settings_t data_rate_delta_table = { + .num_data_rate_settings = 3, + .data_rate_settings = { + { + /* (2.5 * 10**3 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 12, + .csiphy_data_rate_regs = { + {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (3.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 7980000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + }, + { + /* (4.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 10260000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + } + } +}; +#endif /* _CAM_CSIPHY_1_2_HWREG_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h new file mode 100644 index 000000000000..cbd0dc582b32 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_2_0_HWREG_H_ +#define _CAM_CSIPHY_2_0_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v2_0 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 3, + .csiphy_2ph_config_array_size = 15, + .csiphy_3ph_config_array_size = 17, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_2_0[] = { + {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x06, 0x00, CSIPHY_3PH_REGS}, + {0x0164, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0364, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0564, 0x00, 0x00, CSIPHY_2PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_2_0[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_2_0[] = { + {0x082c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xff, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xfb, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xef, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_2ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v2_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t csiphy_3ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_2_0_HWREG_H_ */ diff --git a/drivers/cam_sensor_module/cam_eeprom/Makefile b/drivers/cam_sensor_module/cam_eeprom/Makefile new file mode 100644 index 000000000000..e52bc01dc5a5 --- /dev/null +++ b/drivers/cam_sensor_module/cam_eeprom/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom_dev.o cam_eeprom_core.o cam_eeprom_soc.o diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c new file mode 100644 index 000000000000..b211471adf00 --- /dev/null +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -0,0 +1,1506 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include + +#include "cam_eeprom_core.h" +#include "cam_eeprom_soc.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +#define MAX_READ_SIZE 0x7FFFF + +/** + * cam_eeprom_read_memory() - read map data into buffer + * @e_ctrl: eeprom control struct + * @block: block to be read + * + * This function iterates through blocks stored in block->map, reads each + * region and concatenate them into the pre-allocated block->mapdata + */ +static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_eeprom_memory_block_t *block) +{ + int rc = 0; + int j; + struct cam_sensor_i2c_reg_setting i2c_reg_settings = {0}; + struct cam_sensor_i2c_reg_array i2c_reg_array = {0}; + struct cam_eeprom_memory_map_t *emap = block->map; + struct cam_eeprom_soc_private *eb_info = NULL; + uint8_t *memptr = block->mapdata; + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "e_ctrl is NULL"); + return -EINVAL; + } + + eb_info = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + + for (j = 0; j < block->num_map; j++) { + CAM_DBG(CAM_EEPROM, "slave-addr = 0x%X", emap[j].saddr); + if (emap[j].saddr) { + eb_info->i2c_info.slave_addr = emap[j].saddr; + rc = cam_eeprom_update_i2c_info(e_ctrl, + &eb_info->i2c_info); + if (rc) { + CAM_ERR(CAM_EEPROM, + "failed: to update i2c info rc %d", + rc); + return rc; + } + } + + if (emap[j].page.valid_size) { + i2c_reg_settings.addr_type = emap[j].page.addr_type; + i2c_reg_settings.data_type = emap[j].page.data_type; + i2c_reg_settings.size = 1; + i2c_reg_array.reg_addr = emap[j].page.addr; + i2c_reg_array.reg_data = emap[j].page.data; + i2c_reg_array.delay = emap[j].page.delay; + i2c_reg_settings.reg_setting = &i2c_reg_array; + rc = camera_io_dev_write(&e_ctrl->io_master_info, + &i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_EEPROM, "page write failed rc %d", + rc); + return rc; + } + memptr = block->mapdata + emap[j].mem.valid_size; + } + + if (emap[j].pageen.valid_size) { + i2c_reg_settings.addr_type = emap[j].pageen.addr_type; + i2c_reg_settings.data_type = emap[j].pageen.data_type; + i2c_reg_settings.size = 1; + i2c_reg_array.reg_addr = emap[j].pageen.addr; + i2c_reg_array.reg_data = emap[j].pageen.data; + i2c_reg_array.delay = emap[j].pageen.delay; + i2c_reg_settings.reg_setting = &i2c_reg_array; + rc = camera_io_dev_write(&e_ctrl->io_master_info, + &i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_EEPROM, "page enable failed rc %d", + rc); + return rc; + } + } + + if (emap[j].poll.valid_size) { + rc = camera_io_dev_poll(&e_ctrl->io_master_info, + emap[j].poll.addr, emap[j].poll.data, + 0, emap[j].poll.addr_type, + emap[j].poll.data_type, + emap[j].poll.delay); + if (rc) { + CAM_ERR(CAM_EEPROM, "poll failed rc %d", + rc); + return rc; + } + } + + if (emap[j].mem.valid_size) { + rc = camera_io_dev_read_seq(&e_ctrl->io_master_info, + emap[j].mem.addr, memptr, + emap[j].mem.addr_type, + emap[j].mem.data_type, + emap[j].mem.valid_size); + if (rc) { + CAM_ERR(CAM_EEPROM, "read failed rc %d", + rc); + return rc; + } + memptr += emap[j].mem.valid_size; + } + + if (emap[j].pageen.valid_size) { + i2c_reg_settings.addr_type = emap[j].pageen.addr_type; + i2c_reg_settings.data_type = emap[j].pageen.data_type; + i2c_reg_settings.size = 1; + i2c_reg_array.reg_addr = emap[j].pageen.addr; + i2c_reg_array.reg_data = 0; + i2c_reg_array.delay = emap[j].pageen.delay; + i2c_reg_settings.reg_setting = &i2c_reg_array; + rc = camera_io_dev_write(&e_ctrl->io_master_info, + &i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_EEPROM, + "page disable failed rc %d", + rc); + return rc; + } + } + } + return rc; +} + +/** + * cam_eeprom_power_up - Power up eeprom hardware + * @e_ctrl: ctrl structure + * @power_info: power up/down info for eeprom + * + * Returns success or failure + */ +static int cam_eeprom_power_up(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_sensor_power_ctrl_t *power_info) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info = + &e_ctrl->soc_info; + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params( + &e_ctrl->soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_EEPROM, + "failed to fill power up vreg params rc:%d", rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + &e_ctrl->soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_EEPROM, + "failed to fill power down vreg params rc:%d", rc); + return rc; + } + + power_info->dev = soc_info->dev; + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed in eeprom power up rc %d", rc); + return rc; + } + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) { + rc = camera_io_init(&(e_ctrl->io_master_info)); + if (rc) { + CAM_ERR(CAM_EEPROM, "cci_init failed"); + return -EINVAL; + } + } + return rc; +} + +/** + * cam_eeprom_power_down - Power down eeprom hardware + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int cam_eeprom_power_down(struct cam_eeprom_ctrl_t *e_ctrl) +{ + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info; + struct cam_eeprom_soc_private *soc_private; + int rc = 0; + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "failed: e_ctrl %pK", e_ctrl); + return -EINVAL; + } + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + soc_info = &e_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_EEPROM, "failed: power_info %pK", power_info); + return -EINVAL; + } + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "power down the core is failed:%d", rc); + return rc; + } + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) + camera_io_release(&(e_ctrl->io_master_info)); + + return rc; +} + +/** + * cam_eeprom_match_id - match eeprom id + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int cam_eeprom_match_id(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc; + struct camera_io_master *client = &e_ctrl->io_master_info; + uint8_t id[2]; + + rc = cam_spi_query_id(client, 0, CAMERA_SENSOR_I2C_TYPE_WORD, + &id[0], 2); + if (rc) + return rc; + CAM_DBG(CAM_EEPROM, "read 0x%x 0x%x, check 0x%x 0x%x", + id[0], id[1], client->spi_client->mfr_id0, + client->spi_client->device_id0); + if (id[0] != client->spi_client->mfr_id0 + || id[1] != client->spi_client->device_id0) + return -ENODEV; + return 0; +} + +/** + * cam_eeprom_parse_read_memory_map - Parse memory map + * @of_node: device node + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +int32_t cam_eeprom_parse_read_memory_map(struct device_node *of_node, + struct cam_eeprom_ctrl_t *e_ctrl) +{ + int32_t rc = 0; + struct cam_eeprom_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "failed: e_ctrl is NULL"); + return -EINVAL; + } + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + rc = cam_eeprom_parse_dt_memory_map(of_node, &e_ctrl->cal_data); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: eeprom dt parse rc %d", rc); + return rc; + } + rc = cam_eeprom_power_up(e_ctrl, power_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: eeprom power up rc %d", rc); + goto data_mem_free; + } + + e_ctrl->cam_eeprom_state = CAM_EEPROM_CONFIG; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) { + rc = cam_eeprom_match_id(e_ctrl); + if (rc) { + CAM_DBG(CAM_EEPROM, "eeprom not matching %d", rc); + goto power_down; + } + } + rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data); + if (rc) { + CAM_ERR(CAM_EEPROM, "read_eeprom_memory failed"); + goto power_down; + } + + rc = cam_eeprom_power_down(e_ctrl); + if (rc) + CAM_ERR(CAM_EEPROM, "failed: eeprom power down rc %d", rc); + + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + return rc; +power_down: + cam_eeprom_power_down(e_ctrl); +data_mem_free: + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + return rc; +} + +/** + * cam_eeprom_get_dev_handle - get device handle + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, + void *arg) +{ + struct cam_sensor_acquire_dev eeprom_acq_dev; + struct cam_create_dev_hdl bridge_params; + struct cam_control *cmd = (struct cam_control *)arg; + + if (e_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_EEPROM, "Device is already acquired"); + return -EFAULT; + } + if (copy_from_user(&eeprom_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(eeprom_acq_dev))) { + CAM_ERR(CAM_EEPROM, + "EEPROM:ACQUIRE_DEV: copy from user failed"); + return -EFAULT; + } + + bridge_params.session_hdl = eeprom_acq_dev.session_handle; + bridge_params.ops = &e_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = e_ctrl; + + eeprom_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; + e_ctrl->bridge_intf.session_hdl = eeprom_acq_dev.session_handle; + + CAM_DBG(CAM_EEPROM, "Device Handle: %d", eeprom_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &eeprom_acq_dev, sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_EEPROM, "EEPROM:ACQUIRE_DEV: copy to user failed"); + return -EFAULT; + } + return 0; +} + +/** + * cam_eeprom_update_slaveInfo - Update slave info + * @e_ctrl: ctrl structure + * @cmd_buf: command buffer + * + * Returns success or failure + */ +static int32_t cam_eeprom_update_slaveInfo(struct cam_eeprom_ctrl_t *e_ctrl, + void *cmd_buf) +{ + int32_t rc = 0; + struct cam_eeprom_soc_private *soc_private; + struct cam_cmd_i2c_info *cmd_i2c_info = NULL; + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + cmd_i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + soc_private->i2c_info.slave_addr = cmd_i2c_info->slave_addr; + soc_private->i2c_info.i2c_freq_mode = cmd_i2c_info->i2c_freq_mode; + + rc = cam_eeprom_update_i2c_info(e_ctrl, + &soc_private->i2c_info); + CAM_DBG(CAM_EEPROM, "Slave addr: 0x%x Freq Mode: %d", + soc_private->i2c_info.slave_addr, + soc_private->i2c_info.i2c_freq_mode); + + return rc; +} + +/** + * cam_eeprom_parse_memory_map - Parse memory map info + * @data: memory block data + * @cmd_buf: command buffer + * @cmd_length: command buffer length + * @num_map: memory map size + * @cmd_length_bytes: command length processed in this function + * + * Returns success or failure + */ +static int32_t cam_eeprom_parse_memory_map( + struct cam_eeprom_memory_block_t *data, + void *cmd_buf, int cmd_length, uint32_t *cmd_length_bytes, + int *num_map, size_t remain_buf_len) +{ + int32_t rc = 0; + int32_t cnt = 0; + int32_t processed_size = 0; + uint8_t generic_op_code; + struct cam_eeprom_memory_map_t *map = data->map; + struct common_header *cmm_hdr = + (struct common_header *)cmd_buf; + uint16_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_random_wr *i2c_random_wr = NULL; + struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL; + struct cam_cmd_conditional_wait *i2c_poll = NULL; + struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL; + size_t validate_size = 0; + + generic_op_code = cmm_hdr->fifth_byte; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR) + validate_size = sizeof(struct cam_cmd_i2c_random_wr); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD) + validate_size = sizeof(struct cam_cmd_i2c_continuous_rd); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf_len < validate_size || + *num_map >= MSM_EEPROM_MAX_MEM_MAP_CNT) { + CAM_ERR(CAM_EEPROM, "not enough buffer"); + return -EINVAL; + } + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: + i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + + if (i2c_random_wr->header.count == 0 || + i2c_random_wr->header.count >= MSM_EEPROM_MAX_MEM_MAP_CNT || + (size_t)*num_map > U16_MAX - i2c_random_wr->header.count) { + CAM_ERR(CAM_EEPROM, "OOB Error"); + return -EINVAL; + } + cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr) + + ((i2c_random_wr->header.count - 1) * + sizeof(struct i2c_random_wr_payload)); + + if (cmd_length_in_bytes > remain_buf_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer remaining"); + return -EINVAL; + } + for (cnt = 0; cnt < (i2c_random_wr->header.count); + cnt++) { + map[*num_map + cnt].page.addr = + i2c_random_wr->random_wr_payload[cnt].reg_addr; + map[*num_map + cnt].page.addr_type = + i2c_random_wr->header.addr_type; + map[*num_map + cnt].page.data = + i2c_random_wr->random_wr_payload[cnt].reg_data; + map[*num_map + cnt].page.data_type = + i2c_random_wr->header.data_type; + map[*num_map + cnt].page.valid_size = 1; + } + + *num_map += (i2c_random_wr->header.count - 1); + cmd_buf += cmd_length_in_bytes / sizeof(int32_t); + processed_size += + cmd_length_in_bytes; + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: + i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf; + cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); + + if (i2c_cont_rd->header.count >= U32_MAX - data->num_data) { + CAM_ERR(CAM_EEPROM, + "int overflow on eeprom memory block"); + return -EINVAL; + } + map[*num_map].mem.addr = i2c_cont_rd->reg_addr; + map[*num_map].mem.addr_type = i2c_cont_rd->header.addr_type; + map[*num_map].mem.data_type = i2c_cont_rd->header.data_type; + map[*num_map].mem.valid_size = + i2c_cont_rd->header.count; + cmd_buf += cmd_length_in_bytes / sizeof(int32_t); + processed_size += + cmd_length_in_bytes; + data->num_data += map[*num_map].mem.valid_size; + break; + case CAMERA_SENSOR_CMD_TYPE_WAIT: + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND || + generic_op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) { + i2c_uncond_wait = + (struct cam_cmd_unconditional_wait *)cmd_buf; + cmd_length_in_bytes = + sizeof(struct cam_cmd_unconditional_wait); + + if (*num_map < 1) { + CAM_ERR(CAM_EEPROM, + "invalid map number, num_map=%d", + *num_map); + return -EINVAL; + } + + /* + * Though delay is added all of them, but delay will + * be applicable to only one of them as only one of + * them will have valid_size set to >= 1. + */ + map[*num_map - 1].mem.delay = i2c_uncond_wait->delay; + map[*num_map - 1].page.delay = i2c_uncond_wait->delay; + map[*num_map - 1].pageen.delay = i2c_uncond_wait->delay; + } else if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_COND) { + i2c_poll = (struct cam_cmd_conditional_wait *)cmd_buf; + cmd_length_in_bytes = + sizeof(struct cam_cmd_conditional_wait); + + map[*num_map].poll.addr = i2c_poll->reg_addr; + map[*num_map].poll.addr_type = i2c_poll->addr_type; + map[*num_map].poll.data = i2c_poll->reg_data; + map[*num_map].poll.data_type = i2c_poll->data_type; + map[*num_map].poll.delay = i2c_poll->timeout; + map[*num_map].poll.valid_size = 1; + } + cmd_buf += cmd_length_in_bytes / sizeof(int32_t); + processed_size += + cmd_length_in_bytes; + break; + default: + break; + } + + *cmd_length_bytes = processed_size; + return rc; +} + +static struct i2c_settings_list* + cam_eeprom_get_i2c_ptr(struct i2c_settings_array *i2c_reg_settings, + uint32_t size) +{ + struct i2c_settings_list *tmp; + + tmp = kzalloc(sizeof(struct i2c_settings_list), GFP_KERNEL); + + if (tmp != NULL) + list_add_tail(&(tmp->list), + &(i2c_reg_settings->list_head)); + else + return NULL; + + tmp->seq_settings.reg_data = + kcalloc(size, sizeof(uint8_t), GFP_KERNEL); + if (tmp->seq_settings.reg_data == NULL) { + list_del(&(tmp->list)); + kfree(tmp); + tmp = NULL; + return NULL; + } + tmp->seq_settings.size = size; + + return tmp; +} + +static int32_t cam_eeprom_handle_continuous_write( + struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_cmd_i2c_continuous_wr *cam_cmd_i2c_continuous_wr, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt = 0; + + + CAM_DBG(CAM_EEPROM, "Total Size: %d", + cam_cmd_i2c_continuous_wr->header.count); + + i2c_list = cam_eeprom_get_i2c_ptr(i2c_reg_settings, + cam_cmd_i2c_continuous_wr->header.count); + if (i2c_list == NULL || + i2c_list->seq_settings.reg_data == NULL) { + CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); + return -ENOMEM; + } + + *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + sizeof(struct cam_cmd_read) * + (cam_cmd_i2c_continuous_wr->header.count)); + if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_BURST; + else if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_SEQ; + else { + rc = -EINVAL; + goto deallocate_i2c_list; + } + + i2c_list->seq_settings.addr_type = + cam_cmd_i2c_continuous_wr->header.addr_type; + + CAM_ERR(CAM_EEPROM, "Write Address: 0x%x", + cam_cmd_i2c_continuous_wr->reg_addr); + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) { + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_RANDOM; + e_ctrl->eebin_info.start_address = + cam_cmd_i2c_continuous_wr->reg_addr; + e_ctrl->eebin_info.size = + cam_cmd_i2c_continuous_wr->header.count; + CAM_DBG(CAM_EEPROM, "Header Count: %d", + cam_cmd_i2c_continuous_wr->header.count); + e_ctrl->eebin_info.is_valid = 1; + + i2c_list->seq_settings.reg_addr = + cam_cmd_i2c_continuous_wr->reg_addr; + } else + CAM_ERR(CAM_EEPROM, "Burst Mode Not Supported\n"); + + (*offset) += cnt; + *list = &(i2c_list->list); + return rc; +deallocate_i2c_list: + kfree(i2c_list); + return rc; +} + +static int32_t cam_eeprom_handle_delay( + uint32_t **cmd_buf, + uint16_t generic_op_code, + struct i2c_settings_array *i2c_reg_settings, + uint32_t offset, uint32_t *byte_cnt, + struct list_head *list_ptr, + size_t remain_buf_len) +{ + int32_t rc = 0; + struct i2c_settings_list *i2c_list = NULL; + struct cam_cmd_unconditional_wait *cmd_uncond_wait = + (struct cam_cmd_unconditional_wait *) *cmd_buf; + + if (remain_buf_len < (sizeof(struct cam_cmd_unconditional_wait))) { + CAM_ERR(CAM_EEPROM, "Not Enough buffer"); + return -EINVAL; + } + + if (list_ptr == NULL) { + CAM_ERR(CAM_SENSOR, "Invalid list ptr"); + return -EINVAL; + } + + if (offset > 0) { + i2c_list = + list_entry(list_ptr, struct i2c_settings_list, list); + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND) + i2c_list->i2c_settings.reg_setting[offset - 1].delay = + cmd_uncond_wait->delay; + else + i2c_list->i2c_settings.delay = + cmd_uncond_wait->delay; + (*cmd_buf) += + sizeof( + struct cam_cmd_unconditional_wait) / sizeof(uint32_t); + (*byte_cnt) += + sizeof( + struct cam_cmd_unconditional_wait); + } else { + CAM_ERR(CAM_SENSOR, "Delay Rxed before any buffer: %d", offset); + return -EINVAL; + } + + return rc; +} + +/** + * cam_eeprom_parse_write_memory_packet - Write eeprom packet + * @csl_packet: csl packet received + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int32_t cam_eeprom_parse_write_memory_packet( + struct cam_packet *csl_packet, + struct cam_eeprom_ctrl_t *e_ctrl) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + uint32_t *offset = NULL; + int32_t i, rc = 0; + uint32_t *cmd_buf = NULL; + uintptr_t generic_pkt_addr; + size_t pkt_len = 0; + size_t remain_len = 0; + uint32_t total_cmd_buf_in_bytes = 0; + uint32_t processed_cmd_buf_in_bytes = 0; + struct common_header *cmm_hdr = NULL; + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_info *i2c_info = NULL; + + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + CAM_DBG(CAM_EEPROM, "Number of Command Buffers: %d", + csl_packet->num_cmd_buf); + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + struct list_head *list = NULL; + uint16_t generic_op_code; + uint32_t off = 0; + int master; + struct cam_sensor_cci_client *cci; + + total_cmd_buf_in_bytes = cmd_desc[i].length; + processed_cmd_buf_in_bytes = 0; + + if (!total_cmd_buf_in_bytes) + continue; + + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to get cpu buf"); + return rc; + } + + cmd_buf = (uint32_t *)generic_pkt_addr; + if (!cmd_buf) { + CAM_ERR(CAM_EEPROM, "invalid cmd buf"); + rc = -EINVAL; + goto end; + } + + if ((pkt_len < sizeof(struct common_header) || + (cmd_desc[i].offset) > (pkt_len - + sizeof(struct common_header)))) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto end; + } + + remain_len = pkt_len - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + if (total_cmd_buf_in_bytes > remain_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer for command"); + rc = -EINVAL; + goto end; + } + + master = e_ctrl->io_master_info.master_type; + cci = e_ctrl->io_master_info.cci_client; + while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct common_header)) { + CAM_ERR(CAM_EEPROM, "Not Enough buffer"); + rc = -EINVAL; + goto end; + } + cmm_hdr = (struct common_header *)cmd_buf; + generic_op_code = cmm_hdr->fifth_byte; + + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + if (master == CCI_MASTER) { + cci->cci_i2c_master = + e_ctrl->cci_i2c_master; + cci->i2c_freq_mode = + i2c_info->i2c_freq_mode; + cci->sid = + i2c_info->slave_addr >> 1; + CAM_DBG(CAM_EEPROM, + "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, + i2c_info->i2c_freq_mode); + } else if (master == I2C_MASTER) { + e_ctrl->io_master_info.client->addr = + i2c_info->slave_addr; + CAM_DBG(CAM_EEPROM, + "Slave addr: 0x%x", + i2c_info->slave_addr); + } else if (master == SPI_MASTER) { + CAM_ERR(CAM_EEPROM, + "No Need of Slave Info"); + } else { + CAM_ERR(CAM_EEPROM, + "Invalid Master type: %d", + master); + rc = -EINVAL; + goto end; + } + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/4; + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR: { + struct cam_cmd_i2c_continuous_wr + *cam_cmd_i2c_continuous_wr = + (struct cam_cmd_i2c_continuous_wr *) + cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_continuous_wr)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_EEPROM, + "CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR"); + rc = cam_eeprom_handle_continuous_write( + e_ctrl, + cam_cmd_i2c_continuous_wr, + &(e_ctrl->wr_settings), + &cmd_length_in_bytes, &off, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in continuous write %d", rc); + goto end; + } + + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + break; + } + case CAMERA_SENSOR_CMD_TYPE_WAIT: { + CAM_DBG(CAM_EEPROM, + "CAMERA_SENSOR_CMD_TYPE_WAIT"); + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND || + generic_op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) { + + rc = cam_eeprom_handle_delay( + &cmd_buf, generic_op_code, + &(e_ctrl->wr_settings), off, + &cmd_length_in_bytes, + list, (remain_len - + processed_cmd_buf_in_bytes)); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "delay hdl failed: %d", + rc); + goto end; + } + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + } else { + CAM_ERR(CAM_EEPROM, + "Wrong Wait Command: %d", + generic_op_code); + rc = -EINVAL; + goto end; + } + break; + } + default: + CAM_ERR(CAM_EEPROM, + "Invalid Cmd_type rxed: %d\n", + cmm_hdr->cmd_type); + rc = -EINVAL; + break; + } + } + } + +end: + return rc; +} + +/** + * cam_eeprom_init_pkt_parser - Parse eeprom packet + * @e_ctrl: ctrl structure + * @csl_packet: csl packet received + * + * Returns success or failure + */ +static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_packet *csl_packet) +{ + int32_t rc = 0; + int i = 0; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uint32_t *offset = NULL; + uint32_t *cmd_buf = NULL; + uintptr_t generic_pkt_addr; + size_t pkt_len = 0; + size_t remain_len = 0; + uint32_t total_cmd_buf_in_bytes = 0; + uint32_t processed_cmd_buf_in_bytes = 0; + struct common_header *cmm_hdr = NULL; + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_info *i2c_info = NULL; + int num_map = -1; + struct cam_eeprom_memory_map_t *map = NULL; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + e_ctrl->cal_data.map = vzalloc((MSM_EEPROM_MEMORY_MAP_MAX_SIZE * + MSM_EEPROM_MAX_MEM_MAP_CNT) * + (sizeof(struct cam_eeprom_memory_map_t))); + if (!e_ctrl->cal_data.map) { + rc = -ENOMEM; + CAM_ERR(CAM_EEPROM, "failed"); + return rc; + } + map = e_ctrl->cal_data.map; + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + processed_cmd_buf_in_bytes = 0; + if (!total_cmd_buf_in_bytes) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to get cpu buf"); + return rc; + } + cmd_buf = (uint32_t *)generic_pkt_addr; + if (!cmd_buf) { + CAM_ERR(CAM_EEPROM, "invalid cmd buf"); + rc = -EINVAL; + goto end; + } + + if ((pkt_len < sizeof(struct common_header)) || + (cmd_desc[i].offset > (pkt_len - + sizeof(struct common_header)))) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto end; + } + remain_len = pkt_len - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + if (total_cmd_buf_in_bytes > remain_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer for command"); + rc = -EINVAL; + goto end; + } + /* Loop through multiple cmd formats in one cmd buffer */ + while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct common_header)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + cmm_hdr = (struct common_header *)cmd_buf; + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + /* Configure the following map slave address */ + map[num_map + 1].saddr = i2c_info->slave_addr; + rc = cam_eeprom_update_slaveInfo(e_ctrl, + cmd_buf); + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + cmd_length_in_bytes = total_cmd_buf_in_bytes; + rc = cam_sensor_update_power_settings(cmd_buf, + cmd_length_in_bytes, power_info, + (remain_len - + processed_cmd_buf_in_bytes)); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed"); + goto end; + } + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: + case CAMERA_SENSOR_CMD_TYPE_WAIT: + num_map++; + rc = cam_eeprom_parse_memory_map( + &e_ctrl->cal_data, cmd_buf, + total_cmd_buf_in_bytes, + &cmd_length_in_bytes, &num_map, + (remain_len - + processed_cmd_buf_in_bytes)); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/sizeof(uint32_t); + break; + default: + CAM_ERR(CAM_EEPROM, "Invalid cmd_type 0x%x", + cmm_hdr->cmd_type); + rc = -EINVAL; + goto end; + } + } + e_ctrl->cal_data.num_map = num_map + 1; + } + +end: + return rc; +} + +/** + * cam_eeprom_get_cal_data - parse the userspace IO config and + * copy read data to share with userspace + * @e_ctrl: ctrl structure + * @csl_packet: csl packet received + * + * Returns success or failure + */ +static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_buf_io_cfg *io_cfg; + uint32_t i = 0; + int rc = 0; + uintptr_t buf_addr; + size_t buf_size; + uint8_t *read_buffer; + size_t remain_len = 0; + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + CAM_DBG(CAM_EEPROM, "number of IO configs: %d:", + csl_packet->num_io_configs); + + for (i = 0; i < csl_packet->num_io_configs; i++) { + CAM_DBG(CAM_EEPROM, "Direction: %d:", io_cfg->direction); + if (io_cfg->direction == CAM_BUF_OUTPUT) { + rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], + &buf_addr, &buf_size); + if (rc) { + CAM_ERR(CAM_EEPROM, "Fail in get buffer: %d", + rc); + return rc; + } + if (buf_size <= io_cfg->offsets[0]) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + + remain_len = buf_size - io_cfg->offsets[0]; + CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n", + (void *)buf_addr, buf_size); + + read_buffer = (uint8_t *)buf_addr; + if (!read_buffer) { + CAM_ERR(CAM_EEPROM, + "invalid buffer to copy data"); + rc = -EINVAL; + return rc; + } + read_buffer += io_cfg->offsets[0]; + + if (remain_len < e_ctrl->cal_data.num_data) { + CAM_ERR(CAM_EEPROM, + "failed to copy, Invalid size"); + rc = -EINVAL; + return rc; + } + + CAM_DBG(CAM_EEPROM, "copy the data, len:%d", + e_ctrl->cal_data.num_data); + memcpy(read_buffer, e_ctrl->cal_data.mapdata, + e_ctrl->cal_data.num_data); + } else { + CAM_ERR(CAM_EEPROM, "Invalid direction"); + rc = -EINVAL; + } + } + + return rc; +} + +static int32_t delete_eeprom_request(struct i2c_settings_array *i2c_array) +{ + struct i2c_settings_list *i2c_list = NULL, *i2c_next = NULL; + int32_t rc = 0; + + if (i2c_array == NULL) { + CAM_ERR(CAM_SENSOR, "FATAL:: Invalid argument"); + return -EINVAL; + } + + list_for_each_entry_safe(i2c_list, i2c_next, + &(i2c_array->list_head), list) { + kfree(i2c_list->seq_settings.reg_data); + list_del(&(i2c_list->list)); + kfree(i2c_list); + } + INIT_LIST_HEAD(&(i2c_array->list_head)); + i2c_array->is_settings_valid = 0; + + return rc; +} + +/** + * cam_eeprom_write - Write Packet + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int32_t cam_eeprom_write(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int32_t rc = 0; + struct i2c_settings_array *i2c_set = NULL; + struct i2c_settings_list *i2c_list = NULL; + + i2c_set = &e_ctrl->wr_settings; + + if (i2c_set->is_settings_valid == 1) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = camera_io_dev_write_continuous( + &e_ctrl->io_master_info, + &i2c_list->i2c_settings, 1); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "Error in EEPROM write"); + goto del_req; + } + } + } + +del_req: + delete_eeprom_request(i2c_set); + return rc; +} + +/** + * cam_eeprom_pkt_parse - Parse csl packet + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) +{ + int32_t rc = 0; + struct cam_control *ioctl_ctrl = NULL; + struct cam_config_dev_cmd dev_config; + uintptr_t generic_pkt_addr; + size_t pkt_len; + size_t remain_len = 0; + struct cam_packet *csl_packet = NULL; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user(&dev_config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(dev_config))) + return -EFAULT; + rc = cam_mem_get_cpu_buf(dev_config.packet_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_EEPROM, + "error in converting command Handle Error: %d", rc); + return rc; + } + + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_EEPROM, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + rc = -EINVAL; + return rc; + } + + remain_len -= (size_t)dev_config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_EEPROM, "Invalid packet params"); + rc = -EINVAL; + return rc; + } + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_EEPROM_PACKET_OPCODE_INIT: + if (e_ctrl->userspace_probe == false) { + rc = cam_eeprom_parse_read_memory_map( + e_ctrl->soc_info.dev->of_node, e_ctrl); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); + return rc; + } + rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + CAM_DBG(CAM_EEPROM, + "Returning the data using kernel probe"); + break; + } + rc = cam_eeprom_init_pkt_parser(e_ctrl, csl_packet); + if (rc) { + CAM_ERR(CAM_EEPROM, + "Failed in parsing the pkt"); + return rc; + } + + e_ctrl->cal_data.mapdata = + vzalloc(e_ctrl->cal_data.num_data); + if (!e_ctrl->cal_data.mapdata) { + rc = -ENOMEM; + CAM_ERR(CAM_EEPROM, "failed"); + goto error; + } + + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) { + rc = cam_eeprom_match_id(e_ctrl); + if (rc) { + CAM_DBG(CAM_EEPROM, + "eeprom not matching %d", rc); + goto memdata_free; + } + } + + rc = cam_eeprom_power_up(e_ctrl, + &soc_private->power_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed rc %d", rc); + goto memdata_free; + } + + e_ctrl->cam_eeprom_state = CAM_EEPROM_CONFIG; + rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data); + if (rc) { + CAM_ERR(CAM_EEPROM, + "read_eeprom_memory failed"); + goto power_down; + } + + rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); + rc = cam_eeprom_power_down(e_ctrl); + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + break; + case CAM_EEPROM_WRITE: { + struct i2c_settings_array *i2c_reg_settings = + &e_ctrl->wr_settings; + + i2c_reg_settings->is_settings_valid = 1; + rc = cam_eeprom_parse_write_memory_packet( + csl_packet, e_ctrl); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); + return rc; + } + + rc = cam_eeprom_power_up(e_ctrl, + &soc_private->power_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed power up rc %d", rc); + goto memdata_free; + } + + usleep_range(10*1000, 11*1000); + CAM_DBG(CAM_EEPROM, + "Calling Erase : %d start Address: 0x%x size: %d", + rc, e_ctrl->eebin_info.start_address, + e_ctrl->eebin_info.size); + + rc = camera_io_dev_erase(&e_ctrl->io_master_info, + e_ctrl->eebin_info.start_address, + e_ctrl->eebin_info.size); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed in erase : %d", rc); + return rc; + } + + /* Buffer time margin */ + usleep_range(10*1000, 11*1000); + + rc = cam_eeprom_write(e_ctrl); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); + return rc; + } + + rc = cam_eeprom_power_down(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed power down rc %d", rc); + goto memdata_free; + } + + break; + } + default: + CAM_ERR(CAM_EEPROM, "Invalid op-code 0x%x", + csl_packet->header.op_code & 0xFFFFFF); + rc = -EINVAL; + break; + } + + return rc; +power_down: + cam_eeprom_power_down(e_ctrl); +memdata_free: + vfree(e_ctrl->cal_data.mapdata); +error: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + vfree(e_ctrl->cal_data.map); + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + return rc; +} + +void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + if (e_ctrl->cam_eeprom_state == CAM_EEPROM_INIT) + return; + + if (e_ctrl->cam_eeprom_state == CAM_EEPROM_CONFIG) { + rc = cam_eeprom_power_down(e_ctrl); + if (rc < 0) + CAM_ERR(CAM_EEPROM, "EEPROM Power down failed"); + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + } + + if (e_ctrl->cam_eeprom_state == CAM_EEPROM_ACQUIRE) { + rc = cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_EEPROM, "destroying the device hdl"); + + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.link_hdl = -1; + e_ctrl->bridge_intf.session_hdl = -1; + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + } + + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; +} + +/** + * cam_eeprom_driver_cmd - Handle eeprom cmds + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) +{ + int rc = 0; + struct cam_eeprom_query_cap_t eeprom_cap = {0}; + struct cam_control *cmd = (struct cam_control *)arg; + + if (!e_ctrl || !cmd) { + CAM_ERR(CAM_EEPROM, "Invalid Arguments"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_EEPROM, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + mutex_lock(&(e_ctrl->eeprom_mutex)); + switch (cmd->op_code) { + case CAM_QUERY_CAP: + eeprom_cap.slot_info = e_ctrl->soc_info.index; + if (e_ctrl->userspace_probe == false) + eeprom_cap.eeprom_kernel_probe = true; + else + eeprom_cap.eeprom_kernel_probe = false; + + eeprom_cap.is_multimodule_mode = + e_ctrl->is_multimodule_mode; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &eeprom_cap, + sizeof(struct cam_eeprom_query_cap_t))) { + CAM_ERR(CAM_EEPROM, "Failed Copy to User"); + return -EFAULT; + goto release_mutex; + } + CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info); + break; + case CAM_ACQUIRE_DEV: + rc = cam_eeprom_get_dev_handle(e_ctrl, arg); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to acquire dev"); + goto release_mutex; + } + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + break; + case CAM_RELEASE_DEV: + if (e_ctrl->cam_eeprom_state != CAM_EEPROM_ACQUIRE) { + rc = -EINVAL; + CAM_WARN(CAM_EEPROM, + "Not in right state to release : %d", + e_ctrl->cam_eeprom_state); + goto release_mutex; + } + + if (e_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_EEPROM, + "Invalid Handles: link hdl: %d device hdl: %d", + e_ctrl->bridge_intf.device_hdl, + e_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_EEPROM, + "failed in destroying the device hdl"); + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.link_hdl = -1; + e_ctrl->bridge_intf.session_hdl = -1; + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + break; + case CAM_CONFIG_DEV: + rc = cam_eeprom_pkt_parse(e_ctrl, arg); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed in eeprom pkt Parsing"); + goto release_mutex; + } + break; + default: + CAM_DBG(CAM_EEPROM, "invalid opcode"); + break; + } + +release_mutex: + mutex_unlock(&(e_ctrl->eeprom_mutex)); + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.h b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.h new file mode 100644 index 000000000000..6a1e867542cb --- /dev/null +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_EEPROM_CORE_H_ +#define _CAM_EEPROM_CORE_H_ + +#include "cam_eeprom_dev.h" + +int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg); +int32_t cam_eeprom_parse_read_memory_map(struct device_node *of_node, + struct cam_eeprom_ctrl_t *e_ctrl); +/** + * @e_ctrl: EEPROM ctrl structure + * + * This API handles the shutdown ioctl/close + */ +void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl); + +#endif +/* _CAM_EEPROM_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c new file mode 100644 index 000000000000..328541553b59 --- /dev/null +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_eeprom_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_eeprom_soc.h" +#include "cam_eeprom_core.h" +#include "cam_debug_util.h" + +static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_eeprom_driver_cmd(e_ctrl, arg); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + +static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_eeprom_ctrl_t *e_ctrl = + v4l2_get_subdevdata(sd); + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "e_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + + return 0; +} + +int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_eeprom_i2c_info_t *i2c_info) +{ + struct cam_sensor_cci_client *cci_client = NULL; + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) { + cci_client = e_ctrl->io_master_info.cci_client; + if (!cci_client) { + CAM_ERR(CAM_EEPROM, "failed: cci_client %pK", + cci_client); + return -EINVAL; + } + cci_client->cci_i2c_master = e_ctrl->cci_i2c_master; + cci_client->sid = (i2c_info->slave_addr) >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + } else if (e_ctrl->io_master_info.master_type == I2C_MASTER) { + e_ctrl->io_master_info.client->addr = i2c_info->slave_addr; + CAM_DBG(CAM_EEPROM, "Slave addr: 0x%x", i2c_info->slave_addr); + } else if (e_ctrl->io_master_info.master_type == SPI_MASTER) { + CAM_ERR(CAM_EEPROM, "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, i2c_info->i2c_freq_mode); + } + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_eeprom_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_EEPROM, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_eeprom_subdev_ioctl(sd, cmd, &cmd_data); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "Failed in eeprom suddev handling rc %d", + rc); + return rc; + } + break; + default: + CAM_ERR(CAM_EEPROM, "Invalid compat ioctl: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_EEPROM, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + return rc; +} +#endif + +static const struct v4l2_subdev_internal_ops cam_eeprom_internal_ops = { + .close = cam_eeprom_subdev_close, +}; + +static struct v4l2_subdev_core_ops cam_eeprom_subdev_core_ops = { + .ioctl = cam_eeprom_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_eeprom_init_subdev_do_ioctl, +#endif +}; + +static struct v4l2_subdev_ops cam_eeprom_subdev_ops = { + .core = &cam_eeprom_subdev_core_ops, +}; + +static int cam_eeprom_init_subdev(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0; + + e_ctrl->v4l2_dev_str.internal_ops = &cam_eeprom_internal_ops; + e_ctrl->v4l2_dev_str.ops = &cam_eeprom_subdev_ops; + strlcpy(e_ctrl->device_name, CAM_EEPROM_NAME, + sizeof(e_ctrl->device_name)); + e_ctrl->v4l2_dev_str.name = e_ctrl->device_name; + e_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + e_ctrl->v4l2_dev_str.ent_function = CAM_EEPROM_DEVICE_TYPE; + e_ctrl->v4l2_dev_str.token = e_ctrl; + + rc = cam_register_subdev(&(e_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev"); + + return rc; +} + +static int cam_eeprom_i2c_driver_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = NULL; + struct cam_eeprom_soc_private *soc_private = NULL; + struct cam_hw_soc_info *soc_info = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_EEPROM, "i2c_check_functionality failed"); + goto probe_failure; + } + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "kzalloc failed"); + rc = -ENOMEM; + goto probe_failure; + } + + soc_private = kzalloc(sizeof(*soc_private), GFP_KERNEL); + if (!soc_private) + goto ectrl_free; + + e_ctrl->soc_info.soc_private = soc_private; + + i2c_set_clientdata(client, e_ctrl); + + mutex_init(&(e_ctrl->eeprom_mutex)); + + INIT_LIST_HEAD(&(e_ctrl->wr_settings.list_head)); + soc_info = &e_ctrl->soc_info; + soc_info->dev = &client->dev; + soc_info->dev_name = client->name; + e_ctrl->io_master_info.master_type = I2C_MASTER; + e_ctrl->io_master_info.client = client; + e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; + e_ctrl->cal_data.mapdata = NULL; + e_ctrl->cal_data.map = NULL; + e_ctrl->userspace_probe = false; + + rc = cam_eeprom_parse_dt(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: soc init rc %d", rc); + goto free_soc; + } + + rc = cam_eeprom_update_i2c_info(e_ctrl, &soc_private->i2c_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: to update i2c info rc %d", rc); + goto free_soc; + } + + rc = cam_eeprom_init_subdev(e_ctrl); + if (rc) + goto free_soc; + + if (soc_private->i2c_info.slave_addr != 0) + e_ctrl->io_master_info.client->addr = + soc_private->i2c_info.slave_addr; + + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.ops.get_dev_info = NULL; + e_ctrl->bridge_intf.ops.link_setup = NULL; + e_ctrl->bridge_intf.ops.apply_req = NULL; + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + + return rc; +free_soc: + kfree(soc_private); +ectrl_free: + kfree(e_ctrl); +probe_failure: + return rc; +} + +static int cam_eeprom_i2c_driver_remove(struct i2c_client *client) +{ + int i; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct cam_eeprom_ctrl_t *e_ctrl; + struct cam_eeprom_soc_private *soc_private; + struct cam_hw_soc_info *soc_info; + + if (!sd) { + CAM_ERR(CAM_EEPROM, "Subdevice is NULL"); + return -EINVAL; + } + + e_ctrl = (struct cam_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "eeprom device is NULL"); + return -EINVAL; + } + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + if (!soc_private) { + CAM_ERR(CAM_EEPROM, "soc_info.soc_private is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_EEPROM, "i2c driver remove invoked"); + soc_info = &e_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); + kfree(soc_private); + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); + kfree(e_ctrl); + + return 0; +} + +static int cam_eeprom_spi_setup(struct spi_device *spi) +{ + struct cam_eeprom_ctrl_t *e_ctrl = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_sensor_spi_client *spi_client; + struct cam_eeprom_soc_private *eb_info; + struct cam_sensor_power_ctrl_t *power_info = NULL; + int rc = 0; + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) + return -ENOMEM; + + soc_info = &e_ctrl->soc_info; + soc_info->dev = &spi->dev; + soc_info->dev_name = spi->modalias; + + e_ctrl->v4l2_dev_str.ops = &cam_eeprom_subdev_ops; + e_ctrl->userspace_probe = false; + e_ctrl->cal_data.mapdata = NULL; + e_ctrl->cal_data.map = NULL; + + spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL); + if (!spi_client) { + kfree(e_ctrl); + return -ENOMEM; + } + + eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL); + if (!eb_info) + goto spi_free; + e_ctrl->soc_info.soc_private = eb_info; + + e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE; + e_ctrl->io_master_info.spi_client = spi_client; + e_ctrl->io_master_info.master_type = SPI_MASTER; + spi_client->spi_master = spi; + INIT_LIST_HEAD(&(e_ctrl->wr_settings.list_head)); + power_info = &eb_info->power_info; + power_info->dev = &spi->dev; + + /* set spi instruction info */ + spi_client->retry_delay = 1; + spi_client->retries = 0; + + /* Initialize mutex */ + mutex_init(&(e_ctrl->eeprom_mutex)); + + e_ctrl->bridge_intf.device_hdl = -1; + rc = cam_eeprom_parse_dt(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: spi soc init rc %d", rc); + goto board_free; + } + + rc = cam_eeprom_spi_parse_of(spi_client); + if (rc) { + CAM_ERR(CAM_EEPROM, "Device tree parsing error"); + goto board_free; + } + + rc = cam_eeprom_init_subdev(e_ctrl); + if (rc) + goto board_free; + + e_ctrl->bridge_intf.ops.get_dev_info = NULL; + e_ctrl->bridge_intf.ops.link_setup = NULL; + e_ctrl->bridge_intf.ops.apply_req = NULL; + + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl); + return rc; + +board_free: + kfree(e_ctrl->soc_info.soc_private); +spi_free: + kfree(spi_client); + kfree(e_ctrl); + return rc; +} + +static int cam_eeprom_spi_driver_probe(struct spi_device *spi) +{ + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + spi_setup(spi); + + CAM_DBG(CAM_EEPROM, "irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]", + spi->irq, spi->chip_select, (spi->mode & SPI_CPHA) ? 1 : 0, + (spi->mode & SPI_CPOL) ? 1 : 0, + (spi->mode & SPI_CS_HIGH) ? 1 : 0); + CAM_DBG(CAM_EEPROM, "max_speed[%u]", spi->max_speed_hz); + + return cam_eeprom_spi_setup(spi); +} + +static int cam_eeprom_spi_driver_remove(struct spi_device *sdev) +{ + int i; + struct v4l2_subdev *sd = spi_get_drvdata(sdev); + struct cam_eeprom_ctrl_t *e_ctrl; + struct cam_eeprom_soc_private *soc_private; + struct cam_hw_soc_info *soc_info; + + if (!sd) { + CAM_ERR(CAM_EEPROM, "Subdevice is NULL"); + return -EINVAL; + } + + e_ctrl = (struct cam_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "eeprom device is NULL"); + return -EINVAL; + } + + soc_info = &e_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); + kfree(e_ctrl->io_master_info.spi_client); + e_ctrl->io_master_info.spi_client = NULL; + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + if (soc_private) { + kfree(soc_private->power_info.gpio_num_info); + soc_private->power_info.gpio_num_info = NULL; + kfree(soc_private); + soc_private = NULL; + } + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); + kfree(e_ctrl); + + return 0; +} + +static int32_t cam_eeprom_platform_driver_probe( + struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = NULL; + struct cam_eeprom_soc_private *soc_private = NULL; + + e_ctrl = kzalloc(sizeof(struct cam_eeprom_ctrl_t), GFP_KERNEL); + if (!e_ctrl) + return -ENOMEM; + + e_ctrl->soc_info.pdev = pdev; + e_ctrl->soc_info.dev = &pdev->dev; + e_ctrl->soc_info.dev_name = pdev->name; + e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE; + e_ctrl->cal_data.mapdata = NULL; + e_ctrl->cal_data.map = NULL; + e_ctrl->userspace_probe = false; + + e_ctrl->io_master_info.master_type = CCI_MASTER; + e_ctrl->io_master_info.cci_client = kzalloc( + sizeof(struct cam_sensor_cci_client), GFP_KERNEL); + if (!e_ctrl->io_master_info.cci_client) { + rc = -ENOMEM; + goto free_e_ctrl; + } + + soc_private = kzalloc(sizeof(struct cam_eeprom_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_cci_client; + } + e_ctrl->soc_info.soc_private = soc_private; + soc_private->power_info.dev = &pdev->dev; + + /* Initialize mutex */ + mutex_init(&(e_ctrl->eeprom_mutex)); + rc = cam_eeprom_parse_dt(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: soc init rc %d", rc); + goto free_soc; + } + rc = cam_eeprom_update_i2c_info(e_ctrl, &soc_private->i2c_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: to update i2c info rc %d", rc); + goto free_soc; + } + + INIT_LIST_HEAD(&(e_ctrl->wr_settings.list_head)); + rc = cam_eeprom_init_subdev(e_ctrl); + if (rc) + goto free_soc; + + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.ops.get_dev_info = NULL; + e_ctrl->bridge_intf.ops.link_setup = NULL; + e_ctrl->bridge_intf.ops.apply_req = NULL; + platform_set_drvdata(pdev, e_ctrl); + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + + return rc; +free_soc: + kfree(soc_private); +free_cci_client: + kfree(e_ctrl->io_master_info.cci_client); +free_e_ctrl: + kfree(e_ctrl); + + return rc; +} + +static int cam_eeprom_platform_driver_remove(struct platform_device *pdev) +{ + int i; + struct cam_eeprom_ctrl_t *e_ctrl; + struct cam_hw_soc_info *soc_info; + + e_ctrl = platform_get_drvdata(pdev); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "eeprom device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_EEPROM, "Platform driver remove invoked"); + soc_info = &e_ctrl->soc_info; + + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); + kfree(soc_info->soc_private); + kfree(e_ctrl->io_master_info.cci_client); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); + kfree(e_ctrl); + + return 0; +} + +static const struct of_device_id cam_eeprom_dt_match[] = { + { .compatible = "qcom,eeprom" }, + { } +}; + + +MODULE_DEVICE_TABLE(of, cam_eeprom_dt_match); + +static struct platform_driver cam_eeprom_platform_driver = { + .driver = { + .name = "qcom,eeprom", + .owner = THIS_MODULE, + .of_match_table = cam_eeprom_dt_match, + .suppress_bind_attrs = true, + }, + .probe = cam_eeprom_platform_driver_probe, + .remove = cam_eeprom_platform_driver_remove, +}; + +static const struct i2c_device_id cam_eeprom_i2c_id[] = { + { "msm_eeprom", (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_eeprom_i2c_driver = { + .id_table = cam_eeprom_i2c_id, + .probe = cam_eeprom_i2c_driver_probe, + .remove = cam_eeprom_i2c_driver_remove, + .driver = { + .name = "msm_eeprom", + }, +}; + +static struct spi_driver cam_eeprom_spi_driver = { + .driver = { + .name = "qcom_eeprom", + .owner = THIS_MODULE, + .of_match_table = cam_eeprom_dt_match, + }, + .probe = cam_eeprom_spi_driver_probe, + .remove = cam_eeprom_spi_driver_remove, +}; +static int __init cam_eeprom_driver_init(void) +{ + int rc = 0; + + rc = platform_driver_register(&cam_eeprom_platform_driver); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "platform_driver_register failed rc = %d", + rc); + return rc; + } + + rc = spi_register_driver(&cam_eeprom_spi_driver); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "spi_register_driver failed rc = %d", rc); + return rc; + } + + rc = i2c_add_driver(&cam_eeprom_i2c_driver); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "i2c_add_driver failed rc = %d", rc); + return rc; + } + + return rc; +} + +static void __exit cam_eeprom_driver_exit(void) +{ + platform_driver_unregister(&cam_eeprom_platform_driver); + spi_unregister_driver(&cam_eeprom_spi_driver); + i2c_del_driver(&cam_eeprom_i2c_driver); +} + +module_init(cam_eeprom_driver_init); +module_exit(cam_eeprom_driver_exit); +MODULE_DESCRIPTION("CAM EEPROM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h new file mode 100644 index 000000000000..2bac99f8c298 --- /dev/null +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_EEPROM_DEV_H_ +#define _CAM_EEPROM_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_soc_util.h" + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define PROPERTY_MAXSIZE 32 + +#define MSM_EEPROM_MEMORY_MAP_MAX_SIZE 80 +#define MSM_EEPROM_MAX_MEM_MAP_CNT 8 +#define MSM_EEPROM_MEM_MAP_PROPERTIES_CNT 8 + +enum cam_eeprom_state { + CAM_EEPROM_INIT, + CAM_EEPROM_ACQUIRE, + CAM_EEPROM_CONFIG, +}; + +/** + * struct cam_eeprom_map_t - eeprom map + * @data_type : Data type + * @addr_type : Address type + * @addr : Address + * @data : data + * @delay : Delay + * + */ +struct cam_eeprom_map_t { + uint32_t valid_size; + uint32_t addr; + uint32_t addr_type; + uint32_t data; + uint32_t data_type; + uint32_t delay; +}; + +/** + * struct cam_eeprom_memory_map_t - eeprom memory map types + * @page : page memory + * @pageen : pageen memory + * @poll : poll memory + * @mem : mem + * @saddr : slave addr + * + */ +struct cam_eeprom_memory_map_t { + struct cam_eeprom_map_t page; + struct cam_eeprom_map_t pageen; + struct cam_eeprom_map_t poll; + struct cam_eeprom_map_t mem; + uint32_t saddr; +}; + +/** + * struct cam_eeprom_memory_block_t - eeprom mem block info + * @map : eeprom memory map + * @num_map : number of map blocks + * @mapdata : map data + * @cmd_type : size of total mapdata + * + */ +struct cam_eeprom_memory_block_t { + struct cam_eeprom_memory_map_t *map; + uint32_t num_map; + uint8_t *mapdata; + uint32_t num_data; +}; + +/** + * struct cam_eeprom_cmm_t - camera multimodule + * @cmm_support : cmm support flag + * @cmm_compression : cmm compression flag + * @cmm_offset : cmm data start offset + * @cmm_size : cmm data size + * + */ +struct cam_eeprom_cmm_t { + uint32_t cmm_support; + uint32_t cmm_compression; + uint32_t cmm_offset; + uint32_t cmm_size; +}; + +/** + * struct cam_eeprom_i2c_info_t - I2C info + * @slave_addr : slave address + * @i2c_freq_mode : i2c frequency mode + * + */ +struct cam_eeprom_i2c_info_t { + uint16_t slave_addr; + uint8_t i2c_freq_mode; +}; + +/** + * struct cam_eeprom_soc_private - eeprom soc private data structure + * @eeprom_name : eeprom name + * @i2c_info : i2c info structure + * @power_info : eeprom power info + * @cmm_data : cmm data + * + */ +struct cam_eeprom_soc_private { + const char *eeprom_name; + struct cam_eeprom_i2c_info_t i2c_info; + struct cam_sensor_power_ctrl_t power_info; + struct cam_eeprom_cmm_t cmm_data; +}; + +/** + * struct cam_eeprom_intf_params - bridge interface params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_eeprom_intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +struct eebin_info { + uint32_t start_address; + uint32_t size; + uint32_t is_valid; +}; + +/** + * struct cam_eeprom_ctrl_t - EEPROM control structure + * @pdev : platform device + * @spi : spi device + * @eeprom_mutex : eeprom mutex + * @soc_info : eeprom soc related info + * @io_master_info : Information about the communication master + * @gpio_num_info : gpio info + * @cci_i2c_master : I2C structure + * @v4l2_dev_str : V4L2 device structure + * @bridge_intf : bridge interface params + * @cam_eeprom_state : eeprom_device_state + * @userspace_probe : flag indicates userspace or kernel probe + * @cal_data : Calibration data + * @device_name : Device name + * @is_multimodule_mode : To identify multimodule node + * @wr_settings : I2C write settings + * @eebin_info : EEBIN address, size info + */ +struct cam_eeprom_ctrl_t { + struct platform_device *pdev; + struct spi_device *spi; + struct mutex eeprom_mutex; + struct cam_hw_soc_info soc_info; + struct camera_io_master io_master_info; + struct msm_camera_gpio_num_info *gpio_num_info; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct cam_subdev v4l2_dev_str; + struct cam_eeprom_intf_params bridge_intf; + enum msm_camera_device_type_t eeprom_device_type; + enum cam_eeprom_state cam_eeprom_state; + bool userspace_probe; + struct cam_eeprom_memory_block_t cal_data; + char device_name[20]; + uint16_t is_multimodule_mode; + struct i2c_settings_array wr_settings; + struct eebin_info eebin_info; +}; + +int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_eeprom_i2c_info_t *i2c_info); + +#endif /*_CAM_EEPROM_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c new file mode 100644 index 000000000000..33f80b0c9716 --- /dev/null +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_eeprom_soc.h" +#include "cam_debug_util.h" + +#define cam_eeprom_spi_parse_cmd(spi_dev, name, out) \ + { \ + spi_dev->cmd_tbl.name.opcode = out[0]; \ + spi_dev->cmd_tbl.name.addr_len = out[1]; \ + spi_dev->cmd_tbl.name.dummy_len = out[2]; \ + spi_dev->cmd_tbl.name.delay_intv = out[3]; \ + spi_dev->cmd_tbl.name.delay_count = out[4]; \ + } + +int cam_eeprom_spi_parse_of(struct cam_sensor_spi_client *spi_dev) +{ + int rc = -EFAULT; + uint32_t tmp[5]; + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-read", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, read, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get read data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-readseq", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, read_seq, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get readseq data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-queryid", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, query_id, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get queryid data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-pprog", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, page_program, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get page program data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-wenable", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, write_enable, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get write enable data"); + return rc; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-readst", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, read_status, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get readdst data"); + return rc; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-erase", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, erase, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get erase data"); + return rc; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "eeprom-id", tmp, 2); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to get eeprom id"); + return rc; + } + + spi_dev->mfr_id0 = tmp[0]; + spi_dev->device_id0 = tmp[1]; + + return 0; +} + +/* + * cam_eeprom_parse_memory_map() - parse memory map in device node + * @of: device node + * @data: memory block for output + * + * This functions parses @of to fill @data. It allocates map itself, parses + * the @of node, calculate total data length, and allocates required buffer. + * It only fills the map, but does not perform actual reading. + */ +int cam_eeprom_parse_dt_memory_map(struct device_node *node, + struct cam_eeprom_memory_block_t *data) +{ + int i, rc = 0; + char property[PROPERTY_MAXSIZE]; + uint32_t count = MSM_EEPROM_MEM_MAP_PROPERTIES_CNT; + struct cam_eeprom_memory_map_t *map; + + snprintf(property, PROPERTY_MAXSIZE, "num-blocks"); + rc = of_property_read_u32(node, property, &data->num_map); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: num-blocks not available rc %d", + rc); + return rc; + } + + map = vzalloc((sizeof(*map) * data->num_map)); + if (!map) { + rc = -ENOMEM; + return rc; + } + data->map = map; + + for (i = 0; i < data->num_map; i++) { + snprintf(property, PROPERTY_MAXSIZE, "page%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].page, count); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: page not available rc %d", + rc); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "pageen%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].pageen, count); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "pageen not needed"); + + snprintf(property, PROPERTY_MAXSIZE, "saddr%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].saddr, 1); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "saddr not needed - block %d", i); + + snprintf(property, PROPERTY_MAXSIZE, "poll%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].poll, count); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: poll not available rc %d", + rc); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "mem%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].mem, count); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: mem not available rc %d", + rc); + goto ERROR; + } + data->num_data += map[i].mem.valid_size; + } + + data->mapdata = vzalloc(data->num_data); + if (!data->mapdata) { + rc = -ENOMEM; + goto ERROR; + } + return rc; + +ERROR: + vfree(data->map); + memset(data, 0, sizeof(*data)); + return rc; +} + +/** + * @e_ctrl: ctrl structure + * + * Parses eeprom dt + */ +static int cam_eeprom_get_dt_data(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = &e_ctrl->soc_info; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + struct device_node *of_node = NULL; + + of_node = soc_info->dev->of_node; + + if (e_ctrl->userspace_probe == false) { + rc = cam_get_dt_power_setting_data(of_node, + soc_info, power_info); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed in getting power settings"); + return rc; + } + } + + if (!soc_info->gpio_data) { + CAM_INFO(CAM_EEPROM, "No GPIO found"); + return 0; + } + + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_INFO(CAM_EEPROM, "No GPIO found"); + return -EINVAL; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &power_info->gpio_num_info); + if ((rc < 0) || (!power_info->gpio_num_info)) { + CAM_ERR(CAM_EEPROM, "No/Error EEPROM GPIOs"); + return -EINVAL; + } + + return rc; +} + +/** + * @eb_info: eeprom private data structure + * @of_node: eeprom device node + * + * This function parses the eeprom dt to get the MM data + */ +static int cam_eeprom_cmm_dts(struct cam_eeprom_soc_private *eb_info, + struct device_node *of_node) +{ + int rc = 0; + struct cam_eeprom_cmm_t *cmm_data = &eb_info->cmm_data; + + cmm_data->cmm_support = + of_property_read_bool(of_node, "cmm-data-support"); + if (!cmm_data->cmm_support) { + CAM_DBG(CAM_EEPROM, "No cmm support"); + return 0; + } + + cmm_data->cmm_compression = + of_property_read_bool(of_node, "cmm-data-compressed"); + + rc = of_property_read_u32(of_node, "cmm-data-offset", + &cmm_data->cmm_offset); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "No MM offset data rc %d", rc); + + rc = of_property_read_u32(of_node, "cmm-data-size", + &cmm_data->cmm_size); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "No MM size data rc %d", rc); + + CAM_DBG(CAM_EEPROM, "cmm_compr %d, cmm_offset %d, cmm_size %d", + cmm_data->cmm_compression, cmm_data->cmm_offset, + cmm_data->cmm_size); + return 0; +} + +/** + * @e_ctrl: ctrl structure + * + * This function is called from cam_eeprom_platform/i2c/spi_driver_probe + * it parses the eeprom dt node and decides for userspace or kernel probe. + */ +int cam_eeprom_parse_dt(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int i, rc = 0; + struct cam_hw_soc_info *soc_info = &e_ctrl->soc_info; + struct device_node *of_node = NULL; + struct device_node *of_parent = NULL; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + uint32_t temp; + + if (!soc_info->dev) { + CAM_ERR(CAM_EEPROM, "Dev is NULL"); + return -EINVAL; + } + + e_ctrl->is_multimodule_mode = false; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed to read DT properties rc : %d", rc); + return rc; + } + + of_node = soc_info->dev->of_node; + + if (of_property_read_bool(of_node, "multimodule-support")) { + CAM_DBG(CAM_UTIL, "Multi Module is Supported"); + e_ctrl->is_multimodule_mode = true; + } + + rc = of_property_read_string(of_node, "eeprom-name", + &soc_private->eeprom_name); + if (rc < 0) { + CAM_DBG(CAM_EEPROM, "kernel probe is not enabled"); + e_ctrl->userspace_probe = true; + } + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) { + rc = of_property_read_u32(of_node, "cci-master", + &e_ctrl->cci_i2c_master); + if (rc < 0 || (e_ctrl->cci_i2c_master >= MASTER_MAX)) { + CAM_DBG(CAM_EEPROM, "failed rc %d", rc); + rc = -EFAULT; + return rc; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &e_ctrl->cci_num) < 0) + /* Set default master 0 */ + e_ctrl->cci_num = CCI_DEVICE_0; + + e_ctrl->io_master_info.cci_client->cci_device = e_ctrl->cci_num; + CAM_DBG(CAM_EEPROM, "cci-index %d", e_ctrl->cci_num, rc); + } + + if (e_ctrl->io_master_info.master_type == SPI_MASTER) { + rc = cam_eeprom_cmm_dts(soc_private, soc_info->dev->of_node); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "MM data not available rc %d", rc); + } + + rc = cam_eeprom_get_dt_data(e_ctrl); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "failed: eeprom get dt data rc %d", rc); + + if ((e_ctrl->userspace_probe == false) && + (e_ctrl->io_master_info.master_type != SPI_MASTER)) { + rc = of_property_read_u32(of_node, "slave-addr", &temp); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "failed: no slave-addr rc %d", rc); + + soc_private->i2c_info.slave_addr = temp; + + rc = of_property_read_u32(of_node, "i2c-freq-mode", &temp); + soc_private->i2c_info.i2c_freq_mode = temp; + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "i2c-freq-mode read fail %d", rc); + soc_private->i2c_info.i2c_freq_mode = 0; + } + if (soc_private->i2c_info.i2c_freq_mode >= I2C_MAX_MODES) { + CAM_ERR(CAM_EEPROM, "invalid i2c_freq_mode = %d", + soc_private->i2c_info.i2c_freq_mode); + soc_private->i2c_info.i2c_freq_mode = 0; + } + CAM_DBG(CAM_EEPROM, "slave-addr = 0x%X", + soc_private->i2c_info.slave_addr); + } + + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = devm_clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_EEPROM, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + return rc; + } + } + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h new file mode 100644 index 000000000000..ed37989eb2d7 --- /dev/null +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_EEPROM_SOC_H_ +#define _CAM_EEPROM_SOC_H_ + +#include "cam_eeprom_dev.h" + +int cam_eeprom_spi_parse_of(struct cam_sensor_spi_client *client); + +int cam_eeprom_parse_dt_memory_map(struct device_node *of, + struct cam_eeprom_memory_block_t *data); + +int cam_eeprom_parse_dt(struct cam_eeprom_ctrl_t *e_ctrl); +#endif/* _CAM_EEPROM_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_flash/Makefile b/drivers/cam_sensor_module/cam_flash/Makefile new file mode 100644 index 000000000000..dfc2bc2c8c8c --- /dev/null +++ b/drivers/cam_sensor_module/cam_flash/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash_dev.o cam_flash_core.o cam_flash_soc.o diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c new file mode 100644 index 000000000000..293d1422b393 --- /dev/null +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -0,0 +1,1812 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include + +#include "cam_sensor_cmn_header.h" +#include "cam_flash_core.h" +#include "cam_res_mgr_api.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, + bool regulator_enable) +{ + int rc = 0; + struct cam_flash_private_soc *soc_private = + (struct cam_flash_private_soc *) + flash_ctrl->soc_info.soc_private; + + if (!(flash_ctrl->switch_trigger)) { + CAM_ERR(CAM_FLASH, "Invalid argument"); + return -EINVAL; + } + + if (soc_private->is_wled_flash) { + if (regulator_enable && + flash_ctrl->is_regulator_enabled == false) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "enable reg failed: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = true; + } else if (!regulator_enable && + flash_ctrl->is_regulator_enabled == true) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "disalbe reg fail: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = false; + } else { + CAM_ERR(CAM_FLASH, "Wrong Wled flash state: %d", + flash_ctrl->flash_state); + rc = -EINVAL; + } + } else { + if (regulator_enable && + (flash_ctrl->is_regulator_enabled == false)) { + rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, + "Regulator enable failed rc = %d", rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = true; + } else if ((!regulator_enable) && + (flash_ctrl->is_regulator_enabled == true)) { + rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, + "Regulator disable failed rc = %d", rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = false; + } else { + CAM_ERR(CAM_FLASH, "Wrong Flash State : %d", + flash_ctrl->flash_state); + rc = -EINVAL; + } + } + return rc; +} + +static int cam_flash_pmic_flush_nrt(struct cam_flash_ctrl *fctrl) +{ + int j = 0; + struct cam_flash_frame_setting *nrt_settings; + + if (!fctrl) + return -EINVAL; + + nrt_settings = &fctrl->nrt_info; + + if (nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO) { + fctrl->flash_init_setting.cmn_attr.is_settings_valid = false; + } else if ((nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) || + (nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_RER) || + (nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE)) { + fctrl->nrt_info.cmn_attr.is_settings_valid = false; + fctrl->nrt_info.cmn_attr.count = 0; + fctrl->nrt_info.num_iterations = 0; + fctrl->nrt_info.led_on_delay_ms = 0; + fctrl->nrt_info.led_off_delay_ms = 0; + for (j = 0; j < CAM_FLASH_MAX_LED_TRIGGERS; j++) + fctrl->nrt_info.led_current_ma[j] = 0; + } + + return 0; +} + +static int cam_flash_i2c_flush_nrt(struct cam_flash_ctrl *fctrl) +{ + int rc = 0; + + if (fctrl->i2c_data.init_settings.is_settings_valid == true) { + rc = delete_request(&fctrl->i2c_data.init_settings); + if (rc) { + CAM_WARN(CAM_FLASH, + "Failed to delete Init i2c_setting: %d", + rc); + return rc; + } + } + if (fctrl->i2c_data.config_settings.is_settings_valid == true) { + rc = delete_request(&fctrl->i2c_data.config_settings); + if (rc) { + CAM_WARN(CAM_FLASH, + "Failed to delete NRT i2c_setting: %d", + rc); + return rc; + } + } + + return rc; +} + +static int cam_flash_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0; + + power_info->power_setting_size = 1; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_setting[0].seq_type = SENSOR_CUSTOM_REG1; + power_info->power_setting[0].seq_val = CAM_V_CUSTOM1; + power_info->power_setting[0].config_val = 0; + power_info->power_setting[0].delay = 2; + + power_info->power_down_setting_size = 1; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + + power_info->power_down_setting[0].seq_type = SENSOR_CUSTOM_REG1; + power_info->power_down_setting[0].seq_val = CAM_V_CUSTOM1; + power_info->power_down_setting[0].config_val = 0; + + return rc; + +free_power_settings: + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return rc; +} + +int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable) +{ + int rc = 0; + + if (!(fctrl->switch_trigger)) { + CAM_ERR(CAM_FLASH, "Invalid argument"); + return -EINVAL; + } + + if (regulator_enable) { + rc = cam_flash_prepare(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + return rc; + } + fctrl->last_flush_req = 0; + } + + if (!regulator_enable) { + if ((fctrl->flash_state == CAM_FLASH_STATE_START) && + (fctrl->is_regulator_enabled == true)) { + rc = cam_flash_prepare(fctrl, false); + if (rc) + CAM_ERR(CAM_FLASH, + "Disable Regulator Failed rc: %d", rc); + } + } + + return rc; +} + +int cam_flash_i2c_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = &fctrl->soc_info; + struct cam_sensor_power_ctrl_t *power_info = + &fctrl->power_info; + + if (!power_info || !soc_info) { + CAM_ERR(CAM_FLASH, "Power Info is NULL"); + return -EINVAL; + } + power_info->dev = soc_info->dev; + + if (regulator_enable && (fctrl->is_regulator_enabled == false)) { + if ((power_info->power_setting == NULL) && + (power_info->power_down_setting == NULL)) { + CAM_INFO(CAM_FLASH, + "Using default power settings"); + rc = cam_flash_construct_default_power_setting( + power_info); + if (rc < 0) { + CAM_ERR(CAM_FLASH, + "Construct default pwr setting failed rc: %d", + rc); + return rc; + } + } + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "power up the core is failed:%d", + rc); + goto free_pwr_settings; + } + + rc = camera_io_init(&(fctrl->io_master_info)); + if (rc) { + CAM_ERR(CAM_FLASH, "cci_init failed: rc: %d", rc); + cam_sensor_util_power_down(power_info, soc_info); + goto free_pwr_settings; + } + fctrl->is_regulator_enabled = true; + } else if ((!regulator_enable) && + (fctrl->is_regulator_enabled == true)) { + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "power down the core is failed:%d", + rc); + return rc; + } + camera_io_release(&(fctrl->io_master_info)); + fctrl->is_regulator_enabled = false; + goto free_pwr_settings; + } + return rc; + +free_pwr_settings: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + + return rc; +} + +int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id) +{ + int rc = 0; + int i = 0, j = 0; + int frame_offset = 0; + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + + if (type == FLUSH_ALL) { + /* flush all requests*/ + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + fctrl->per_frame[i].cmn_attr.request_id = 0; + fctrl->per_frame[i].cmn_attr.is_settings_valid = false; + fctrl->per_frame[i].cmn_attr.count = 0; + for (j = 0; j < CAM_FLASH_MAX_LED_TRIGGERS; j++) + fctrl->per_frame[i].led_current_ma[j] = 0; + } + + cam_flash_pmic_flush_nrt(fctrl); + } else if ((type == FLUSH_REQ) && (req_id != 0)) { + /* flush request with req_id*/ + frame_offset = req_id % MAX_PER_FRAME_ARRAY; + fctrl->per_frame[frame_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid = + false; + fctrl->per_frame[frame_offset].cmn_attr.count = 0; + for (i = 0; i < CAM_FLASH_MAX_LED_TRIGGERS; i++) + fctrl->per_frame[frame_offset].led_current_ma[i] = 0; + } else if ((type == FLUSH_REQ) && (req_id == 0)) { + /* Handels NonRealTime usecase */ + cam_flash_pmic_flush_nrt(fctrl); + } else { + CAM_ERR(CAM_FLASH, "Invalid arguments"); + return -EINVAL; + } + + return rc; +} + +int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id) +{ + int rc = 0; + int i = 0; + uint32_t cancel_req_id_found = 0; + struct i2c_settings_array *i2c_set = NULL; + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + if ((type == FLUSH_REQ) && (req_id == 0)) { + /* This setting will be called only when NonRealTime + * settings needs to clean. + */ + cam_flash_i2c_flush_nrt(fctrl); + } else { + /* All other usecase will be handle here */ + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(fctrl->i2c_data.per_frame[i]); + + if ((type == FLUSH_REQ) && + (i2c_set->request_id != req_id)) + continue; + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_FLASH, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + + if (type == FLUSH_REQ) { + cancel_req_id_found = 1; + break; + } + } + } + } + + if ((type == FLUSH_REQ) && (req_id != 0) && + (!cancel_req_id_found)) + CAM_DBG(CAM_FLASH, + "Flush request id:%lld not found in the pending list", + req_id); + + return rc; +} + +int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush) +{ + int rc = 0; + struct cam_flash_ctrl *fctrl = NULL; + + fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(flush->dev_hdl); + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + if (fctrl->flash_state == CAM_FLASH_STATE_INIT) + goto end; + + if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + fctrl->last_flush_req = flush->req_id; + CAM_DBG(CAM_FLASH, "last reqest to flush is %lld", + flush->req_id); + rc = fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + if (rc) { + CAM_ERR(CAM_FLASH, "FLUSH_TYPE_ALL failed rc: %d", rc); + goto end; + } + } else if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + rc = fctrl->func_tbl.flush_req(fctrl, + FLUSH_REQ, flush->req_id); + if (rc) { + CAM_ERR(CAM_FLASH, "FLUSH_REQ failed rc: %d", rc); + goto end; + } + } +end: + mutex_unlock(&fctrl->flash_mutex); + return rc; +} + +static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, + struct cam_flash_frame_setting *flash_data, enum camera_flash_opcode op) +{ + uint32_t curr = 0, max_current = 0; + struct cam_flash_private_soc *soc_private = NULL; + int i = 0; + + if (!flash_ctrl || !flash_data) { + CAM_ERR(CAM_FLASH, "Fctrl or Data NULL"); + return -EINVAL; + } + + soc_private = (struct cam_flash_private_soc *) + flash_ctrl->soc_info.soc_private; + + if (op == CAMERA_SENSOR_FLASH_OP_FIRELOW) { + for (i = 0; i < flash_ctrl->torch_num_sources; i++) { + if (flash_ctrl->torch_trigger[i]) { + max_current = soc_private->torch_max_current[i]; + if (flash_data->led_current_ma[i] <= + max_current) + curr = flash_data->led_current_ma[i]; + else + curr = max_current; + } + CAM_DBG(CAM_FLASH, "Led_Torch[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->torch_trigger[i], curr); + } + } else if (op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { + for (i = 0; i < flash_ctrl->flash_num_sources; i++) { + if (flash_ctrl->flash_trigger[i]) { + max_current = soc_private->flash_max_current[i]; + if (flash_data->led_current_ma[i] <= + max_current) + curr = flash_data->led_current_ma[i]; + else + curr = max_current; + } + CAM_DBG(CAM_FLASH, "LED_Flash[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->flash_trigger[i], curr); + } + } else { + CAM_ERR(CAM_FLASH, "Wrong Operation: %d", op); + return -EINVAL; + } + + if (flash_ctrl->switch_trigger) + cam_res_mgr_led_trigger_event( + flash_ctrl->switch_trigger, + (enum led_brightness)LED_SWITCH_ON); + + return 0; +} + +int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) +{ + if (!flash_ctrl) { + CAM_ERR(CAM_FLASH, "Flash control Null"); + return -EINVAL; + } + + if (flash_ctrl->switch_trigger) + cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, + (enum led_brightness)LED_SWITCH_OFF); + + flash_ctrl->flash_state = CAM_FLASH_STATE_START; + return 0; +} + +static int cam_flash_low( + struct cam_flash_ctrl *flash_ctrl, + struct cam_flash_frame_setting *flash_data) +{ + int i = 0, rc = 0; + + if (!flash_data) { + CAM_ERR(CAM_FLASH, "Flash Data Null"); + return -EINVAL; + } + + for (i = 0; i < flash_ctrl->flash_num_sources; i++) + if (flash_ctrl->flash_trigger[i]) + cam_res_mgr_led_trigger_event( + flash_ctrl->flash_trigger[i], + LED_OFF); + + rc = cam_flash_ops(flash_ctrl, flash_data, + CAMERA_SENSOR_FLASH_OP_FIRELOW); + if (rc) + CAM_ERR(CAM_FLASH, "Fire Torch failed: %d", rc); + + return rc; +} + +static int cam_flash_high( + struct cam_flash_ctrl *flash_ctrl, + struct cam_flash_frame_setting *flash_data) +{ + int i = 0, rc = 0; + + if (!flash_data) { + CAM_ERR(CAM_FLASH, "Flash Data Null"); + return -EINVAL; + } + + for (i = 0; i < flash_ctrl->torch_num_sources; i++) + if (flash_ctrl->torch_trigger[i]) + cam_res_mgr_led_trigger_event( + flash_ctrl->torch_trigger[i], + LED_OFF); + + rc = cam_flash_ops(flash_ctrl, flash_data, + CAMERA_SENSOR_FLASH_OP_FIREHIGH); + if (rc) + CAM_ERR(CAM_FLASH, "Fire Flash Failed: %d", rc); + + return rc; +} + +static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + int i = 0, rc = 0; + uint64_t top = 0, del_req_id = 0; + + if (req_id != 0) { + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((req_id >= + fctrl->i2c_data.per_frame[i].request_id) && + (top < + fctrl->i2c_data.per_frame[i].request_id) && + (fctrl->i2c_data.per_frame[i].is_settings_valid + == 1)) { + del_req_id = top; + top = fctrl->i2c_data.per_frame[i].request_id; + } + } + + if (top < req_id) { + if ((((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) || + (((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX)) + del_req_id = req_id; + } + + if (!del_req_id) + return rc; + + CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", + top, del_req_id); + } + fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + return 0; +} + +static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + int i = 0; + struct cam_flash_frame_setting *flash_data = NULL; + uint64_t top = 0, del_req_id = 0; + + if (req_id != 0) { + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + flash_data = &fctrl->per_frame[i]; + if (req_id >= flash_data->cmn_attr.request_id && + flash_data->cmn_attr.is_settings_valid + == 1) { + if (top < flash_data->cmn_attr.request_id) { + del_req_id = top; + top = flash_data->cmn_attr.request_id; + } else if (top > + flash_data->cmn_attr.request_id && + del_req_id < + flash_data->cmn_attr.request_id) { + del_req_id = + flash_data->cmn_attr.request_id; + } + } + } + + if (top < req_id) { + if ((((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) || + (((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX)) + del_req_id = req_id; + } + + if (!del_req_id) + return 0; + + CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", + top, del_req_id); + } + + fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + return 0; +} + +static int32_t cam_flash_slaveInfo_pkt_parser(struct cam_flash_ctrl *fctrl, + uint32_t *cmd_buf, size_t len) +{ + int32_t rc = 0; + struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + + if (len < sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + if (fctrl->io_master_info.master_type == CCI_MASTER) { + fctrl->io_master_info.cci_client->cci_i2c_master = + fctrl->cci_i2c_master; + fctrl->io_master_info.cci_client->i2c_freq_mode = + i2c_info->i2c_freq_mode; + fctrl->io_master_info.cci_client->sid = + i2c_info->slave_addr >> 1; + CAM_DBG(CAM_FLASH, "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, i2c_info->i2c_freq_mode); + } else if (fctrl->io_master_info.master_type == I2C_MASTER) { + fctrl->io_master_info.client->addr = i2c_info->slave_addr; + CAM_DBG(CAM_FLASH, "Slave addr: 0x%x", i2c_info->slave_addr); + } else { + CAM_ERR(CAM_FLASH, "Invalid Master type: %d", + fctrl->io_master_info.master_type); + rc = -EINVAL; + } + + return rc; +} + +int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + struct i2c_settings_list *i2c_list; + struct i2c_settings_array *i2c_set = NULL; + int frame_offset = 0, rc = 0; + + if (req_id == 0) { + /* NonRealTime Init settings*/ + if (fctrl->i2c_data.init_settings.is_settings_valid == true) { + list_for_each_entry(i2c_list, + &(fctrl->i2c_data.init_settings.list_head), + list) { + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply init settings: %d", + rc); + return rc; + } + } + } + /* NonRealTime (Widget/RER/INIT_FIRE settings) */ + if (fctrl->i2c_data.config_settings.is_settings_valid == true) { + list_for_each_entry(i2c_list, + &(fctrl->i2c_data.config_settings.list_head), + list) { + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply NRT settings: %d", rc); + return rc; + } + } + } + } else { + /* RealTime */ + frame_offset = req_id % MAX_PER_FRAME_ARRAY; + i2c_set = &fctrl->i2c_data.per_frame[frame_offset]; + if ((i2c_set->is_settings_valid == true) && + (i2c_set->request_id == req_id)) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_util_i2c_apply_setting( + &(fctrl->io_master_info), i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply settings: %d", rc); + return rc; + } + } + } + } + + cam_flash_i2c_delete_req(fctrl, req_id); + return rc; +} + +int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + int rc = 0, i = 0; + int frame_offset = 0; + uint16_t num_iterations; + struct cam_flash_frame_setting *flash_data = NULL; + + if (req_id == 0) { + if (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE) { + flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_INIT_FIRE req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIREHIGH) { + if (fctrl->flash_state == + CAM_FLASH_STATE_START) { + CAM_WARN(CAM_FLASH, + "Wrong state :Prev state: %d", + fctrl->flash_state); + return -EINVAL; + } + + rc = cam_flash_high(fctrl, flash_data); + if (rc) + CAM_ERR(CAM_FLASH, + "FLASH ON failed : %d", rc); + } + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIRELOW) { + if (fctrl->flash_state == + CAM_FLASH_STATE_START) { + CAM_WARN(CAM_FLASH, + "Wrong state :Prev state: %d", + fctrl->flash_state); + return -EINVAL; + } + + rc = cam_flash_low(fctrl, flash_data); + if (rc) + CAM_ERR(CAM_FLASH, + "TORCH ON failed : %d", rc); + } + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) { + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "LED OFF FAILED: %d", + rc); + return rc; + } + } + } else if (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) { + flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_WIDGET req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIRELOW) { + rc = cam_flash_low(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Torch ON failed : %d", + rc); + goto nrt_del_req; + } + } else if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) { + rc = cam_flash_off(fctrl); + if (rc) + CAM_ERR(CAM_FLASH, + "LED off failed: %d", + rc); + } + } else if (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_RER) { + flash_data = &fctrl->nrt_info; + if (fctrl->flash_state != CAM_FLASH_STATE_START) { + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash off failed: %d", + rc); + goto nrt_del_req; + } + } + CAM_DBG(CAM_REQ, "FLASH_RER req_id: %u", req_id); + + num_iterations = flash_data->num_iterations; + for (i = 0; i < num_iterations; i++) { + /* Turn On Torch */ + if (fctrl->flash_state == + CAM_FLASH_STATE_START) { + rc = cam_flash_low(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Fire Torch Failed"); + goto nrt_del_req; + } + + usleep_range( + flash_data->led_on_delay_ms * 1000, + flash_data->led_on_delay_ms * 1000 + + 100); + } + /* Turn Off Torch */ + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash off failed: %d", rc); + continue; + } + fctrl->flash_state = CAM_FLASH_STATE_START; + usleep_range( + flash_data->led_off_delay_ms * 1000, + flash_data->led_off_delay_ms * 1000 + 100); + } + } + } else { + frame_offset = req_id % MAX_PER_FRAME_ARRAY; + flash_data = &fctrl->per_frame[frame_offset]; + CAM_DBG(CAM_REQ, "FLASH_RT req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + + if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIREHIGH) && + (flash_data->cmn_attr.is_settings_valid) && + (flash_data->cmn_attr.request_id == req_id)) { + /* Turn On Flash */ + if (fctrl->flash_state == CAM_FLASH_STATE_START) { + rc = cam_flash_high(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash ON failed: rc= %d", + rc); + goto apply_setting_err; + } + } + } else if ((flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIRELOW) && + (flash_data->cmn_attr.is_settings_valid) && + (flash_data->cmn_attr.request_id == req_id)) { + /* Turn On Torch */ + if (fctrl->flash_state == CAM_FLASH_STATE_START) { + rc = cam_flash_low(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Torch ON failed: rc= %d", + rc); + goto apply_setting_err; + } + } + } else if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) && + (flash_data->cmn_attr.is_settings_valid) && + (flash_data->cmn_attr.request_id == req_id)) { + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash off failed %d", rc); + goto apply_setting_err; + } + } else if (flash_data->opcode == CAM_PKT_NOP_OPCODE) { + CAM_DBG(CAM_FLASH, "NOP Packet"); + } else { + rc = -EINVAL; + CAM_ERR(CAM_FLASH, "Invalid opcode: %d req_id: %llu", + flash_data->opcode, req_id); + goto apply_setting_err; + } + } + +nrt_del_req: + cam_flash_pmic_delete_req(fctrl, req_id); +apply_setting_err: + return rc; +} + +int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) +{ + int rc = 0, i = 0; + uintptr_t generic_ptr; + uint32_t total_cmd_buf_in_bytes = 0; + uint32_t processed_cmd_buf_in_bytes = 0; + uint16_t cmd_length_in_bytes = 0; + uint32_t *cmd_buf = NULL; + uint32_t *offset = NULL; + uint32_t frm_offset = 0; + size_t len_of_buffer; + size_t remain_len; + struct cam_flash_init *flash_init = NULL; + struct common_header *cmn_hdr = NULL; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_config_dev_cmd config; + struct cam_req_mgr_add_request add_req; + struct i2c_data_settings *i2c_data = NULL; + struct i2c_settings_array *i2c_reg_settings = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + + if (!fctrl || !arg) { + CAM_ERR(CAM_FLASH, "fctrl/arg is NULL"); + return -EINVAL; + } + /* getting CSL Packet */ + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user((&config), (void __user *) ioctl_ctrl->handle, + sizeof(config))) { + CAM_ERR(CAM_FLASH, "Copy cmd handle from user failed"); + return -EFAULT; + } + + rc = cam_mem_get_cpu_buf(config.packet_handle, + &generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed in getting the packet : %d", rc); + return rc; + } + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_FLASH, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); + return -EINVAL; + } + + remain_len -= (size_t)config.offset; + /* Add offset to the flash csl header */ + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + return -EINVAL; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_DBG(CAM_FLASH, + "reject request %lld, last request to flush %lld", + csl_packet->header.request_id, fctrl->last_flush_req); + return -EINVAL; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_FLASH_PACKET_OPCODE_INIT: { + /* INIT packet*/ + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 1; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + processed_cmd_buf_in_bytes = 0; + if (!total_cmd_buf_in_bytes) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buffer); + if (rc < 0) { + CAM_ERR(CAM_FLASH, "Failed to get cpu buf"); + return rc; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_FLASH, "invalid cmd buf"); + return -EINVAL; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buffer - + sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "invalid cmd buf length"); + return -EINVAL; + } + remain_len = len_of_buffer - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + cmn_hdr = (struct common_header *)cmd_buf; + + /* Loop through cmd formats in one cmd buffer */ + CAM_DBG(CAM_FLASH, + "command Type: %d,Processed: %d,Total: %d", + cmn_hdr->cmd_type, processed_cmd_buf_in_bytes, + total_cmd_buf_in_bytes); + switch (cmn_hdr->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO: + if (len_of_buffer < + sizeof(struct cam_flash_init)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + + flash_init = (struct cam_flash_init *)cmd_buf; + fctrl->flash_type = flash_init->flash_type; + cmd_length_in_bytes = + sizeof(struct cam_flash_init); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + rc = cam_flash_slaveInfo_pkt_parser( + fctrl, cmd_buf, remain_len); + if (rc < 0) { + CAM_ERR(CAM_FLASH, + "Failed parsing slave info: rc: %d", + rc); + return rc; + } + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + CAM_DBG(CAM_FLASH, + "Received power settings"); + cmd_length_in_bytes = + total_cmd_buf_in_bytes; + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + &fctrl->power_info, remain_len); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed update power settings"); + return rc; + } + break; + default: + CAM_DBG(CAM_FLASH, + "Received initSettings"); + i2c_data = &(fctrl->i2c_data); + i2c_reg_settings = + &fctrl->i2c_data.init_settings; + + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + rc = cam_sensor_i2c_command_parser( + &fctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_FLASH, + "pkt parsing failed: %d", rc); + return rc; + } + cmd_length_in_bytes = + cmd_desc[i].length; + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + + break; + } + } + power_info = &fctrl->power_info; + if (!power_info) { + CAM_ERR(CAM_FLASH, "Power_info is NULL"); + return -EINVAL; + } + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params(&fctrl->soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_FLASH, + "failed to fill vreg params for power up rc:%d", + rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + &fctrl->soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_FLASH, + "failed to fill vreg params power down rc:%d", + rc); + return rc; + } + + rc = fctrl->func_tbl.power_ops(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + return rc; + } + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) { + CAM_ERR(CAM_FLASH, "cannot apply settings rc = %d", rc); + return rc; + } + + fctrl->flash_state = CAM_FLASH_STATE_CONFIG; + break; + } + case CAM_FLASH_PACKET_OPCODE_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + /* add support for handling i2c_data*/ + i2c_reg_settings = + &fctrl->i2c_data.per_frame[frm_offset]; + if (i2c_reg_settings->is_settings_valid == true) { + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = false; + goto update_req_mgr; + } + i2c_reg_settings->is_settings_valid = true; + i2c_reg_settings->request_id = + csl_packet->header.request_id; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &fctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed in parsing i2c packets"); + return rc; + } + break; + } + case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + + /* add support for handling i2c_data*/ + i2c_reg_settings = &fctrl->i2c_data.config_settings; + if (i2c_reg_settings->is_settings_valid == true) { + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = false; + + rc = delete_request(i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed in Deleting the err: %d", rc); + return rc; + } + } + i2c_reg_settings->is_settings_valid = true; + i2c_reg_settings->request_id = + csl_packet->header.request_id; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &fctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed in parsing i2c NRT packets"); + return rc; + } + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, + "Apply setting failed: %d", rc); + return rc; + } + case CAM_PKT_NOP_OPCODE: { + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { + CAM_WARN(CAM_FLASH, + "Rxed NOP packets without linking"); + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + fctrl->i2c_data.per_frame[frm_offset].is_settings_valid + = false; + return 0; + } + + CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u", + csl_packet->header.request_id); + goto update_req_mgr; + } + default: + CAM_ERR(CAM_FLASH, "Wrong Opcode : %d", + (csl_packet->header.op_code & 0xFFFFFF)); + return -EINVAL; + } +update_req_mgr: + if (((csl_packet->header.op_code & 0xFFFFF) == + CAM_PKT_NOP_OPCODE) || + ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS)) { + add_req.link_hdl = fctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = fctrl->bridge_intf.device_hdl; + + if ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS) + add_req.skip_before_applying = 1; + else + add_req.skip_before_applying = 0; + + if (fctrl->bridge_intf.crm_cb && + fctrl->bridge_intf.crm_cb->add_req) + fctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_FLASH, "add req to req_mgr= %lld", add_req.req_id); + } + return rc; +} + +int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) +{ + int rc = 0, i = 0; + uintptr_t generic_ptr, cmd_buf_ptr; + uint32_t *cmd_buf = NULL; + uint32_t *offset = NULL; + uint32_t frm_offset = 0; + size_t len_of_buffer; + size_t remain_len; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct common_header *cmn_hdr; + struct cam_config_dev_cmd config; + struct cam_req_mgr_add_request add_req = {0}; + struct cam_flash_init *cam_flash_info = NULL; + struct cam_flash_set_rer *flash_rer_info = NULL; + struct cam_flash_set_on_off *flash_operation_info = NULL; + struct cam_flash_query_curr *flash_query_info = NULL; + struct cam_flash_frame_setting *flash_data = NULL; + struct cam_flash_private_soc *soc_private = NULL; + + if (!fctrl || !arg) { + CAM_ERR(CAM_FLASH, "fctrl/arg is NULL"); + return -EINVAL; + } + + soc_private = (struct cam_flash_private_soc *) + fctrl->soc_info.soc_private; + + /* getting CSL Packet */ + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user((&config), + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) { + CAM_ERR(CAM_FLASH, "Copy cmd handle from user failed"); + rc = -EFAULT; + return rc; + } + + rc = cam_mem_get_cpu_buf(config.packet_handle, + &generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed in getting the packet: %d", rc); + return rc; + } + + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_FLASH, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); + rc = -EINVAL; + return rc; + } + + remain_len -= (size_t)config.offset; + /* Add offset to the flash csl header */ + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + rc = -EINVAL; + return rc; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_WARN(CAM_FLASH, + "reject request %lld, last request to flush %d", + csl_packet->header.request_id, fctrl->last_flush_req); + rc = -EINVAL; + return rc; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_FLASH_PACKET_OPCODE_INIT: { + /* INIT packet*/ + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + return rc; + } + if ((len_of_buffer < sizeof(struct cam_flash_init)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct cam_flash_init)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + cam_flash_info = (struct cam_flash_init *)cmd_buf; + + switch (cam_flash_info->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO: { + CAM_DBG(CAM_FLASH, "INIT_INFO CMD CALLED"); + fctrl->flash_init_setting.cmn_attr.request_id = 0; + fctrl->flash_init_setting.cmn_attr.is_settings_valid = + true; + fctrl->flash_type = cam_flash_info->flash_type; + fctrl->is_regulator_enabled = false; + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO; + + rc = fctrl->func_tbl.power_ops(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + return rc; + } + + fctrl->flash_state = + CAM_FLASH_STATE_CONFIG; + break; + } + case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE: { + CAM_DBG(CAM_FLASH, "INIT_FIRE Operation"); + + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + fctrl->nrt_info.cmn_attr.count = + flash_operation_info->count; + fctrl->nrt_info.cmn_attr.request_id = 0; + fctrl->nrt_info.opcode = + flash_operation_info->opcode; + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE; + for (i = 0; + i < flash_operation_info->count; i++) + fctrl->nrt_info.led_current_ma[i] = + flash_operation_info->led_current_ma[i]; + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, + "Apply setting failed: %d", + rc); + + fctrl->flash_state = CAM_FLASH_STATE_CONFIG; + break; + } + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", + cam_flash_info->cmd_type); + rc = -EINVAL; + return rc; + } + break; + } + case CAM_FLASH_PACKET_OPCODE_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + flash_data = &fctrl->per_frame[frm_offset]; + + if (flash_data->cmn_attr.is_settings_valid == true) { + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; + for (i = 0; i < flash_data->cmn_attr.count; i++) + flash_data->led_current_ma[i] = 0; + } + + flash_data->cmn_attr.request_id = csl_packet->header.request_id; + flash_data->cmn_attr.is_settings_valid = true; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: 0x%x", + cmd_desc->mem_handle); + return rc; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "not enough buffer"); + rc = -EINVAL; + return rc; + } + remain_len = len_of_buffer - cmd_desc->offset; + + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + if (!cmd_buf) { + rc = -EINVAL; + return rc; + } + cmn_hdr = (struct common_header *)cmd_buf; + + switch (cmn_hdr->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE: { + CAM_DBG(CAM_FLASH, + "CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE cmd called"); + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == + CAM_FLASH_STATE_ACQUIRE)) { + CAM_WARN(CAM_FLASH, + "Rxed Flash fire ops without linking"); + flash_data->cmn_attr.is_settings_valid = false; + return -EINVAL; + } + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + + flash_data->opcode = flash_operation_info->opcode; + flash_data->cmn_attr.count = + flash_operation_info->count; + for (i = 0; i < flash_operation_info->count; i++) + flash_data->led_current_ma[i] + = flash_operation_info->led_current_ma[i]; + + if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) + add_req.skip_before_applying |= SKIP_NEXT_FRAME; + } + break; + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", + cmn_hdr->cmd_type); + rc = -EINVAL; + return rc; + } + break; + } + case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + fctrl->nrt_info.cmn_attr.is_settings_valid = true; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + return rc; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + cmn_hdr = (struct common_header *)cmd_buf; + + switch (cmn_hdr->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET: { + CAM_DBG(CAM_FLASH, "Widget Flash Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + + fctrl->nrt_info.cmn_attr.count = + flash_operation_info->count; + fctrl->nrt_info.cmn_attr.request_id = 0; + fctrl->nrt_info.opcode = + flash_operation_info->opcode; + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET; + + for (i = 0; i < flash_operation_info->count; i++) + fctrl->nrt_info.led_current_ma[i] = + flash_operation_info->led_current_ma[i]; + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, "Apply setting failed: %d", + rc); + return rc; + } + case CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR: { + int query_curr_ma = 0; + + if (remain_len < sizeof(struct cam_flash_query_curr)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + flash_query_info = + (struct cam_flash_query_curr *)cmd_buf; + + if (soc_private->is_wled_flash) + rc = wled_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + else + rc = qpnp_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + + CAM_DBG(CAM_FLASH, "query_curr_ma = %d", + query_curr_ma); + if (rc) { + CAM_ERR(CAM_FLASH, + "Query current failed with rc=%d", rc); + return rc; + } + flash_query_info->query_current_ma = query_curr_ma; + break; + } + case CAMERA_SENSOR_FLASH_CMD_TYPE_RER: { + rc = 0; + if (remain_len < sizeof(struct cam_flash_set_rer)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + flash_rer_info = (struct cam_flash_set_rer *)cmd_buf; + if (!flash_rer_info) { + CAM_ERR(CAM_FLASH, + "flash_rer_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_rer_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_RER; + fctrl->nrt_info.opcode = flash_rer_info->opcode; + fctrl->nrt_info.cmn_attr.count = flash_rer_info->count; + fctrl->nrt_info.cmn_attr.request_id = 0; + fctrl->nrt_info.num_iterations = + flash_rer_info->num_iteration; + fctrl->nrt_info.led_on_delay_ms = + flash_rer_info->led_on_delay_ms; + fctrl->nrt_info.led_off_delay_ms = + flash_rer_info->led_off_delay_ms; + + for (i = 0; i < flash_rer_info->count; i++) + fctrl->nrt_info.led_current_ma[i] = + flash_rer_info->led_current_ma[i]; + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed: %d", + rc); + return rc; + } + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type : %d", + cmn_hdr->cmd_type); + rc = -EINVAL; + return rc; + } + + break; + } + case CAM_PKT_NOP_OPCODE: { + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { + CAM_WARN(CAM_FLASH, + "Rxed NOP packets without linking"); + fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid + = false; + return -EINVAL; + } + + fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; + fctrl->per_frame[frm_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frm_offset].opcode = CAM_PKT_NOP_OPCODE; + CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %llu", + csl_packet->header.request_id); + break; + } + default: + CAM_ERR(CAM_FLASH, "Wrong Opcode : %d", + (csl_packet->header.op_code & 0xFFFFFF)); + rc = -EINVAL; + return rc; + } + + if (((csl_packet->header.op_code & 0xFFFFF) == + CAM_PKT_NOP_OPCODE) || + ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS)) { + add_req.link_hdl = fctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = fctrl->bridge_intf.device_hdl; + + if ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS) + add_req.skip_before_applying |= 1; + else + add_req.skip_before_applying = 0; + + if (fctrl->bridge_intf.crm_cb && + fctrl->bridge_intf.crm_cb->add_req) + fctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_FLASH, "add req to req_mgr= %lld", add_req.req_id); + } + + return rc; +} + +int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info) +{ + info->dev_id = CAM_REQ_MGR_DEVICE_FLASH; + strlcpy(info->name, CAM_FLASH_NAME, sizeof(info->name)); + info->p_delay = CAM_FLASH_PIPELINE_DELAY; + info->trigger = CAM_TRIGGER_POINT_SOF; + return 0; +} + +int cam_flash_establish_link(struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_flash_ctrl *fctrl = NULL; + + if (!link) + return -EINVAL; + + fctrl = (struct cam_flash_ctrl *)cam_get_device_priv(link->dev_hdl); + if (!fctrl) { + CAM_ERR(CAM_FLASH, " Device data is NULL"); + return -EINVAL; + } + mutex_lock(&fctrl->flash_mutex); + if (link->link_enable) { + fctrl->bridge_intf.link_hdl = link->link_hdl; + fctrl->bridge_intf.crm_cb = link->crm_cb; + } else { + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.crm_cb = NULL; + } + mutex_unlock(&fctrl->flash_mutex); + + return 0; +} + +int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) +{ + int rc = 0; + + if (fctrl->bridge_intf.device_hdl != 1) { + rc = cam_destroy_device_hdl(fctrl->bridge_intf.device_hdl); + if (rc) + CAM_ERR(CAM_FLASH, + "Failed in destroying device handle rc = %d", + rc); + fctrl->bridge_intf.device_hdl = -1; + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.session_hdl = -1; + fctrl->last_flush_req = 0; + } + + return rc; +} + +void cam_flash_shutdown(struct cam_flash_ctrl *fctrl) +{ + int rc; + + if (fctrl->flash_state == CAM_FLASH_STATE_INIT) + return; + + if ((fctrl->flash_state == CAM_FLASH_STATE_CONFIG) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) { + fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + rc = fctrl->func_tbl.power_ops(fctrl, false); + if (rc) + CAM_ERR(CAM_FLASH, "Power Down Failed rc: %d", + rc); + } + + rc = cam_flash_release_dev(fctrl); + if (rc) + CAM_ERR(CAM_FLASH, "Release failed rc: %d", rc); + + fctrl->flash_state = CAM_FLASH_STATE_INIT; +} + +int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_flash_ctrl *fctrl = NULL; + + if (!apply) + return -EINVAL; + + fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(apply->dev_hdl); + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + rc = fctrl->func_tbl.apply_setting(fctrl, apply->request_id); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", + rc); + mutex_unlock(&fctrl->flash_mutex); + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.h b/drivers/cam_sensor_module/cam_flash/cam_flash_core.h new file mode 100644 index 000000000000..6cafe927cdbb --- /dev/null +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FLASH_CORE_H_ +#define _CAM_FLASH_CORE_H_ + +#include +#include "cam_flash_dev.h" + +int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info); +int cam_flash_establish_link(struct cam_req_mgr_core_dev_link_setup *link); +int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply); +int cam_flash_process_evt(struct cam_req_mgr_link_evt_data *event_data); +int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush); + + +#endif /*_CAM_FLASH_CORE_H_*/ diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c new file mode 100644 index 000000000000..d0610667e626 --- /dev/null +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -0,0 +1,652 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_flash_dev.h" +#include "cam_flash_soc.h" +#include "cam_flash_core.h" +#include "cam_common_util.h" + +static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, + void *arg, struct cam_flash_private_soc *soc_private) +{ + int rc = 0; + int i = 0; + struct cam_control *cmd = (struct cam_control *)arg; + + if (!fctrl || !arg) { + CAM_ERR(CAM_FLASH, "fctrl/arg is NULL with arg:%pK fctrl%pK", + fctrl, arg); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_FLASH, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + mutex_lock(&(fctrl->flash_mutex)); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev flash_acq_dev; + struct cam_create_dev_hdl bridge_params; + + CAM_DBG(CAM_FLASH, "CAM_ACQUIRE_DEV"); + + if (fctrl->flash_state != CAM_FLASH_STATE_INIT) { + CAM_ERR(CAM_FLASH, + "Cannot apply Acquire dev: Prev state: %d", + fctrl->flash_state); + rc = -EINVAL; + goto release_mutex; + } + + if (fctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_FLASH, "Device is already acquired"); + rc = -EINVAL; + goto release_mutex; + } + + rc = copy_from_user(&flash_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(flash_acq_dev)); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed Copying from User"); + goto release_mutex; + } + + bridge_params.session_hdl = flash_acq_dev.session_handle; + bridge_params.ops = &fctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = fctrl; + + flash_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + fctrl->bridge_intf.device_hdl = + flash_acq_dev.device_handle; + fctrl->bridge_intf.session_hdl = + flash_acq_dev.session_handle; + + rc = copy_to_user(u64_to_user_ptr(cmd->handle), + &flash_acq_dev, + sizeof(struct cam_sensor_acquire_dev)); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed Copy to User with rc = %d", + rc); + rc = -EFAULT; + goto release_mutex; + } + fctrl->flash_state = CAM_FLASH_STATE_ACQUIRE; + break; + } + case CAM_RELEASE_DEV: { + CAM_DBG(CAM_FLASH, "CAM_RELEASE_DEV"); + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) { + CAM_WARN(CAM_FLASH, + "Wrong state for Release dev: Prev state:%d", + fctrl->flash_state); + } + + if (fctrl->bridge_intf.device_hdl == -1 && + fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE) { + CAM_ERR(CAM_FLASH, + "Invalid Handle: Link Hdl: %d device hdl: %d", + fctrl->bridge_intf.device_hdl, + fctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + + if (fctrl->bridge_intf.link_hdl != -1) { + CAM_ERR(CAM_FLASH, + "Device [%d] still active on link 0x%x", + fctrl->flash_state, + fctrl->bridge_intf.link_hdl); + rc = -EAGAIN; + goto release_mutex; + } + + if ((fctrl->flash_state == CAM_FLASH_STATE_CONFIG) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) + fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + + if (cam_flash_release_dev(fctrl)) + CAM_WARN(CAM_FLASH, + "Failed in destroying the device Handle"); + + if (fctrl->func_tbl.power_ops(fctrl, false)) + CAM_WARN(CAM_FLASH, "Power Down Failed"); + + fctrl->flash_state = CAM_FLASH_STATE_INIT; + break; + } + case CAM_QUERY_CAP: { + struct cam_flash_query_cap_info flash_cap = {0}; + + CAM_DBG(CAM_FLASH, "CAM_QUERY_CAP"); + flash_cap.slot_info = fctrl->soc_info.index; + for (i = 0; i < fctrl->flash_num_sources; i++) { + flash_cap.max_current_flash[i] = + soc_private->flash_max_current[i]; + flash_cap.max_duration_flash[i] = + soc_private->flash_max_duration[i]; + } + + for (i = 0; i < fctrl->torch_num_sources; i++) + flash_cap.max_current_torch[i] = + soc_private->torch_max_current[i]; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &flash_cap, sizeof(struct cam_flash_query_cap_info))) { + CAM_ERR(CAM_FLASH, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + break; + } + case CAM_START_DEV: { + CAM_DBG(CAM_FLASH, "CAM_START_DEV"); + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) { + CAM_WARN(CAM_FLASH, + "Cannot apply Start Dev: Prev state: %d", + fctrl->flash_state); + rc = -EINVAL; + goto release_mutex; + } + + fctrl->flash_state = CAM_FLASH_STATE_START; + break; + } + case CAM_STOP_DEV: { + CAM_DBG(CAM_FLASH, "CAM_STOP_DEV ENTER"); + if (fctrl->flash_state != CAM_FLASH_STATE_START) { + CAM_WARN(CAM_FLASH, + "Cannot apply Stop dev: Prev state is: %d", + fctrl->flash_state); + rc = -EINVAL; + goto release_mutex; + } + + cam_flash_off(fctrl); + fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + fctrl->last_flush_req = 0; + fctrl->flash_state = CAM_FLASH_STATE_ACQUIRE; + break; + } + case CAM_CONFIG_DEV: { + CAM_DBG(CAM_FLASH, "CAM_CONFIG_DEV"); + rc = fctrl->func_tbl.parser(fctrl, arg); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed Flash Config: rc=%d\n", rc); + goto release_mutex; + } + break; + } + default: + CAM_ERR(CAM_FLASH, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + } + +release_mutex: + mutex_unlock(&(fctrl->flash_mutex)); + return rc; +} + +static int32_t cam_flash_init_default_params(struct cam_flash_ctrl *fctrl) +{ + /* Validate input parameters */ + if (!fctrl) { + CAM_ERR(CAM_FLASH, "failed: invalid params fctrl %pK", + fctrl); + return -EINVAL; + } + + CAM_DBG(CAM_FLASH, + "master_type: %d", fctrl->io_master_info.master_type); + /* Initialize cci_client */ + if (fctrl->io_master_info.master_type == CCI_MASTER) { + fctrl->io_master_info.cci_client = kzalloc(sizeof( + struct cam_sensor_cci_client), GFP_KERNEL); + if (!(fctrl->io_master_info.cci_client)) + return -ENOMEM; + } else if (fctrl->io_master_info.master_type == I2C_MASTER) { + if (!(fctrl->io_master_info.client)) + return -EINVAL; + } else { + CAM_ERR(CAM_FLASH, + "Invalid master / Master type Not supported"); + return -EINVAL; + } + + return 0; +} + +static const struct of_device_id cam_flash_dt_match[] = { + {.compatible = "qcom,camera-flash", .data = NULL}, + {} +}; + +static long cam_flash_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_flash_ctrl *fctrl = NULL; + struct cam_flash_private_soc *soc_private = NULL; + + CAM_DBG(CAM_FLASH, "Enter"); + + fctrl = v4l2_get_subdevdata(sd); + soc_private = fctrl->soc_info.soc_private; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: { + rc = cam_flash_driver_cmd(fctrl, arg, + soc_private); + break; + } + default: + CAM_ERR(CAM_FLASH, "Invalid ioctl cmd type"); + rc = -EINVAL; + break; + } + + CAM_DBG(CAM_FLASH, "Exit"); + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_flash_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_FLASH, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: { + rc = cam_flash_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) + CAM_ERR(CAM_FLASH, "cam_flash_ioctl failed"); + break; + } + default: + CAM_ERR(CAM_FLASH, "Invalid compat ioctl cmd_type:%d", + cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_FLASH, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static int cam_flash_platform_remove(struct platform_device *pdev) +{ + struct cam_flash_ctrl *fctrl; + + fctrl = platform_get_drvdata(pdev); + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash device is NULL"); + return 0; + } + + CAM_INFO(CAM_FLASH, "Platform remove invoked"); + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + cam_unregister_subdev(&(fctrl->v4l2_dev_str)); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&fctrl->v4l2_dev_str.sd, NULL); + kfree(fctrl); + + return 0; +} + +static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client) +{ + int32_t rc = 0; + struct cam_flash_ctrl *fctrl = i2c_get_clientdata(client); + /* Handle I2C Devices */ + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_FLASH, "i2c driver remove invoked"); + /*Free Allocated Mem */ + kfree(fctrl->i2c_data.per_frame); + fctrl->i2c_data.per_frame = NULL; + kfree(fctrl); + return rc; +} + +static int cam_flash_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_flash_ctrl *fctrl = + v4l2_get_subdevdata(sd); + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + + return 0; +} + +static struct v4l2_subdev_core_ops cam_flash_subdev_core_ops = { + .ioctl = cam_flash_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_flash_subdev_do_ioctl +#endif +}; + +static struct v4l2_subdev_ops cam_flash_subdev_ops = { + .core = &cam_flash_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_flash_internal_ops = { + .close = cam_flash_subdev_close, +}; + +static int cam_flash_init_subdev(struct cam_flash_ctrl *fctrl) +{ + int rc = 0; + + fctrl->v4l2_dev_str.internal_ops = + &cam_flash_internal_ops; + fctrl->v4l2_dev_str.ops = &cam_flash_subdev_ops; + fctrl->v4l2_dev_str.name = CAMX_FLASH_DEV_NAME; + fctrl->v4l2_dev_str.sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + fctrl->v4l2_dev_str.ent_function = CAM_FLASH_DEVICE_TYPE; + fctrl->v4l2_dev_str.token = fctrl; + + rc = cam_register_subdev(&(fctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_FLASH, "Fail to create subdev with %d", rc); + + return rc; +} + +static int32_t cam_flash_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0, i = 0; + struct cam_flash_ctrl *fctrl = NULL; + struct device_node *of_parent = NULL; + + CAM_DBG(CAM_FLASH, "Enter"); + if (!pdev->dev.of_node) { + CAM_ERR(CAM_FLASH, "of_node NULL"); + return -EINVAL; + } + + fctrl = kzalloc(sizeof(struct cam_flash_ctrl), GFP_KERNEL); + if (!fctrl) + return -ENOMEM; + + fctrl->pdev = pdev; + fctrl->soc_info.pdev = pdev; + fctrl->soc_info.dev = &pdev->dev; + fctrl->soc_info.dev_name = pdev->name; + + platform_set_drvdata(pdev, fctrl); + + rc = cam_flash_get_dt_data(fctrl, &fctrl->soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "cam_flash_get_dt_data failed with %d", rc); + kfree(fctrl); + return -EINVAL; + } + + if (of_find_property(pdev->dev.of_node, "cci-master", NULL)) { + /* Get CCI master */ + rc = of_property_read_u32(pdev->dev.of_node, "cci-master", + &fctrl->cci_i2c_master); + CAM_DBG(CAM_FLASH, "cci-master %d, rc %d", + fctrl->cci_i2c_master, rc); + if (rc < 0) { + /* Set default master 0 */ + fctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + fctrl->io_master_info.master_type = CCI_MASTER; + rc = cam_flash_init_default_params(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "failed: cam_flash_init_default_params rc %d", + rc); + return rc; + } + + of_parent = of_get_parent(pdev->dev.of_node); + if (of_property_read_u32(of_parent, "cell-index", + &fctrl->cci_num) < 0) + /* Set default master 0 */ + fctrl->cci_num = CCI_DEVICE_0; + + fctrl->io_master_info.cci_client->cci_device = fctrl->cci_num; + CAM_DBG(CAM_FLASH, "cci-index %d", fctrl->cci_num, rc); + + fctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (fctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_FLASH, "No Memory"); + rc = -ENOMEM; + goto free_cci_resource; + } + + INIT_LIST_HEAD(&(fctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(fctrl->i2c_data.config_settings.list_head)); + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD( + &(fctrl->i2c_data.per_frame[i].list_head)); + + fctrl->func_tbl.parser = cam_flash_i2c_pkt_parser; + fctrl->func_tbl.apply_setting = cam_flash_i2c_apply_setting; + fctrl->func_tbl.power_ops = cam_flash_i2c_power_ops; + fctrl->func_tbl.flush_req = cam_flash_i2c_flush_request; + } else { + /* PMIC Flash */ + fctrl->func_tbl.parser = cam_flash_pmic_pkt_parser; + fctrl->func_tbl.apply_setting = cam_flash_pmic_apply_setting; + fctrl->func_tbl.power_ops = cam_flash_pmic_power_ops; + fctrl->func_tbl.flush_req = cam_flash_pmic_flush_request; + } + + rc = cam_flash_init_subdev(fctrl); + if (rc) { + if (fctrl->io_master_info.cci_client != NULL) + goto free_cci_resource; + else + goto free_resource; + } + + fctrl->bridge_intf.device_hdl = -1; + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.ops.get_dev_info = cam_flash_publish_dev_info; + fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; + fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; + fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; + + mutex_init(&(fctrl->flash_mutex)); + + fctrl->flash_state = CAM_FLASH_STATE_INIT; + CAM_DBG(CAM_FLASH, "Probe success"); + return rc; + +free_cci_resource: + kfree(fctrl->io_master_info.cci_client); + fctrl->io_master_info.cci_client = NULL; +free_resource: + kfree(fctrl->i2c_data.per_frame); + kfree(fctrl->soc_info.soc_private); + cam_soc_util_release_platform_resource(&fctrl->soc_info); + fctrl->i2c_data.per_frame = NULL; + fctrl->soc_info.soc_private = NULL; + kfree(fctrl); + fctrl = NULL; + return rc; +} + +static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0, i = 0; + struct cam_flash_ctrl *fctrl; + + if (client == NULL || id == NULL) { + CAM_ERR(CAM_FLASH, "Invalid Args client: %pK id: %pK", + client, id); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_FLASH, "%s :: i2c_check_functionality failed", + client->name); + return -EFAULT; + } + + /* Create sensor control structure */ + fctrl = kzalloc(sizeof(*fctrl), GFP_KERNEL); + if (!fctrl) + return -ENOMEM; + + i2c_set_clientdata(client, fctrl); + + fctrl->io_master_info.client = client; + fctrl->soc_info.dev = &client->dev; + fctrl->soc_info.dev_name = client->name; + fctrl->io_master_info.master_type = I2C_MASTER; + + rc = cam_flash_get_dt_data(fctrl, &fctrl->soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "failed: cam_sensor_parse_dt rc %d", rc); + goto free_ctrl; + } + + rc = cam_flash_init_subdev(fctrl); + if (rc) + goto free_ctrl; + + fctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (fctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(fctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(fctrl->i2c_data.config_settings.list_head)); + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(fctrl->i2c_data.per_frame[i].list_head)); + + fctrl->func_tbl.parser = cam_flash_i2c_pkt_parser; + fctrl->func_tbl.apply_setting = cam_flash_i2c_apply_setting; + fctrl->func_tbl.power_ops = cam_flash_i2c_power_ops; + fctrl->func_tbl.flush_req = cam_flash_i2c_flush_request; + + fctrl->bridge_intf.device_hdl = -1; + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.ops.get_dev_info = cam_flash_publish_dev_info; + fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; + fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; + fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; + + mutex_init(&(fctrl->flash_mutex)); + fctrl->flash_state = CAM_FLASH_STATE_INIT; + + return rc; + +unreg_subdev: + cam_unregister_subdev(&(fctrl->v4l2_dev_str)); +free_ctrl: + kfree(fctrl); + fctrl = NULL; + return rc; +} + +MODULE_DEVICE_TABLE(of, cam_flash_dt_match); + +static struct platform_driver cam_flash_platform_driver = { + .probe = cam_flash_platform_probe, + .remove = cam_flash_platform_remove, + .driver = { + .name = "CAM-FLASH-DRIVER", + .owner = THIS_MODULE, + .of_match_table = cam_flash_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static const struct i2c_device_id i2c_id[] = { + {FLASH_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_flash_i2c_driver = { + .id_table = i2c_id, + .probe = cam_flash_i2c_driver_probe, + .remove = cam_flash_i2c_driver_remove, + .driver = { + .name = FLASH_DRIVER_I2C, + }, +}; + +static int32_t __init cam_flash_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_flash_platform_driver); + if (rc == 0) { + CAM_DBG(CAM_FLASH, "platform probe success"); + return 0; + } + + rc = i2c_add_driver(&cam_flash_i2c_driver); + if (rc) + CAM_ERR(CAM_FLASH, "i2c_add_driver failed rc: %d", rc); + return rc; +} + +static void __exit cam_flash_exit_module(void) +{ + platform_driver_unregister(&cam_flash_platform_driver); + i2c_del_driver(&cam_flash_i2c_driver); +} + +module_init(cam_flash_init_module); +module_exit(cam_flash_exit_module); +MODULE_DESCRIPTION("CAM FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h new file mode 100644 index 000000000000..c4f17656ace0 --- /dev/null +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -0,0 +1,225 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FLASH_DEV_H_ +#define _CAM_FLASH_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_interface.h" +#include "cam_subdev.h" +#include "cam_mem_mgr.h" +#include "cam_sensor_cmn_header.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_sensor_io.h" +#include "cam_flash_core.h" + +#define CAMX_FLASH_DEV_NAME "cam-flash-dev" + +#define CAM_FLASH_PIPELINE_DELAY 1 + +#define FLASH_DRIVER_I2C "i2c_flash" + +#define CAM_FLASH_PACKET_OPCODE_INIT 0 +#define CAM_FLASH_PACKET_OPCODE_SET_OPS 1 +#define CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS 2 + +struct cam_flash_ctrl; + +enum cam_flash_switch_trigger_ops { + LED_SWITCH_OFF = 0, + LED_SWITCH_ON, +}; + +enum cam_flash_state { + CAM_FLASH_STATE_INIT, + CAM_FLASH_STATE_ACQUIRE, + CAM_FLASH_STATE_CONFIG, + CAM_FLASH_STATE_START, +}; + +enum cam_flash_flush_type { + FLUSH_ALL = 0, + FLUSH_REQ, + FLUSH_MAX, +}; + +/** + * struct cam_flash_intf_params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @link_hdl : Link Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_flash_intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_flash_common_attr + * @is_settings_valid : Notify the valid settings + * @request_id : Request id provided by umd + * @count : Number of led count + * @cmd_type : Command buffer type + */ +struct cam_flash_common_attr { + bool is_settings_valid; + uint64_t request_id; + uint16_t count; + uint8_t cmd_type; +}; + +/** + * struct flash_init_packet + * @cmn_attr : Provides common attributes + * @flash_type : Flash type(PMIC/I2C/GPIO) + */ +struct cam_flash_init_packet { + struct cam_flash_common_attr cmn_attr; + uint8_t flash_type; +}; + +/** + * struct flash_frame_setting + * @cmn_attr : Provides common attributes + * @num_iterations : Iterations used to perform RER + * @led_on_delay_ms : LED on time in milisec + * @led_off_delay_ms : LED off time in milisec + * @opcode : Command buffer opcode + * @led_current_ma[] : LED current array in miliamps + * + */ +struct cam_flash_frame_setting { + struct cam_flash_common_attr cmn_attr; + uint16_t num_iterations; + uint16_t led_on_delay_ms; + uint16_t led_off_delay_ms; + int8_t opcode; + uint32_t led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS]; +}; + +/** + * struct cam_flash_private_soc + * @switch_trigger_name : Switch trigger name + * @flash_trigger_name : Flash trigger name array + * @flash_op_current : Flash operational current + * @flash_max_current : Max supported current for LED in flash mode + * @flash_max_duration : Max turn on duration for LED in Flash mode + * @torch_trigger_name : Torch trigger name array + * @torch_op_current : Torch operational current + * @torch_max_current : Max supported current for LED in torch mode + * @is_wled_flash : Detection between WLED/LED flash + */ + +struct cam_flash_private_soc { + const char *switch_trigger_name; + const char *flash_trigger_name[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t flash_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t flash_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t flash_max_duration[CAM_FLASH_MAX_LED_TRIGGERS]; + const char *torch_trigger_name[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t torch_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; + bool is_wled_flash; +}; + +struct cam_flash_func_tbl { + int (*parser)(struct cam_flash_ctrl *fctrl, void *arg); + int (*apply_setting)(struct cam_flash_ctrl *fctrl, uint64_t req_id); + int (*power_ops)(struct cam_flash_ctrl *fctrl, bool regulator_enable); + int (*flush_req)(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id); +}; + +/** + * struct cam_flash_ctrl + * @soc_info : Soc related information + * @pdev : Platform device + * @per_frame[] : Per_frame setting array + * @nrt_info : NonRealTime settings + * @of_node : Of Node ptr + * @v4l2_dev_str : V4L2 device structure + * @bridge_intf : CRM interface + * @flash_init_setting : Init command buffer structure + * @switch_trigger : Switch trigger ptr + * @flash_num_sources : Number of flash sources + * @torch_num_source : Number of torch sources + * @flash_mutex : Mutex for flash operations + * @flash_state : Current flash state (LOW/OFF/ON/INIT) + * @flash_type : Flash types (PMIC/I2C/GPIO) + * @is_regulator_enable : Regulator disable/enable notifier + * @func_tbl : Function table for different HW + * (e.g. i2c/pmic/gpio) + * @flash_trigger : Flash trigger ptr + * @torch_trigger : Torch trigger ptr + * @cci_i2c_master : I2C structure + * @cci_device_num : cci parent cell index + * @io_master_info : Information about the communication master + * @i2c_data : I2C register settings + * @last_flush_req : last request to flush + */ +struct cam_flash_ctrl { + struct cam_hw_soc_info soc_info; + struct platform_device *pdev; + struct cam_sensor_power_ctrl_t power_info; + struct cam_flash_frame_setting per_frame[MAX_PER_FRAME_ARRAY]; + struct cam_flash_frame_setting nrt_info; + struct device_node *of_node; + struct cam_subdev v4l2_dev_str; + struct cam_flash_intf_params bridge_intf; + struct cam_flash_init_packet flash_init_setting; + struct led_trigger *switch_trigger; + uint32_t flash_num_sources; + uint32_t torch_num_sources; + struct mutex flash_mutex; + enum cam_flash_state flash_state; + uint8_t flash_type; + bool is_regulator_enabled; + struct cam_flash_func_tbl func_tbl; + struct led_trigger *flash_trigger[CAM_FLASH_MAX_LED_TRIGGERS]; + struct led_trigger *torch_trigger[CAM_FLASH_MAX_LED_TRIGGERS]; +/* I2C related setting */ + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct camera_io_master io_master_info; + struct i2c_data_settings i2c_data; + uint32_t last_flush_req; +}; + +int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); +int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); +int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl, uint64_t req_id); +int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, uint64_t req_id); +int cam_flash_off(struct cam_flash_ctrl *fctrl); +int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable); +int cam_flash_i2c_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable); +int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id); +int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type, uint64_t req_id); +void cam_flash_shutdown(struct cam_flash_ctrl *fctrl); +int cam_flash_release_dev(struct cam_flash_ctrl *fctrl); + +#endif /*_CAM_FLASH_DEV_H_*/ diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c new file mode 100644 index 000000000000..762977f4b968 --- /dev/null +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_flash_soc.h" +#include "cam_res_mgr_api.h" + +static int32_t cam_get_source_node_info( + struct device_node *of_node, + struct cam_flash_ctrl *fctrl, + struct cam_flash_private_soc *soc_private) +{ + int32_t rc = 0; + uint32_t count = 0, i = 0; + struct device_node *flash_src_node = NULL; + struct device_node *torch_src_node = NULL; + struct device_node *switch_src_node = NULL; + + soc_private->is_wled_flash = + of_property_read_bool(of_node, "wled-flash-support"); + + switch_src_node = of_parse_phandle(of_node, "switch-source", 0); + if (!switch_src_node) { + CAM_WARN(CAM_FLASH, "switch_src_node NULL"); + } else { + rc = of_property_read_string(switch_src_node, + "qcom,default-led-trigger", + &soc_private->switch_trigger_name); + if (rc) { + CAM_ERR(CAM_FLASH, + "default-led-trigger read failed rc=%d", rc); + } else { + CAM_DBG(CAM_FLASH, "switch trigger %s", + soc_private->switch_trigger_name); + cam_res_mgr_led_trigger_register( + soc_private->switch_trigger_name, + &fctrl->switch_trigger); + } + + of_node_put(switch_src_node); + } + + if (of_get_property(of_node, "flash-source", &count)) { + count /= sizeof(uint32_t); + + if (count > CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "Invalid LED count: %d", count); + return -EINVAL; + } + + fctrl->flash_num_sources = count; + + for (i = 0; i < count; i++) { + flash_src_node = of_parse_phandle(of_node, + "flash-source", i); + if (!flash_src_node) { + CAM_WARN(CAM_FLASH, "flash_src_node NULL"); + continue; + } + + rc = of_property_read_string(flash_src_node, + "qcom,default-led-trigger", + &soc_private->flash_trigger_name[i]); + if (rc) { + CAM_WARN(CAM_FLASH, + "defalut-led-trigger read failed rc=%d", rc); + of_node_put(flash_src_node); + continue; + } + + CAM_DBG(CAM_FLASH, "Flash default trigger %s", + soc_private->flash_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->flash_trigger_name[i], + &fctrl->flash_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->flash_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->flash_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED FLASH max_current read fail: %d", + rc); + of_node_put(flash_src_node); + rc = 0; + continue; + } + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,max-current", + &soc_private->flash_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED FLASH max-current read fail: %d", + rc); + of_node_put(flash_src_node); + continue; + } + } + + /* Read operational-current */ + rc = of_property_read_u32(flash_src_node, + "qcom,current-ma", + &soc_private->flash_op_current[i]); + if (rc) { + CAM_INFO(CAM_FLASH, "op-current: read failed"); + rc = 0; + } + + /* Read max-duration */ + rc = of_property_read_u32(flash_src_node, + "qcom,duration-ms", + &soc_private->flash_max_duration[i]); + if (rc) { + CAM_INFO(CAM_FLASH, + "max-duration prop unavailable: %d", + rc); + rc = 0; + } + of_node_put(flash_src_node); + + CAM_DBG(CAM_FLASH, "MainFlashMaxCurrent[%d]: %d", + i, soc_private->flash_max_current[i]); + } + } + + if (of_get_property(of_node, "torch-source", &count)) { + count /= sizeof(uint32_t); + if (count > CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "Invalid LED count : %d", count); + return -EINVAL; + } + + fctrl->torch_num_sources = count; + + CAM_DBG(CAM_FLASH, "torch_num_sources = %d", + fctrl->torch_num_sources); + for (i = 0; i < count; i++) { + torch_src_node = of_parse_phandle(of_node, + "torch-source", i); + if (!torch_src_node) { + CAM_WARN(CAM_FLASH, "torch_src_node NULL"); + continue; + } + + rc = of_property_read_string(torch_src_node, + "qcom,default-led-trigger", + &soc_private->torch_trigger_name[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "default-trigger read failed"); + of_node_put(torch_src_node); + continue; + } + + CAM_DBG(CAM_FLASH, "Torch default trigger %s", + soc_private->torch_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->torch_trigger_name[i], + &fctrl->torch_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->torch_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->torch_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED TORCH max_current read fail: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } else { + rc = of_property_read_u32(torch_src_node, + "qcom,max-current", + &soc_private->torch_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED-TORCH max-current read failed: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } + + /* Read operational-current */ + rc = of_property_read_u32(torch_src_node, + "qcom,current-ma", + &soc_private->torch_op_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "op-current prop unavailable: %d", rc); + rc = 0; + } + + of_node_put(torch_src_node); + + CAM_DBG(CAM_FLASH, "TorchMaxCurrent[%d]: %d", + i, soc_private->torch_max_current[i]); + } + } + + return rc; +} + +int cam_flash_get_dt_data(struct cam_flash_ctrl *fctrl, + struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0; + struct device_node *of_node = NULL; + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "NULL flash control structure"); + return -EINVAL; + } + + soc_info->soc_private = + kzalloc(sizeof(struct cam_flash_private_soc), GFP_KERNEL); + if (!soc_info->soc_private) { + rc = -ENOMEM; + goto release_soc_res; + } + of_node = fctrl->pdev->dev.of_node; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "Get_dt_properties failed rc %d", rc); + goto free_soc_private; + } + + rc = cam_get_source_node_info(of_node, fctrl, soc_info->soc_private); + if (rc) { + CAM_ERR(CAM_FLASH, + "cam_flash_get_pmic_source_info failed rc %d", rc); + goto free_soc_private; + } + return rc; + +free_soc_private: + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; +release_soc_res: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.h b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.h new file mode 100644 index 000000000000..cfe7c3464f64 --- /dev/null +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FLASH_SOC_H_ +#define _CAM_FLASH_SOC_H_ + +#include "cam_flash_dev.h" + +int cam_flash_get_dt_data(struct cam_flash_ctrl *fctrl, + struct cam_hw_soc_info *soc_info); + +#endif /*_CAM_FLASH_SOC_H_*/ diff --git a/drivers/cam_sensor_module/cam_ois/Makefile b/drivers/cam_sensor_module/cam_ois/Makefile new file mode 100644 index 000000000000..e987a2257e9e --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois_dev.o cam_ois_core.o cam_ois_soc.o diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c new file mode 100644 index 000000000000..b6035252a234 --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -0,0 +1,843 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "cam_ois_core.h" +#include "cam_ois_soc.h" +#include "cam_sensor_util.h" +#include "cam_debug_util.h" +#include "cam_res_mgr_api.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +int32_t cam_ois_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0; + + power_info->power_setting_size = 1; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_setting[0].seq_type = SENSOR_VAF; + power_info->power_setting[0].seq_val = CAM_VAF; + power_info->power_setting[0].config_val = 1; + power_info->power_setting[0].delay = 2; + + power_info->power_down_setting_size = 1; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + + power_info->power_down_setting[0].seq_type = SENSOR_VAF; + power_info->power_down_setting[0].seq_val = CAM_VAF; + power_info->power_down_setting[0].config_val = 0; + + return rc; + +free_power_settings: + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return rc; +} + + +/** + * cam_ois_get_dev_handle - get device handle + * @o_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, + void *arg) +{ + struct cam_sensor_acquire_dev ois_acq_dev; + struct cam_create_dev_hdl bridge_params; + struct cam_control *cmd = (struct cam_control *)arg; + + if (o_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_OIS, "Device is already acquired"); + return -EFAULT; + } + if (copy_from_user(&ois_acq_dev, u64_to_user_ptr(cmd->handle), + sizeof(ois_acq_dev))) + return -EFAULT; + + bridge_params.session_hdl = ois_acq_dev.session_handle; + bridge_params.ops = &o_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = o_ctrl; + + ois_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle; + o_ctrl->bridge_intf.session_hdl = ois_acq_dev.session_handle; + + CAM_DBG(CAM_OIS, "Device Handle: %d", ois_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), &ois_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_OIS, "ACQUIRE_DEV: copy to user failed"); + return -EFAULT; + } + return 0; +} + +static int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = + &o_ctrl->soc_info; + struct cam_ois_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + if ((power_info->power_setting == NULL) && + (power_info->power_down_setting == NULL)) { + CAM_INFO(CAM_OIS, + "Using default power settings"); + rc = cam_ois_construct_default_power_setting(power_info); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Construct default ois power setting failed."); + return rc; + } + } + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params( + soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_OIS, + "failed to fill vreg params for power up rc:%d", rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_OIS, + "failed to fill vreg params for power down rc:%d", rc); + return rc; + } + + power_info->dev = soc_info->dev; + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_OIS, "failed in ois power up rc %d", rc); + return rc; + } + + rc = camera_io_init(&o_ctrl->io_master_info); + if (rc) + CAM_ERR(CAM_OIS, "cci_init failed: rc: %d", rc); + + return rc; +} + +/** + * cam_ois_power_down - power down OIS device + * @o_ctrl: ctrl structure + * + * Returns success or failure + */ +static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl) +{ + int32_t rc = 0; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info = + &o_ctrl->soc_info; + struct cam_ois_soc_private *soc_private; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "failed: o_ctrl %pK", o_ctrl); + return -EINVAL; + } + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + soc_info = &o_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_OIS, "failed: power_info %pK", power_info); + return -EINVAL; + } + + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_OIS, "power down the core is failed:%d", rc); + return rc; + } + + camera_io_release(&o_ctrl->io_master_info); + + return rc; +} + +static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, + struct i2c_settings_array *i2c_set) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0; + uint32_t i, size; + + if (o_ctrl == NULL || i2c_set == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + if (i2c_set->is_settings_valid != 1) { + CAM_ERR(CAM_OIS, " Invalid settings"); + return -EINVAL; + } + + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { + rc = camera_io_dev_write(&(o_ctrl->io_master_info), + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in Applying i2c wrt settings"); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + &(o_ctrl->io_master_info), + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "i2c poll apply setting Fail"); + return rc; + } + } + } + } + + return rc; +} + +static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, + uint32_t *cmd_buf, size_t len) +{ + int32_t rc = 0; + struct cam_cmd_ois_info *ois_info; + + if (!o_ctrl || !cmd_buf || len < sizeof(struct cam_cmd_ois_info)) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + ois_info = (struct cam_cmd_ois_info *)cmd_buf; + if (o_ctrl->io_master_info.master_type == CCI_MASTER) { + o_ctrl->io_master_info.cci_client->i2c_freq_mode = + ois_info->i2c_freq_mode; + o_ctrl->io_master_info.cci_client->sid = + ois_info->slave_addr >> 1; + o_ctrl->ois_fw_flag = ois_info->ois_fw_flag; + o_ctrl->is_ois_calib = ois_info->is_ois_calib; + memcpy(o_ctrl->ois_name, ois_info->ois_name, OIS_NAME_LEN); + o_ctrl->ois_name[OIS_NAME_LEN - 1] = '\0'; + o_ctrl->io_master_info.cci_client->retries = 3; + o_ctrl->io_master_info.cci_client->id_map = 0; + memcpy(&(o_ctrl->opcode), &(ois_info->opcode), + sizeof(struct cam_ois_opcode)); + CAM_DBG(CAM_OIS, "Slave addr: 0x%x Freq Mode: %d", + ois_info->slave_addr, ois_info->i2c_freq_mode); + } else if (o_ctrl->io_master_info.master_type == I2C_MASTER) { + o_ctrl->io_master_info.client->addr = ois_info->slave_addr; + CAM_DBG(CAM_OIS, "Slave addr: 0x%x", ois_info->slave_addr); + } else { + CAM_ERR(CAM_OIS, "Invalid Master type : %d", + o_ctrl->io_master_info.master_type); + rc = -EINVAL; + } + + return rc; +} + +static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + uint8_t *ptr = NULL; + int32_t rc = 0, cnt; + uint32_t fw_size; + const struct firmware *fw = NULL; + const char *fw_name_prog = NULL; + const char *fw_name_coeff = NULL; + char name_prog[32] = {0}; + char name_coeff[32] = {0}; + struct device *dev = &(o_ctrl->pdev->dev); + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + snprintf(name_coeff, 32, "%s.coeff", o_ctrl->ois_name); + + snprintf(name_prog, 32, "%s.prog", o_ctrl->ois_name); + + /* cast pointer as const pointer*/ + fw_name_prog = name_prog; + fw_name_coeff = name_coeff; + + /* Load FW */ + rc = request_firmware(&fw, fw_name_prog, dev); + if (rc) { + CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_prog); + return rc; + } + + total_bytes = fw->size; + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * + total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)), + fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + release_firmware(fw); + return -ENOMEM; + } + + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( + page_address(page)); + + for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes; + cnt++, ptr++) { + i2c_reg_setting.reg_setting[cnt].reg_addr = + o_ctrl->opcode.prog; + i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; + i2c_reg_setting.reg_setting[cnt].delay = 0; + i2c_reg_setting.reg_setting[cnt].data_mask = 0; + } + + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); + goto release_firmware; + } + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), + page, fw_size); + page = NULL; + fw_size = 0; + release_firmware(fw); + + rc = request_firmware(&fw, fw_name_coeff, dev); + if (rc) { + CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_coeff); + return rc; + } + + total_bytes = fw->size; + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * + total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)), + fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + release_firmware(fw); + return -ENOMEM; + } + + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( + page_address(page)); + + for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes; + cnt++, ptr++) { + i2c_reg_setting.reg_setting[cnt].reg_addr = + o_ctrl->opcode.coeff; + i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; + i2c_reg_setting.reg_setting[cnt].delay = 0; + i2c_reg_setting.reg_setting[cnt].data_mask = 0; + } + + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 1); + if (rc < 0) + CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); + +release_firmware: + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), + page, fw_size); + release_firmware(fw); + + return rc; +} + +/** + * cam_ois_pkt_parse - Parse csl packet + * @o_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) +{ + int32_t rc = 0; + int32_t i = 0; + uint32_t total_cmd_buf_in_bytes = 0; + struct common_header *cmm_hdr = NULL; + uintptr_t generic_ptr; + struct cam_control *ioctl_ctrl = NULL; + struct cam_config_dev_cmd dev_config; + struct i2c_settings_array *i2c_reg_settings = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t generic_pkt_addr; + size_t pkt_len; + size_t remain_len = 0; + struct cam_packet *csl_packet = NULL; + size_t len_of_buff = 0; + uint32_t *offset = NULL, *cmd_buf; + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + ioctl_ctrl = (struct cam_control *)arg; + if (copy_from_user(&dev_config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(dev_config))) + return -EFAULT; + rc = cam_mem_get_cpu_buf(dev_config.packet_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_OIS, + "error in converting command Handle Error: %d", rc); + return rc; + } + + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_OIS, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + return -EINVAL; + } + + remain_len -= (size_t)dev_config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_OIS, "Invalid packet params"); + return -EINVAL; + } + + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_OIS_PACKET_OPCODE_INIT: + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + if (!total_cmd_buf_in_bytes) + continue; + + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to get cpu buf : 0x%x", + cmd_desc[i].mem_handle); + return rc; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_OIS, "invalid cmd buf"); + return -EINVAL; + } + + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_OIS, + "Invalid length for sensor cmd"); + return -EINVAL; + } + remain_len = len_of_buff - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + cmm_hdr = (struct common_header *)cmd_buf; + + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + rc = cam_ois_slaveInfo_pkt_parser( + o_ctrl, cmd_buf, remain_len); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in parsing slave info"); + return rc; + } + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + CAM_DBG(CAM_OIS, + "Received power settings buffer"); + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + power_info, remain_len); + if (rc) { + CAM_ERR(CAM_OIS, + "Failed: parse power settings"); + return rc; + } + break; + default: + if (o_ctrl->i2c_init_data.is_settings_valid == 0) { + CAM_DBG(CAM_OIS, + "Received init settings"); + i2c_reg_settings = + &(o_ctrl->i2c_init_data); + i2c_reg_settings->is_settings_valid = 1; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser( + &o_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "init parsing failed: %d", rc); + return rc; + } + } else if ((o_ctrl->is_ois_calib != 0) && + (o_ctrl->i2c_calib_data.is_settings_valid == + 0)) { + CAM_DBG(CAM_OIS, + "Received calib settings"); + i2c_reg_settings = &(o_ctrl->i2c_calib_data); + i2c_reg_settings->is_settings_valid = 1; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser( + &o_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Calib parsing failed: %d", rc); + return rc; + } + } + break; + } + } + + if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) { + rc = cam_ois_power_up(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, " OIS Power up failed"); + return rc; + } + o_ctrl->cam_ois_state = CAM_OIS_CONFIG; + } + + if (o_ctrl->ois_fw_flag) { + rc = cam_ois_fw_download(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, "Failed OIS FW Download"); + goto pwr_dwn; + } + } + + rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Cannot apply Init settings"); + goto pwr_dwn; + } + + if (o_ctrl->is_ois_calib) { + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_calib_data); + if (rc) { + CAM_ERR(CAM_OIS, "Cannot apply calib data"); + goto pwr_dwn; + } + } + + rc = delete_request(&o_ctrl->i2c_init_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting Init data: rc: %d", rc); + rc = 0; + } + rc = delete_request(&o_ctrl->i2c_calib_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting Calibration data: rc: %d", rc); + rc = 0; + } + break; + case CAM_OIS_PACKET_OPCODE_OIS_CONTROL: + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to control OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + i2c_reg_settings = &(o_ctrl->i2c_mode_data); + i2c_reg_settings->is_settings_valid = 1; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); + return rc; + } + + rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Cannot apply mode settings"); + return rc; + } + + rc = delete_request(i2c_reg_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Fail deleting Mode data: rc: %d", rc); + return rc; + } + break; + default: + CAM_ERR(CAM_OIS, "Invalid Opcode: %d", + (csl_packet->header.op_code & 0xFFFFFF)); + return -EINVAL; + } + + if (!rc) + return rc; +pwr_dwn: + cam_ois_power_down(o_ctrl); + return rc; +} + +void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + if (o_ctrl->cam_ois_state == CAM_OIS_INIT) + return; + + if (o_ctrl->cam_ois_state >= CAM_OIS_CONFIG) { + rc = cam_ois_power_down(o_ctrl); + if (rc < 0) + CAM_ERR(CAM_OIS, "OIS Power down failed"); + o_ctrl->cam_ois_state = CAM_OIS_ACQUIRE; + } + + if (o_ctrl->cam_ois_state >= CAM_OIS_ACQUIRE) { + rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_OIS, "destroying the device hdl"); + o_ctrl->bridge_intf.device_hdl = -1; + o_ctrl->bridge_intf.link_hdl = -1; + o_ctrl->bridge_intf.session_hdl = -1; + } + + if (o_ctrl->i2c_mode_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_mode_data); + + if (o_ctrl->i2c_calib_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_calib_data); + + if (o_ctrl->i2c_init_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_init_data); + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + + o_ctrl->cam_ois_state = CAM_OIS_INIT; +} + +/** + * cam_ois_driver_cmd - Handle ois cmds + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) +{ + int rc = 0; + struct cam_ois_query_cap_t ois_cap = {0}; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_ois_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + + if (!o_ctrl || !cmd) { + CAM_ERR(CAM_OIS, "Invalid arguments"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_OIS, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + mutex_lock(&(o_ctrl->ois_mutex)); + switch (cmd->op_code) { + case CAM_QUERY_CAP: + ois_cap.slot_info = o_ctrl->soc_info.index; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &ois_cap, + sizeof(struct cam_ois_query_cap_t))) { + CAM_ERR(CAM_OIS, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + CAM_DBG(CAM_OIS, "ois_cap: ID: %d", ois_cap.slot_info); + break; + case CAM_ACQUIRE_DEV: + rc = cam_ois_get_dev_handle(o_ctrl, arg); + if (rc) { + CAM_ERR(CAM_OIS, "Failed to acquire dev"); + goto release_mutex; + } + + o_ctrl->cam_ois_state = CAM_OIS_ACQUIRE; + break; + case CAM_START_DEV: + if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state for start : %d", + o_ctrl->cam_ois_state); + goto release_mutex; + } + o_ctrl->cam_ois_state = CAM_OIS_START; + break; + case CAM_CONFIG_DEV: + rc = cam_ois_pkt_parse(o_ctrl, arg); + if (rc) { + CAM_ERR(CAM_OIS, "Failed in ois pkt Parsing"); + goto release_mutex; + } + break; + case CAM_RELEASE_DEV: + if (o_ctrl->cam_ois_state == CAM_OIS_START) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Cant release ois: in start state"); + goto release_mutex; + } + + if (o_ctrl->cam_ois_state == CAM_OIS_CONFIG) { + rc = cam_ois_power_down(o_ctrl); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS Power down failed"); + goto release_mutex; + } + } + + if (o_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_OIS, "link hdl: %d device hdl: %d", + o_ctrl->bridge_intf.device_hdl, + o_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_OIS, "destroying the device hdl"); + o_ctrl->bridge_intf.device_hdl = -1; + o_ctrl->bridge_intf.link_hdl = -1; + o_ctrl->bridge_intf.session_hdl = -1; + o_ctrl->cam_ois_state = CAM_OIS_INIT; + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + + if (o_ctrl->i2c_mode_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_mode_data); + + if (o_ctrl->i2c_calib_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_calib_data); + + if (o_ctrl->i2c_init_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_init_data); + + break; + case CAM_STOP_DEV: + if (o_ctrl->cam_ois_state != CAM_OIS_START) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state for stop : %d", + o_ctrl->cam_ois_state); + } + o_ctrl->cam_ois_state = CAM_OIS_CONFIG; + break; + default: + CAM_ERR(CAM_OIS, "invalid opcode"); + goto release_mutex; + } +release_mutex: + mutex_unlock(&(o_ctrl->ois_mutex)); + return rc; +} diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h new file mode 100644 index 000000000000..33abe8b75c72 --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_OIS_CORE_H_ +#define _CAM_OIS_CORE_H_ + +#include +#include "cam_ois_dev.h" + +#define OIS_NAME_LEN 32 + +/** + * @power_info: power setting info to control the power + * + * This API construct the default ois power setting. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int32_t cam_ois_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info); + + +int cam_ois_driver_cmd(struct cam_ois_ctrl_t *e_ctrl, void *arg); + +/** + * @o_ctrl: OIS ctrl structure + * + * This API handles the shutdown ioctl/close + */ +void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl); + +#endif +/* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c new file mode 100644 index 000000000000..10044cec6efd --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_ois_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_ois_soc.h" +#include "cam_ois_core.h" +#include "cam_debug_util.h" + +static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ois_driver_cmd(o_ctrl, arg); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + +static int cam_ois_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_ois_ctrl_t *o_ctrl = + v4l2_get_subdevdata(sd); + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "o_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + + return 0; +} + +static int32_t cam_ois_update_i2c_info(struct cam_ois_ctrl_t *o_ctrl, + struct cam_ois_i2c_info_t *i2c_info) +{ + struct cam_sensor_cci_client *cci_client = NULL; + + if (o_ctrl->io_master_info.master_type == CCI_MASTER) { + cci_client = o_ctrl->io_master_info.cci_client; + if (!cci_client) { + CAM_ERR(CAM_OIS, "failed: cci_client %pK", + cci_client); + return -EINVAL; + } + cci_client->cci_i2c_master = o_ctrl->cci_i2c_master; + cci_client->sid = (i2c_info->slave_addr) >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_ois_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_OIS, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ois_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) { + CAM_ERR(CAM_OIS, + "Failed in ois suddev handling rc %d", + rc); + return rc; + } + break; + default: + CAM_ERR(CAM_OIS, "Invalid compat ioctl: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_OIS, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + return rc; +} +#endif + +static const struct v4l2_subdev_internal_ops cam_ois_internal_ops = { + .close = cam_ois_subdev_close, +}; + +static struct v4l2_subdev_core_ops cam_ois_subdev_core_ops = { + .ioctl = cam_ois_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_ois_init_subdev_do_ioctl, +#endif +}; + +static struct v4l2_subdev_ops cam_ois_subdev_ops = { + .core = &cam_ois_subdev_core_ops, +}; + +static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; + + o_ctrl->v4l2_dev_str.internal_ops = &cam_ois_internal_ops; + o_ctrl->v4l2_dev_str.ops = &cam_ois_subdev_ops; + strlcpy(o_ctrl->device_name, CAM_OIS_NAME, + sizeof(o_ctrl->device_name)); + o_ctrl->v4l2_dev_str.name = o_ctrl->device_name; + o_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + o_ctrl->v4l2_dev_str.ent_function = CAM_OIS_DEVICE_TYPE; + o_ctrl->v4l2_dev_str.token = o_ctrl; + + rc = cam_register_subdev(&(o_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_OIS, "fail to create subdev"); + + return rc; +} + +static int cam_ois_i2c_driver_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct cam_ois_ctrl_t *o_ctrl = NULL; + struct cam_ois_soc_private *soc_private = NULL; + + if (client == NULL || id == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args client: %pK id: %pK", + client, id); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_OIS, "i2c_check_functionality failed"); + goto probe_failure; + } + + o_ctrl = kzalloc(sizeof(*o_ctrl), GFP_KERNEL); + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "kzalloc failed"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, o_ctrl); + + o_ctrl->soc_info.dev = &client->dev; + o_ctrl->soc_info.dev_name = client->name; + o_ctrl->ois_device_type = MSM_CAMERA_I2C_DEVICE; + o_ctrl->io_master_info.master_type = I2C_MASTER; + o_ctrl->io_master_info.client = client; + + soc_private = kzalloc(sizeof(struct cam_ois_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto octrl_free; + } + + o_ctrl->soc_info.soc_private = soc_private; + rc = cam_ois_driver_soc_init(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, "failed: cam_sensor_parse_dt rc %d", rc); + goto soc_free; + } + + rc = cam_ois_init_subdev_param(o_ctrl); + if (rc) + goto soc_free; + + o_ctrl->cam_ois_state = CAM_OIS_INIT; + + return rc; + +soc_free: + kfree(soc_private); +octrl_free: + kfree(o_ctrl); +probe_failure: + return rc; +} + +static int cam_ois_i2c_driver_remove(struct i2c_client *client) +{ + int i; + struct cam_ois_ctrl_t *o_ctrl = i2c_get_clientdata(client); + struct cam_hw_soc_info *soc_info; + struct cam_ois_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "ois device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_OIS, "i2c driver remove invoked"); + soc_info = &o_ctrl->soc_info; + + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + + soc_private = + (struct cam_ois_soc_private *)soc_info->soc_private; + power_info = &soc_private->power_info; + + kfree(o_ctrl->soc_info.soc_private); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); + kfree(o_ctrl); + + return 0; +} + +static int32_t cam_ois_platform_driver_probe( + struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_ois_ctrl_t *o_ctrl = NULL; + struct cam_ois_soc_private *soc_private = NULL; + + o_ctrl = kzalloc(sizeof(struct cam_ois_ctrl_t), GFP_KERNEL); + if (!o_ctrl) + return -ENOMEM; + + o_ctrl->soc_info.pdev = pdev; + o_ctrl->pdev = pdev; + o_ctrl->soc_info.dev = &pdev->dev; + o_ctrl->soc_info.dev_name = pdev->name; + + o_ctrl->ois_device_type = MSM_CAMERA_PLATFORM_DEVICE; + + o_ctrl->io_master_info.master_type = CCI_MASTER; + o_ctrl->io_master_info.cci_client = kzalloc( + sizeof(struct cam_sensor_cci_client), GFP_KERNEL); + if (!o_ctrl->io_master_info.cci_client) + goto free_o_ctrl; + + soc_private = kzalloc(sizeof(struct cam_ois_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_cci_client; + } + o_ctrl->soc_info.soc_private = soc_private; + soc_private->power_info.dev = &pdev->dev; + + INIT_LIST_HEAD(&(o_ctrl->i2c_init_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_calib_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_mode_data.list_head)); + mutex_init(&(o_ctrl->ois_mutex)); + rc = cam_ois_driver_soc_init(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc); + goto free_soc; + } + + rc = cam_ois_init_subdev_param(o_ctrl); + if (rc) + goto free_soc; + + rc = cam_ois_update_i2c_info(o_ctrl, &soc_private->i2c_info); + if (rc) { + CAM_ERR(CAM_OIS, "failed: to update i2c info rc %d", rc); + goto unreg_subdev; + } + o_ctrl->bridge_intf.device_hdl = -1; + + platform_set_drvdata(pdev, o_ctrl); + o_ctrl->cam_ois_state = CAM_OIS_INIT; + + return rc; +unreg_subdev: + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); +free_soc: + kfree(soc_private); +free_cci_client: + kfree(o_ctrl->io_master_info.cci_client); +free_o_ctrl: + kfree(o_ctrl); + return rc; +} + +static int cam_ois_platform_driver_remove(struct platform_device *pdev) +{ + int i; + struct cam_ois_ctrl_t *o_ctrl; + struct cam_ois_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info; + + o_ctrl = platform_get_drvdata(pdev); + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "ois device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_OIS, "platform driver remove invoked"); + soc_info = &o_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + kfree(o_ctrl->soc_info.soc_private); + kfree(o_ctrl->io_master_info.cci_client); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); + kfree(o_ctrl); + + return 0; +} + +static const struct of_device_id cam_ois_dt_match[] = { + { .compatible = "qcom,ois" }, + { } +}; + + +MODULE_DEVICE_TABLE(of, cam_ois_dt_match); + +static struct platform_driver cam_ois_platform_driver = { + .driver = { + .name = "qcom,ois", + .owner = THIS_MODULE, + .of_match_table = cam_ois_dt_match, + }, + .probe = cam_ois_platform_driver_probe, + .remove = cam_ois_platform_driver_remove, +}; +static const struct i2c_device_id cam_ois_i2c_id[] = { + { "msm_ois", (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_ois_i2c_driver = { + .id_table = cam_ois_i2c_id, + .probe = cam_ois_i2c_driver_probe, + .remove = cam_ois_i2c_driver_remove, + .driver = { + .name = "msm_ois", + }, +}; + +static struct cam_ois_registered_driver_t registered_driver = { + 0, 0}; + +static int __init cam_ois_driver_init(void) +{ + int rc = 0; + + rc = platform_driver_register(&cam_ois_platform_driver); + if (rc) { + CAM_ERR(CAM_OIS, "platform_driver_register failed rc = %d", + rc); + return rc; + } + + registered_driver.platform_driver = 1; + + rc = i2c_add_driver(&cam_ois_i2c_driver); + if (rc) { + CAM_ERR(CAM_OIS, "i2c_add_driver failed rc = %d", rc); + return rc; + } + + registered_driver.i2c_driver = 1; + return rc; +} + +static void __exit cam_ois_driver_exit(void) +{ + if (registered_driver.platform_driver) + platform_driver_unregister(&cam_ois_platform_driver); + + if (registered_driver.i2c_driver) + i2c_del_driver(&cam_ois_i2c_driver); +} + +module_init(cam_ois_driver_init); +module_exit(cam_ois_driver_exit); +MODULE_DESCRIPTION("CAM OIS driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h new file mode 100644 index 000000000000..0c2a450fe058 --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_OIS_DEV_H_ +#define _CAM_OIS_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_soc_util.h" + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +enum cam_ois_state { + CAM_OIS_INIT, + CAM_OIS_ACQUIRE, + CAM_OIS_CONFIG, + CAM_OIS_START, +}; + +/** + * struct cam_ois_registered_driver_t - registered driver info + * @platform_driver : flag indicates if platform driver is registered + * @i2c_driver : flag indicates if i2c driver is registered + * + */ +struct cam_ois_registered_driver_t { + bool platform_driver; + bool i2c_driver; +}; + +/** + * struct cam_ois_i2c_info_t - I2C info + * @slave_addr : slave address + * @i2c_freq_mode : i2c frequency mode + * + */ +struct cam_ois_i2c_info_t { + uint16_t slave_addr; + uint8_t i2c_freq_mode; +}; + +/** + * struct cam_ois_soc_private - ois soc private data structure + * @ois_name : ois name + * @i2c_info : i2c info structure + * @power_info : ois power info + * + */ +struct cam_ois_soc_private { + const char *ois_name; + struct cam_ois_i2c_info_t i2c_info; + struct cam_sensor_power_ctrl_t power_info; +}; + +/** + * struct cam_ois_intf_params - bridge interface params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_ois_intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_ois_ctrl_t - OIS ctrl private data + * @pdev : platform device + * @ois_mutex : ois mutex + * @soc_info : ois soc related info + * @io_master_info : Information about the communication master + * @cci_i2c_master : I2C structure + * @v4l2_dev_str : V4L2 device structure + * @bridge_intf : bridge interface params + * @i2c_init_data : ois i2c init settings + * @i2c_mode_data : ois i2c mode settings + * @i2c_calib_data : ois i2c calib settings + * @ois_device_type : ois device type + * @cam_ois_state : ois_device_state + * @ois_name : ois name + * @ois_fw_flag : flag for firmware download + * @is_ois_calib : flag for Calibration data + * @opcode : ois opcode + * @device_name : Device name + * + */ +struct cam_ois_ctrl_t { + struct platform_device *pdev; + struct mutex ois_mutex; + struct cam_hw_soc_info soc_info; + struct camera_io_master io_master_info; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct cam_subdev v4l2_dev_str; + struct cam_ois_intf_params bridge_intf; + struct i2c_settings_array i2c_init_data; + struct i2c_settings_array i2c_calib_data; + struct i2c_settings_array i2c_mode_data; + enum msm_camera_device_type_t ois_device_type; + enum cam_ois_state cam_ois_state; + char device_name[20]; + char ois_name[32]; + uint8_t ois_fw_flag; + uint8_t is_ois_calib; + struct cam_ois_opcode opcode; +}; + +#endif /*_CAM_OIS_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c new file mode 100644 index 000000000000..9c14d87e233d --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_ois_soc.h" +#include "cam_debug_util.h" + +/** + * @e_ctrl: ctrl structure + * + * Parses ois dt + */ +static int cam_ois_get_dt_data(struct cam_ois_ctrl_t *o_ctrl) +{ + int i, rc = 0; + struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info; + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + struct device_node *of_node = NULL; + + of_node = soc_info->dev->of_node; + + if (!of_node) { + CAM_ERR(CAM_OIS, "of_node is NULL, device type %d", + o_ctrl->ois_device_type); + return -EINVAL; + } + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_OIS, "cam_soc_util_get_dt_properties rc %d", + rc); + return rc; + } + + if (!soc_info->gpio_data) { + CAM_INFO(CAM_OIS, "No GPIO found"); + return 0; + } + + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_INFO(CAM_OIS, "No GPIO found"); + return -EINVAL; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &power_info->gpio_num_info); + if ((rc < 0) || (!power_info->gpio_num_info)) { + CAM_ERR(CAM_OIS, "No/Error OIS GPIOs"); + return -EINVAL; + } + + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = devm_clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_SENSOR, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + return rc; + } + } + + return rc; +} +/** + * @o_ctrl: ctrl structure + * + * This function is called from cam_ois_platform/i2c_driver_probe, it parses + * the ois dt node. + */ +int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info; + struct device_node *of_node = NULL; + struct device_node *of_parent = NULL; + + if (!soc_info->dev) { + CAM_ERR(CAM_OIS, "soc_info is not initialized"); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + if (!of_node) { + CAM_ERR(CAM_OIS, "dev.of_node NULL"); + return -EINVAL; + } + + if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = of_property_read_u32(of_node, "cci-master", + &o_ctrl->cci_i2c_master); + if (rc < 0) { + CAM_DBG(CAM_OIS, "failed rc %d", rc); + return rc; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &o_ctrl->cci_num) < 0) + /* Set default master 0 */ + o_ctrl->cci_num = CCI_DEVICE_0; + + o_ctrl->io_master_info.cci_client->cci_device = o_ctrl->cci_num; + CAM_DBG(CAM_OIS, "cci-device %d", o_ctrl->cci_num, rc); + + } + + rc = cam_ois_get_dt_data(o_ctrl); + if (rc < 0) + CAM_DBG(CAM_OIS, "failed: ois get dt data rc %d", rc); + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.h b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.h new file mode 100644 index 000000000000..fd2c209c7504 --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_OIS_SOC_H_ +#define _CAM_OIS_SOC_H_ + +#include "cam_ois_dev.h" + +int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl); + +#endif/* _CAM_OIS_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_res_mgr/Makefile b/drivers/cam_sensor_module/cam_res_mgr/Makefile new file mode 100644 index 000000000000..5bc9889b40e9 --- /dev/null +++ b/drivers/cam_sensor_module/cam_res_mgr/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +#ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_res_mgr.o diff --git a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c new file mode 100644 index 000000000000..c87540f7950f --- /dev/null +++ b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -0,0 +1,739 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_debug_util.h" +#include "cam_res_mgr_api.h" +#include "cam_res_mgr_private.h" + +static struct cam_res_mgr *cam_res; + +static void cam_res_mgr_free_res(void) +{ + struct cam_dev_res *dev_res, *dev_temp; + struct cam_gpio_res *gpio_res, *gpio_temp; + struct cam_flash_res *flash_res, *flash_temp; + + if (!cam_res) + return; + + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry_safe(gpio_res, gpio_temp, + &cam_res->gpio_res_list, list) { + list_for_each_entry_safe(dev_res, dev_temp, + &gpio_res->dev_list, list) { + list_del_init(&dev_res->list); + kfree(dev_res); + } + list_del_init(&gpio_res->list); + kfree(gpio_res); + } + mutex_unlock(&cam_res->gpio_res_lock); + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry_safe(flash_res, flash_temp, + &cam_res->flash_res_list, list) { + list_del_init(&flash_res->list); + kfree(flash_res); + } + mutex_unlock(&cam_res->flash_res_lock); + + mutex_lock(&cam_res->clk_res_lock); + cam_res->shared_clk_ref_count = 0; + mutex_unlock(&cam_res->clk_res_lock); +} + +void cam_res_mgr_led_trigger_register(const char *name, struct led_trigger **tp) +{ + bool found = false; + struct cam_flash_res *flash_res; + + if (!cam_res) { + /* + * If this driver not probed, then just register the + * led trigger. + */ + led_trigger_register_simple(name, tp); + return; + } + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry(flash_res, &cam_res->flash_res_list, list) { + if (!strcmp(flash_res->name, name)) { + found = true; + break; + } + } + mutex_unlock(&cam_res->flash_res_lock); + + if (found) { + *tp = flash_res->trigger; + } else { + flash_res = kzalloc(sizeof(struct cam_flash_res), GFP_KERNEL); + if (!flash_res) { + CAM_ERR(CAM_RES, + "Failed to malloc memory for flash_res:%s", + name); + *tp = NULL; + return; + } + + led_trigger_register_simple(name, tp); + INIT_LIST_HEAD(&flash_res->list); + flash_res->trigger = *tp; + flash_res->name = name; + + mutex_lock(&cam_res->flash_res_lock); + list_add_tail(&flash_res->list, &cam_res->flash_res_list); + mutex_unlock(&cam_res->flash_res_lock); + } +} +EXPORT_SYMBOL(cam_res_mgr_led_trigger_register); + +void cam_res_mgr_led_trigger_unregister(struct led_trigger *tp) +{ + bool found = false; + struct cam_flash_res *flash_res; + + if (!cam_res) { + /* + * If this driver not probed, then just unregister the + * led trigger. + */ + led_trigger_unregister_simple(tp); + return; + } + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry(flash_res, &cam_res->flash_res_list, list) { + if (flash_res->trigger == tp) { + found = true; + break; + } + } + + if (found) { + led_trigger_unregister_simple(tp); + list_del_init(&flash_res->list); + kfree(flash_res); + } + mutex_unlock(&cam_res->flash_res_lock); +} +EXPORT_SYMBOL(cam_res_mgr_led_trigger_unregister); + +void cam_res_mgr_led_trigger_event(struct led_trigger *trig, + enum led_brightness brightness) +{ + bool found = false; + struct cam_flash_res *flash_res; + + if (!cam_res) { + /* + * If this driver not probed, then just trigger + * the led event. + */ + led_trigger_event(trig, brightness); + return; + } + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry(flash_res, &cam_res->flash_res_list, list) { + if (flash_res->trigger == trig) { + found = true; + break; + } + } + mutex_unlock(&cam_res->flash_res_lock); + + if (found) + led_trigger_event(trig, brightness); +} +EXPORT_SYMBOL(cam_res_mgr_led_trigger_event); + +int cam_res_mgr_shared_pinctrl_init(void) +{ + struct cam_soc_pinctrl_info *pinctrl_info; + + /* + * We allow the cam_res is NULL or shared_gpio_enabled + * is false, it means this driver no probed or doesn't + * have shared gpio in this device. + */ + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return 0; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus != PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl already been got."); + mutex_unlock(&cam_res->gpio_res_lock); + return 0; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + pinctrl_info->pinctrl = + devm_pinctrl_get(cam_res->dev); + if (IS_ERR_OR_NULL(pinctrl_info->pinctrl)) { + CAM_ERR(CAM_RES, "Pinctrl not available"); + cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); + return -EINVAL; + } + + pinctrl_info->gpio_state_active = + pinctrl_lookup_state(pinctrl_info->pinctrl, + CAM_RES_MGR_DEFAULT); + if (IS_ERR_OR_NULL(pinctrl_info->gpio_state_active)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); + return -EINVAL; + } + + pinctrl_info->gpio_state_suspend = + pinctrl_lookup_state(pinctrl_info->pinctrl, + CAM_RES_MGR_SLEEP); + if (IS_ERR_OR_NULL(pinctrl_info->gpio_state_suspend)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); + return -EINVAL; + } + + cam_res->pstatus = PINCTRL_STATUS_GOT; + mutex_unlock(&cam_res->gpio_res_lock); + + return 0; +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_init); + +static bool cam_res_mgr_shared_pinctrl_check_hold(void) +{ + int index = 0; + int dev_num = 0; + bool hold = false; + struct list_head *list; + struct cam_gpio_res *gpio_res; + struct cam_res_mgr_dt *dt = &cam_res->dt; + + for (; index < dt->num_shared_gpio; index++) { + list_for_each_entry(gpio_res, + &cam_res->gpio_res_list, list) { + + if (gpio_res->gpio == + dt->shared_gpio[index]) { + list_for_each(list, &gpio_res->dev_list) + dev_num++; + + if (dev_num >= 2) { + hold = true; + break; + } + } + } + } + + if (cam_res->shared_clk_ref_count > 1) + hold = true; + + return hold; +} + +void cam_res_mgr_shared_pinctrl_put(void) +{ + struct cam_soc_pinctrl_info *pinctrl_info; + + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus == PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl already been put"); + mutex_unlock(&cam_res->gpio_res_lock); + return; + } + + if (cam_res_mgr_shared_pinctrl_check_hold()) { + CAM_INFO(CAM_RES, "Need hold put this pinctrl"); + mutex_unlock(&cam_res->gpio_res_lock); + return; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + devm_pinctrl_put(pinctrl_info->pinctrl); + + cam_res->pstatus = PINCTRL_STATUS_PUT; + mutex_unlock(&cam_res->gpio_res_lock); +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_put); + +int cam_res_mgr_shared_pinctrl_select_state(bool active) +{ + int rc = 0; + struct cam_soc_pinctrl_info *pinctrl_info; + + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return 0; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus == PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl alerady been put.!"); + mutex_unlock(&cam_res->gpio_res_lock); + return 0; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + if (active && (cam_res->pstatus != PINCTRL_STATUS_ACTIVE)) { + rc = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->gpio_state_active); + cam_res->pstatus = PINCTRL_STATUS_ACTIVE; + } else if (!active && + !cam_res_mgr_shared_pinctrl_check_hold()) { + rc = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->gpio_state_suspend); + cam_res->pstatus = PINCTRL_STATUS_SUSPEND; + } + + mutex_unlock(&cam_res->gpio_res_lock); + + return rc; +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_select_state); + +int cam_res_mgr_shared_pinctrl_post_init(void) +{ + int ret = 0; + struct cam_soc_pinctrl_info *pinctrl_info; + + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return ret; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus == PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl alerady been put.!"); + mutex_unlock(&cam_res->gpio_res_lock); + return ret; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + /* + * If no gpio resource in gpio_res_list, and + * no shared clk now, it means this device + * don't have shared gpio. + */ + if (list_empty(&cam_res->gpio_res_list) && + cam_res->shared_clk_ref_count < 1) { + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->gpio_state_suspend); + devm_pinctrl_put(pinctrl_info->pinctrl); + cam_res->pstatus = PINCTRL_STATUS_PUT; + } + mutex_unlock(&cam_res->gpio_res_lock); + + return ret; +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_post_init); + +static int cam_res_mgr_add_device(struct device *dev, + struct cam_gpio_res *gpio_res) +{ + struct cam_dev_res *dev_res = NULL; + + dev_res = kzalloc(sizeof(struct cam_dev_res), GFP_KERNEL); + if (!dev_res) + return -ENOMEM; + + dev_res->dev = dev; + INIT_LIST_HEAD(&dev_res->list); + + list_add_tail(&dev_res->list, &gpio_res->dev_list); + + return 0; +} + +static bool cam_res_mgr_gpio_is_shared(uint gpio) +{ + int index = 0; + bool found = false; + struct cam_res_mgr_dt *dt = &cam_res->dt; + + mutex_lock(&cam_res->gpio_res_lock); + for (; index < dt->num_shared_gpio; index++) { + if (gpio == dt->shared_gpio[index]) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + + return found; +} + +int cam_res_mgr_gpio_request(struct device *dev, uint gpio, + unsigned long flags, const char *label) +{ + int rc = 0; + bool found = false; + struct cam_gpio_res *gpio_res = NULL; + + if (cam_res && cam_res->shared_gpio_enabled) { + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(gpio_res, &cam_res->gpio_res_list, list) { + if (gpio == gpio_res->gpio) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + /* + * found equal to false has two situation: + * 1. shared gpio not enabled + * 2. shared gpio enabled, but not find this gpio + * from the gpio_res_list + * These two situation both need request gpio. + */ + if (!found) { + rc = gpio_request_one(gpio, flags, label); + if (rc) { + CAM_ERR(CAM_RES, "gpio %d:%s request fails", + gpio, label); + return rc; + } + } + + /* + * If the gpio is in the shared list, and not find + * from gpio_res_list, then insert a cam_gpio_res + * to gpio_res_list. + */ + if (!found && cam_res + && cam_res->shared_gpio_enabled && + cam_res_mgr_gpio_is_shared(gpio)) { + + gpio_res = kzalloc(sizeof(struct cam_gpio_res), GFP_KERNEL); + if (!gpio_res) + return -ENOMEM; + + gpio_res->gpio = gpio; + gpio_res->power_on_count = 0; + INIT_LIST_HEAD(&gpio_res->list); + INIT_LIST_HEAD(&gpio_res->dev_list); + + mutex_lock(&cam_res->gpio_res_lock); + rc = cam_res_mgr_add_device(dev, gpio_res); + if (rc) { + kfree(gpio_res); + mutex_unlock(&cam_res->gpio_res_lock); + return rc; + } + + list_add_tail(&gpio_res->list, &cam_res->gpio_res_list); + mutex_unlock(&cam_res->gpio_res_lock); + } + + if (found && cam_res + && cam_res->shared_gpio_enabled) { + struct cam_dev_res *dev_res = NULL; + + found = 0; + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(dev_res, &gpio_res->dev_list, list) { + if (dev_res->dev == dev) { + found = 1; + break; + } + } + + if (!found) + rc = cam_res_mgr_add_device(dev, gpio_res); + + mutex_unlock(&cam_res->gpio_res_lock); + } + + return rc; +} +EXPORT_SYMBOL(cam_res_mgr_gpio_request); + +static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) +{ + bool found = false; + bool need_free = true; + int dev_num = 0; + struct cam_gpio_res *gpio_res = NULL; + + if (cam_res && cam_res->shared_gpio_enabled) { + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(gpio_res, &cam_res->gpio_res_list, list) { + if (gpio == gpio_res->gpio) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + if (found && cam_res + && cam_res->shared_gpio_enabled) { + struct list_head *list; + struct cam_dev_res *dev_res = NULL; + + mutex_lock(&cam_res->gpio_res_lock); + /* Count the dev number in the dev_list */ + list_for_each(list, &gpio_res->dev_list) + dev_num++; + + /* + * Need free the gpio if only has last 1 device + * in the dev_list, otherwise, not free this + * gpio. + */ + if (dev_num == 1) { + dev_res = list_first_entry(&gpio_res->dev_list, + struct cam_dev_res, list); + list_del_init(&dev_res->list); + kfree(dev_res); + + list_del_init(&gpio_res->list); + kfree(gpio_res); + } else { + list_for_each_entry(dev_res, + &gpio_res->dev_list, list) { + if (dev_res->dev == dev) { + list_del_init(&dev_res->list); + kfree(dev_res); + need_free = false; + break; + } + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + if (need_free) + gpio_free(gpio); +} + +void cam_res_mgr_gpio_free_arry(struct device *dev, + const struct gpio *array, size_t num) +{ + while (num--) + cam_res_mgr_gpio_free(dev, (array[num]).gpio); +} +EXPORT_SYMBOL(cam_res_mgr_gpio_free_arry); + +int cam_res_mgr_gpio_set_value(unsigned int gpio, int value) +{ + int rc = 0; + bool found = false; + struct cam_gpio_res *gpio_res = NULL; + + if (cam_res && cam_res->shared_gpio_enabled) { + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(gpio_res, &cam_res->gpio_res_list, list) { + if (gpio == gpio_res->gpio) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + /* + * Set the value directly if can't find the gpio from + * gpio_res_list, otherwise, need add ref count support + **/ + if (!found) { + gpio_set_value_cansleep(gpio, value); + } else { + if (value) { + gpio_res->power_on_count++; + if (gpio_res->power_on_count < 2) { + gpio_set_value_cansleep(gpio, value); + CAM_DBG(CAM_RES, + "Shared GPIO(%d) : HIGH", gpio); + } + } else { + gpio_res->power_on_count--; + if (gpio_res->power_on_count < 1) { + gpio_set_value_cansleep(gpio, value); + CAM_DBG(CAM_RES, + "Shared GPIO(%d) : LOW", gpio); + } + } + } + + return rc; +} +EXPORT_SYMBOL(cam_res_mgr_gpio_set_value); + +void cam_res_mgr_shared_clk_config(bool value) +{ + if (!cam_res) + return; + + mutex_lock(&cam_res->clk_res_lock); + if (value) + cam_res->shared_clk_ref_count++; + else + cam_res->shared_clk_ref_count--; + mutex_unlock(&cam_res->clk_res_lock); +} +EXPORT_SYMBOL(cam_res_mgr_shared_clk_config); + +static int cam_res_mgr_parse_dt(struct device *dev) +{ + int rc = 0; + struct device_node *of_node = NULL; + struct cam_res_mgr_dt *dt = &cam_res->dt; + + of_node = dev->of_node; + + dt->num_shared_gpio = of_property_count_u32_elems(of_node, + "shared-gpios"); + + if (dt->num_shared_gpio > MAX_SHARED_GPIO_SIZE || + dt->num_shared_gpio <= 0) { + /* + * Not really an error, it means dtsi not configure + * the shared gpio. + */ + CAM_DBG(CAM_RES, "Invalid GPIO number %d. No shared gpio.", + dt->num_shared_gpio); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, "shared-gpios", + dt->shared_gpio, dt->num_shared_gpio); + if (rc) { + CAM_ERR(CAM_RES, "Get shared gpio array failed."); + return -EINVAL; + } + + dt->pinctrl_info.pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(dt->pinctrl_info.pinctrl)) { + CAM_ERR(CAM_RES, "Pinctrl not available"); + return -EINVAL; + } + + /* + * Check the pinctrl state to make sure the gpio + * shared enabled. + */ + dt->pinctrl_info.gpio_state_active = + pinctrl_lookup_state(dt->pinctrl_info.pinctrl, + CAM_RES_MGR_DEFAULT); + if (IS_ERR_OR_NULL(dt->pinctrl_info.gpio_state_active)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + return -EINVAL; + } + + dt->pinctrl_info.gpio_state_suspend = + pinctrl_lookup_state(dt->pinctrl_info.pinctrl, + CAM_RES_MGR_SLEEP); + if (IS_ERR_OR_NULL(dt->pinctrl_info.gpio_state_suspend)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + return -EINVAL; + } + + devm_pinctrl_put(dt->pinctrl_info.pinctrl); + + return rc; +} + +static int cam_res_mgr_probe(struct platform_device *pdev) +{ + int rc = 0; + + cam_res = kzalloc(sizeof(*cam_res), GFP_KERNEL); + if (!cam_res) + return -ENOMEM; + + cam_res->dev = &pdev->dev; + mutex_init(&cam_res->flash_res_lock); + mutex_init(&cam_res->gpio_res_lock); + mutex_init(&cam_res->clk_res_lock); + + rc = cam_res_mgr_parse_dt(&pdev->dev); + if (rc) { + CAM_INFO(CAM_RES, "Disable shared gpio support."); + cam_res->shared_gpio_enabled = false; + } else { + CAM_INFO(CAM_RES, "Enable shared gpio support."); + cam_res->shared_gpio_enabled = true; + } + + cam_res->shared_clk_ref_count = 0; + cam_res->pstatus = PINCTRL_STATUS_PUT; + + INIT_LIST_HEAD(&cam_res->gpio_res_list); + INIT_LIST_HEAD(&cam_res->flash_res_list); + + return 0; +} + +static int cam_res_mgr_remove(struct platform_device *pdev) +{ + if (cam_res) { + cam_res_mgr_free_res(); + kfree(cam_res); + cam_res = NULL; + } + + return 0; +} + +static const struct of_device_id cam_res_mgr_dt_match[] = { + {.compatible = "qcom,cam-res-mgr"}, + {} +}; +MODULE_DEVICE_TABLE(of, cam_res_mgr_dt_match); + +static struct platform_driver cam_res_mgr_driver = { + .probe = cam_res_mgr_probe, + .remove = cam_res_mgr_remove, + .driver = { + .name = "cam_res_mgr", + .owner = THIS_MODULE, + .of_match_table = cam_res_mgr_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_res_mgr_init(void) +{ + return platform_driver_register(&cam_res_mgr_driver); +} + +static void __exit cam_res_mgr_exit(void) +{ + platform_driver_unregister(&cam_res_mgr_driver); +} + +module_init(cam_res_mgr_init); +module_exit(cam_res_mgr_exit); +MODULE_DESCRIPTION("Camera resource manager driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h new file mode 100644 index 000000000000..e259ba7f2c78 --- /dev/null +++ b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_RES_MGR_API_H__ +#define __CAM_RES_MGR_API_H__ + +#include + +/** + * @brief: Register the led trigger + * + * The newly registered led trigger is assigned to flash_res_list. + * + * @name : Pointer to int led trigger name + * @tp : Save the returned led trigger + * + * @return None + */ +void cam_res_mgr_led_trigger_register(const char *name, + struct led_trigger **tp); + +/** + * @brief: Unregister the led trigger + * + * Free the flash_res if this led trigger isn't used by other device . + * + * @tp : Pointer to the led trigger + * + * @return None + */ +void cam_res_mgr_led_trigger_unregister(struct led_trigger *tp); + +/** + * @brief: Trigger the event to led core + * + * @trig : Pointer to the led trigger + * @brightness : The brightness need to fire + * + * @return None + */ +void cam_res_mgr_led_trigger_event(struct led_trigger *trig, + enum led_brightness brightness); + +/** + * @brief: Get the corresponding pinctrl of dev + * + * Init the shared pinctrl if shared pinctrl enabled. + * + * @return None + */ +int cam_res_mgr_shared_pinctrl_init(void); + +/** + * @brief: Put the pinctrl + * + * Put the shared pinctrl. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +void cam_res_mgr_shared_pinctrl_put(void); + +/** + * @brief: Select the corresponding state + * + * Active state can be selected directly, but need hold to suspend the + * pinctrl if the gpios in this pinctrl also held by other pinctrl. + * + * @active : The flag to indicate whether active or suspend + * the shared pinctrl. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_res_mgr_shared_pinctrl_select_state(bool active); + +/** + * @brief: Post init shared pinctrl + * + * Post init to check if the device really has shared gpio, + * suspend and put the pinctrl if not use shared gpio. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_res_mgr_shared_pinctrl_post_init(void); + +/** + * @brief: Request a gpio + * + * Will alloc a gpio_res for the new gpio, other find the corresponding + * gpio_res. + * + * @dev : Pointer to the device + * @gpio : The GPIO number + * @flags : GPIO configuration as specified by GPIOF_* + * @label : A literal description string of this GPIO + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_res_mgr_gpio_request(struct device *dev, unsigned int gpio, + unsigned long flags, const char *label); + +/** + * @brief: Free a array GPIO + * + * Free the GPIOs and release corresponding gpio_res. + * + * @dev : Pointer to the device + * @gpio : Array of the GPIO number + * @num : The number of gpio + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +void cam_res_mgr_gpio_free_arry(struct device *dev, + const struct gpio *array, size_t num); + +/** + * @brief: Set GPIO power level + * + * Add ref count support for shared GPIOs. + * + * @gpio : The GPIO number + * @value : The power level need to setup + * + * @return Status of operation. Negative in case of error. Zero otherwise. + * -EINVAL will be returned if the gpio can't be found in gpio_res_list. + */ +int cam_res_mgr_gpio_set_value(unsigned int gpio, int value); + +/** + * @brief: Config the shared clk ref count + * + * Config the shared clk ref count.. + * + * @value : get or put the shared clk. + * + * @return None + */ +void cam_res_mgr_shared_clk_config(bool value); + +#endif /* __CAM_RES_MGR_API_H__ */ diff --git a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h new file mode 100644 index 000000000000..48611f6fbd7e --- /dev/null +++ b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_RES_MGR_PRIVATE_H__ +#define __CAM_RES_MGR_PRIVATE_H__ + +#include +#include +#include "cam_soc_util.h" + +#define MAX_SHARED_GPIO_SIZE 16 + +/* pinctrl states name */ +#define CAM_RES_MGR_SLEEP "cam_res_mgr_suspend" +#define CAM_RES_MGR_DEFAULT "cam_res_mgr_default" + +/** + * enum pinctrl_status - Enum for pinctrl status + */ +enum pinctrl_status { + PINCTRL_STATUS_GOT = 0, + PINCTRL_STATUS_ACTIVE, + PINCTRL_STATUS_SUSPEND, + PINCTRL_STATUS_PUT, +}; + +/** + * struct cam_dev_res + * + * @list : List member used to append this node to a dev list + * @dev : Device pointer associated with device + */ +struct cam_dev_res { + struct list_head list; + struct device *dev; +}; + +/** + * struct cam_gpio_res + * + * @list : List member used to append this node to a gpio list + * @dev_list : List the device which request this gpio + * @gpio : Gpio value + * @power_on_count : Record the power on times of this gpio + */ +struct cam_gpio_res { + struct list_head list; + struct list_head dev_list; + unsigned int gpio; + int power_on_count; +}; + +/** + * struct cam_pinctrl_res + * + * @list : List member used to append this node to a linked list + * @name : Pointer to the flash trigger's name. + * @trigger : Pointer to the flash trigger + */ +struct cam_flash_res { + struct list_head list; + const char *name; + struct led_trigger *trigger; +}; + +/** + * struct cam_res_mgr_dt + * + * @shared_gpio : Shared gpios list in the device tree + * @num_shared_gpio : The number of shared gpio + * @pinctrl_info : Pinctrl information + */ +struct cam_res_mgr_dt { + uint shared_gpio[MAX_SHARED_GPIO_SIZE]; + int num_shared_gpio; + struct cam_soc_pinctrl_info pinctrl_info; +}; + +/** + * struct cam_pinctrl_res + * + * @dev : Pointer to the device + * @dt : Device tree resource + * @shared_gpio_enabled : The flag to indicate if support shared gpio + * @pstatus : Shared pinctrl status + * @gpio_res_list : List head of the gpio resource + * @flash_res_list : List head of the flash resource + * @gpio_res_lock : GPIO resource lock + * @flash_res_lock : Flash resource lock + * @clk_res_lock : Clk resource lock + */ +struct cam_res_mgr { + struct device *dev; + struct cam_res_mgr_dt dt; + + bool shared_gpio_enabled; + enum pinctrl_status pstatus; + + uint shared_clk_ref_count; + + struct list_head gpio_res_list; + struct list_head flash_res_list; + struct mutex gpio_res_lock; + struct mutex flash_res_lock; + struct mutex clk_res_lock; +}; + +#endif /* __CAM_RES_MGR_PRIVATE_H__ */ diff --git a/drivers/cam_sensor_module/cam_sensor/Makefile b/drivers/cam_sensor_module/cam_sensor/Makefile new file mode 100644 index 000000000000..641b1c490329 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_dev.o cam_sensor_core.o cam_sensor_soc.o diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c new file mode 100644 index 000000000000..680cf4f302bc --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -0,0 +1,1325 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "cam_sensor_core.h" +#include "cam_sensor_util.h" +#include "cam_soc_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + + +static void cam_sensor_update_req_mgr( + struct cam_sensor_ctrl_t *s_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_req_mgr_add_request add_req; + + add_req.link_hdl = s_ctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + CAM_DBG(CAM_SENSOR, " Rxed Req Id: %lld", + csl_packet->header.request_id); + add_req.dev_hdl = s_ctrl->bridge_intf.device_hdl; + add_req.skip_before_applying = 0; + if (s_ctrl->bridge_intf.crm_cb && + s_ctrl->bridge_intf.crm_cb->add_req) + s_ctrl->bridge_intf.crm_cb->add_req(&add_req); + + CAM_DBG(CAM_SENSOR, " add req to req mgr: %lld", + add_req.req_id); +} + +static void cam_sensor_release_stream_rsc( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int rc; + + i2c_set = &(s_ctrl->i2c_data.streamoff_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting Streamoff settings"); + } + + i2c_set = &(s_ctrl->i2c_data.streamon_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting Streamon settings"); + } +} + +static void cam_sensor_release_per_frame_resource( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int i, rc; + + if (s_ctrl->i2c_data.per_frame != NULL) { + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(s_ctrl->i2c_data.per_frame[i]); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + } + } + } +} + +static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, + void *arg) +{ + int32_t rc = 0; + uintptr_t generic_ptr; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct i2c_settings_array *i2c_reg_settings = NULL; + size_t len_of_buff = 0; + size_t remain_len = 0; + uint32_t *offset = NULL; + struct cam_config_dev_cmd config; + struct i2c_data_settings *i2c_data = NULL; + + ioctl_ctrl = (struct cam_control *)arg; + + if (ioctl_ctrl->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_SENSOR, "Invalid Handle Type"); + return -EINVAL; + } + + if (copy_from_user(&config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) + return -EFAULT; + + rc = cam_mem_get_cpu_buf( + config.packet_handle, + &generic_ptr, + &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed in getting the packet: %d", rc); + return rc; + } + + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_SENSOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto end; + } + + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *)(generic_ptr + + (uint32_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_SENSOR, "Invalid packet params"); + rc = -EINVAL; + goto end; + + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG && + csl_packet->header.request_id <= s_ctrl->last_flush_req + && s_ctrl->last_flush_req != 0) { + CAM_ERR(CAM_SENSOR, + "reject request %lld, last request to flush %u", + csl_packet->header.request_id, s_ctrl->last_flush_req); + rc = -EINVAL; + goto end; + } + + if (csl_packet->header.request_id > s_ctrl->last_flush_req) + s_ctrl->last_flush_req = 0; + + i2c_data = &(s_ctrl->i2c_data); + CAM_DBG(CAM_SENSOR, "Header OpCode: %d", csl_packet->header.op_code); + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG: { + i2c_reg_settings = &i2c_data->init_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG: { + i2c_reg_settings = &i2c_data->config_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { + if (s_ctrl->streamon_count > 0) + goto end; + + s_ctrl->streamon_count = s_ctrl->streamon_count + 1; + i2c_reg_settings = &i2c_data->streamon_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { + if (s_ctrl->streamoff_count > 0) + goto end; + + s_ctrl->streamoff_count = s_ctrl->streamoff_count + 1; + i2c_reg_settings = &i2c_data->streamoff_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + + case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { + CAM_WARN(CAM_SENSOR, + "Rxed Update packets without linking"); + goto end; + } + + i2c_reg_settings = + &i2c_data->per_frame[csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY]; + CAM_DBG(CAM_SENSOR, "Received Packet: %lld req: %lld", + csl_packet->header.request_id % MAX_PER_FRAME_ARRAY, + csl_packet->header.request_id); + if (i2c_reg_settings->is_settings_valid == 1) { + CAM_ERR(CAM_SENSOR, + "Already some pkt in offset req : %lld", + csl_packet->header.request_id); + /* + * Update req mgr even in case of failure. + * This will help not to wait indefinitely + * and freeze. If this log is triggered then + * fix it. + */ + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + goto end; + } + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { + CAM_WARN(CAM_SENSOR, + "Rxed NOP packets without linking"); + goto end; + } + + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + goto end; + } + default: + CAM_ERR(CAM_SENSOR, "Invalid Packet Header"); + rc = -EINVAL; + goto end; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += csl_packet->cmd_buf_offset / 4; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + rc = cam_sensor_i2c_command_parser(&s_ctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); + goto end; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) == + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE) { + i2c_reg_settings->request_id = + csl_packet->header.request_id; + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + } + +end: + return rc; +} + +static int32_t cam_sensor_i2c_modes_util( + struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list) +{ + int32_t rc = 0; + uint32_t i, size; + + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { + rc = camera_io_dev_write(io_master_info, + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to random write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 0); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to seq write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_BURST) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to burst write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + io_master_info, + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "i2c poll apply setting Fail: %d", rc); + return rc; + } + } + } + + return rc; +} + +int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info, + struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + struct cam_sensor_cci_client *cci_client = NULL; + + if (s_ctrl->io_master_info.master_type == CCI_MASTER) { + cci_client = s_ctrl->io_master_info.cci_client; + if (!cci_client) { + CAM_ERR(CAM_SENSOR, "failed: cci_client %pK", + cci_client); + return -EINVAL; + } + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = i2c_info->slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + CAM_DBG(CAM_SENSOR, " Master: %d sid: %d freq_mode: %d", + cci_client->cci_i2c_master, i2c_info->slave_addr, + i2c_info->i2c_freq_mode); + } + + s_ctrl->sensordata->slave_info.sensor_slave_addr = + i2c_info->slave_addr; + return rc; +} + +int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, + struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + + s_ctrl->sensordata->slave_info.sensor_id_reg_addr = + probe_info->reg_addr; + s_ctrl->sensordata->slave_info.sensor_id = + probe_info->expected_data; + s_ctrl->sensordata->slave_info.sensor_id_mask = + probe_info->data_mask; + /* Userspace passes the pipeline delay in reserved field */ + s_ctrl->pipeline_delay = + probe_info->reserved; + + s_ctrl->sensor_probe_addr_type = probe_info->addr_type; + s_ctrl->sensor_probe_data_type = probe_info->data_type; + CAM_DBG(CAM_SENSOR, + "Sensor Addr: 0x%x sensor_id: 0x%x sensor_mask: 0x%x sensor_pipeline_delay:0x%x", + s_ctrl->sensordata->slave_info.sensor_id_reg_addr, + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_id_mask, + s_ctrl->pipeline_delay); + return rc; +} + +int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, + struct cam_sensor_ctrl_t *s_ctrl, + int32_t cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len) +{ + int32_t rc = 0; + + switch (cmd_buf_num) { + case 0: { + struct cam_cmd_i2c_info *i2c_info = NULL; + struct cam_cmd_probe *probe_info; + + if (remain_len < + (sizeof(struct cam_cmd_i2c_info) + + sizeof(struct cam_cmd_probe))) { + CAM_ERR(CAM_SENSOR, + "not enough buffer for cam_cmd_i2c_info"); + return -EINVAL; + } + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed in Updating the i2c Info"); + return rc; + } + probe_info = (struct cam_cmd_probe *) + (cmd_buf + sizeof(struct cam_cmd_i2c_info)); + rc = cam_sensor_update_slave_info(probe_info, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Updating the slave Info"); + return rc; + } + cmd_buf = probe_info; + } + break; + case 1: { + rc = cam_sensor_update_power_settings(cmd_buf, + cmd_buf_length, &s_ctrl->sensordata->power_info, + remain_len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in updating power settings"); + return rc; + } + } + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid command buffer"); + break; + } + return rc; +} + +int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0, i; + uint32_t *cmd_buf; + void *ptr; + size_t len; + struct cam_packet *pkt = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cmd_buf1 = 0; + uintptr_t packet = 0; + size_t remain_len = 0; + + rc = cam_mem_get_cpu_buf(handle, + &packet, &len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer"); + return -EINVAL; + } + + pkt = (struct cam_packet *)packet; + if (pkt == NULL) { + CAM_ERR(CAM_SENSOR, "packet pos is invalid"); + rc = -EINVAL; + goto end; + } + + if ((len < sizeof(struct cam_packet)) || + (pkt->cmd_buf_offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_SENSOR, "Not enough buf provided"); + rc = -EINVAL; + goto end; + } + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *)&pkt->payload + pkt->cmd_buf_offset/4); + if (cmd_desc == NULL) { + CAM_ERR(CAM_SENSOR, "command descriptor pos is invalid"); + rc = -EINVAL; + goto end; + } + if (pkt->num_cmd_buf != 2) { + CAM_ERR(CAM_SENSOR, "Expected More Command Buffers : %d", + pkt->num_cmd_buf); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < pkt->num_cmd_buf; i++) { + if (!(cmd_desc[i].length)) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &cmd_buf1, &len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to parse the command Buffer Header"); + goto end; + } + if (cmd_desc[i].offset >= len) { + CAM_ERR(CAM_SENSOR, + "offset past length of buffer"); + rc = -EINVAL; + goto end; + } + remain_len = len - cmd_desc[i].offset; + if (cmd_desc[i].length > remain_len) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided for cmd"); + rc = -EINVAL; + goto end; + } + cmd_buf = (uint32_t *)cmd_buf1; + cmd_buf += cmd_desc[i].offset/4; + ptr = (void *) cmd_buf; + + rc = cam_handle_cmd_buffers_for_probe(ptr, s_ctrl, + i, cmd_desc[i].length, remain_len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to parse the command Buffer Header"); + goto end; + } + } + +end: + return rc; +} + +void cam_sensor_query_cap(struct cam_sensor_ctrl_t *s_ctrl, + struct cam_sensor_query_cap *query_cap) +{ + query_cap->pos_roll = s_ctrl->sensordata->pos_roll; + query_cap->pos_pitch = s_ctrl->sensordata->pos_pitch; + query_cap->pos_yaw = s_ctrl->sensordata->pos_yaw; + query_cap->secure_camera = 0; + query_cap->actuator_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_ACTUATOR]; + query_cap->csiphy_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY]; + query_cap->eeprom_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_EEPROM]; + query_cap->flash_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_LED_FLASH]; + query_cap->ois_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_OIS]; + query_cap->slot_info = + s_ctrl->soc_info.index; +} + +static uint16_t cam_sensor_id_by_mask(struct cam_sensor_ctrl_t *s_ctrl, + uint32_t chipid) +{ + uint16_t sensor_id = (uint16_t)(chipid & 0xFFFF); + int16_t sensor_id_mask = s_ctrl->sensordata->slave_info.sensor_id_mask; + + if (!sensor_id_mask) + sensor_id_mask = ~sensor_id_mask; + + sensor_id &= sensor_id_mask; + sensor_id_mask &= -sensor_id_mask; + sensor_id_mask -= 1; + while (sensor_id_mask) { + sensor_id_mask >>= 1; + sensor_id >>= 1; + } + return sensor_id; +} + +void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) +{ + struct cam_sensor_power_ctrl_t *power_info = + &s_ctrl->sensordata->power_info; + int rc = 0; + + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) && + (s_ctrl->is_probe_succeed == 0)) + return; + + cam_sensor_release_stream_rsc(s_ctrl); + cam_sensor_release_per_frame_resource(s_ctrl); + + if (s_ctrl->sensor_state != CAM_SENSOR_INIT) + cam_sensor_power_down(s_ctrl); + + rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "dhdl already destroyed: rc = %d", rc); + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.session_hdl = -1; + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + s_ctrl->streamon_count = 0; + s_ctrl->streamoff_count = 0; + s_ctrl->is_probe_succeed = 0; + s_ctrl->last_flush_req = 0; + s_ctrl->sensor_state = CAM_SENSOR_INIT; +} + +int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint32_t chipid = 0; + struct cam_camera_slave_info *slave_info; + + slave_info = &(s_ctrl->sensordata->slave_info); + + if (!slave_info) { + CAM_ERR(CAM_SENSOR, " failed: %pK", + slave_info); + return -EINVAL; + } + + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + slave_info->sensor_id_reg_addr, + &chipid, CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_WORD); + + CAM_DBG(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + + if (cam_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) { + CAM_WARN(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + return -ENODEV; + } + return rc; +} + +int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, + void *arg) +{ + int rc = 0; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_sensor_power_ctrl_t *power_info = + &s_ctrl->sensordata->power_info; + if (!s_ctrl || !arg) { + CAM_ERR(CAM_SENSOR, "s_ctrl is NULL"); + return -EINVAL; + } + + if (cmd->op_code != CAM_SENSOR_PROBE_CMD) { + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_SENSOR, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + switch (cmd->op_code) { + case CAM_SENSOR_PROBE_CMD: { + if (s_ctrl->is_probe_succeed == 1) { + CAM_ERR(CAM_SENSOR, + "Already Sensor Probed in the slot"); + break; + } + + if (cmd->handle_type == + CAM_HANDLE_MEM_HANDLE) { + rc = cam_handle_mem_ptr(cmd->handle, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Get Buffer Handle Failed"); + goto release_mutex; + } + } else { + CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d", + cmd->handle_type); + rc = -EINVAL; + goto release_mutex; + } + + /* Parse and fill vreg params for powerup settings */ + rc = msm_camera_fill_vreg_params( + &s_ctrl->soc_info, + s_ctrl->sensordata->power_info.power_setting, + s_ctrl->sensordata->power_info.power_setting_size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in filling vreg params for PUP rc %d", + rc); + goto free_power_settings; + } + + /* Parse and fill vreg params for powerdown settings*/ + rc = msm_camera_fill_vreg_params( + &s_ctrl->soc_info, + s_ctrl->sensordata->power_info.power_down_setting, + s_ctrl->sensordata->power_info.power_down_setting_size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in filling vreg params for PDOWN rc %d", + rc); + goto free_power_settings; + } + + /* Power up and probe sensor */ + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + goto free_power_settings; + } + + /* Match sensor ID */ + rc = cam_sensor_match_id(s_ctrl); + if (rc < 0) { + cam_sensor_power_down(s_ctrl); + msleep(20); + goto free_power_settings; + } + + CAM_INFO(CAM_SENSOR, + "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x", + s_ctrl->soc_info.index, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + s_ctrl->sensordata->slave_info.sensor_id); + + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); + goto free_power_settings; + } + /* + * Set probe succeeded flag to 1 so that no other camera shall + * probed on this slot + */ + s_ctrl->is_probe_succeed = 1; + s_ctrl->sensor_state = CAM_SENSOR_INIT; + } + break; + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev sensor_acq_dev; + struct cam_create_dev_hdl bridge_params; + + if ((s_ctrl->is_probe_succeed == 0) || + (s_ctrl->sensor_state != CAM_SENSOR_INIT)) { + CAM_WARN(CAM_SENSOR, + "Not in right state to aquire %d", + s_ctrl->sensor_state); + rc = -EINVAL; + goto release_mutex; + } + + if (s_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_SENSOR, "Device is already acquired"); + rc = -EINVAL; + goto release_mutex; + } + rc = copy_from_user(&sensor_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(sensor_acq_dev)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed Copying from user"); + goto release_mutex; + } + + bridge_params.session_hdl = sensor_acq_dev.session_handle; + bridge_params.ops = &s_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = s_ctrl; + + sensor_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; + s_ctrl->bridge_intf.session_hdl = sensor_acq_dev.session_handle; + + CAM_DBG(CAM_SENSOR, "Device Handle: %d", + sensor_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &sensor_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_SENSOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); + goto release_mutex; + } + + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + s_ctrl->last_flush_req = 0; + CAM_INFO(CAM_SENSOR, + "CAM_ACQUIRE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_RELEASE_DEV: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_START)) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to release : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + if (s_ctrl->bridge_intf.link_hdl != -1) { + CAM_ERR(CAM_SENSOR, + "Device [%d] still active on link 0x%x", + s_ctrl->sensor_state, + s_ctrl->bridge_intf.link_hdl); + rc = -EAGAIN; + goto release_mutex; + } + + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); + goto release_mutex; + } + + cam_sensor_release_per_frame_resource(s_ctrl); + cam_sensor_release_stream_rsc(s_ctrl); + if (s_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_SENSOR, + "Invalid Handles: link hdl: %d device hdl: %d", + s_ctrl->bridge_intf.device_hdl, + s_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed in destroying the device hdl"); + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.session_hdl = -1; + + s_ctrl->sensor_state = CAM_SENSOR_INIT; + CAM_INFO(CAM_SENSOR, + "CAM_RELEASE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + s_ctrl->streamon_count = 0; + s_ctrl->streamoff_count = 0; + s_ctrl->last_flush_req = 0; + } + break; + case CAM_QUERY_CAP: { + struct cam_sensor_query_cap sensor_cap; + + cam_sensor_query_cap(s_ctrl, &sensor_cap); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &sensor_cap, sizeof(struct cam_sensor_query_cap))) { + CAM_ERR(CAM_SENSOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + break; + } + case CAM_START_DEV: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_START)) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to start : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + if (s_ctrl->i2c_data.streamon_settings.is_settings_valid && + (s_ctrl->i2c_data.streamon_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply streamon settings"); + goto release_mutex; + } + } + s_ctrl->sensor_state = CAM_SENSOR_START; + CAM_INFO(CAM_SENSOR, + "CAM_START_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_STOP_DEV: { + if (s_ctrl->sensor_state != CAM_SENSOR_START) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to stop : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid && + (s_ctrl->i2c_data.streamoff_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply streamoff settings"); + } + } + + cam_sensor_release_per_frame_resource(s_ctrl); + s_ctrl->last_flush_req = 0; + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + CAM_INFO(CAM_SENSOR, + "CAM_STOP_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_CONFIG_DEV: { + rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); + goto release_mutex; + } + if (s_ctrl->i2c_data.init_settings.is_settings_valid && + (s_ctrl->i2c_data.init_settings.request_id == 0)) { + + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG); + + s_ctrl->i2c_data.init_settings.request_id = -1; + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply init settings"); + delete_request(&s_ctrl->i2c_data.init_settings); + goto release_mutex; + } + rc = delete_request(&s_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the Init settings"); + goto release_mutex; + } + } + + if (s_ctrl->i2c_data.config_settings.is_settings_valid && + (s_ctrl->i2c_data.config_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG); + + s_ctrl->i2c_data.config_settings.request_id = -1; + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply config settings"); + delete_request( + &s_ctrl->i2c_data.config_settings); + goto release_mutex; + } + rc = delete_request(&s_ctrl->i2c_data.config_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the config settings"); + goto release_mutex; + } + s_ctrl->sensor_state = CAM_SENSOR_CONFIG; + } + } + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + goto release_mutex; + } + +release_mutex: + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; + +free_power_settings: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; +} + +int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info) +{ + int rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + + if (!info) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(info->dev_hdl); + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + + info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR; + strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name)); + if (s_ctrl->pipeline_delay >= 1 && s_ctrl->pipeline_delay <= 3) + info->p_delay = s_ctrl->pipeline_delay; + else + info->p_delay = 2; + info->trigger = CAM_TRIGGER_POINT_SOF; + + return rc; +} + +int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_sensor_ctrl_t *s_ctrl = NULL; + + if (!link) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(link->dev_hdl); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&s_ctrl->cam_sensor_mutex); + if (link->link_enable) { + s_ctrl->bridge_intf.link_hdl = link->link_hdl; + s_ctrl->bridge_intf.crm_cb = link->crm_cb; + } else { + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.crm_cb = NULL; + } + mutex_unlock(&s_ctrl->cam_sensor_mutex); + + return 0; +} + +int cam_sensor_power(struct v4l2_subdev *sd, int on) +{ + struct cam_sensor_ctrl_t *s_ctrl = v4l2_get_subdevdata(sd); + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if (!on && s_ctrl->sensor_state == CAM_SENSOR_START) { + cam_sensor_power_down(s_ctrl); + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + } + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + + return 0; +} + +int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_camera_slave_info *slave_info; + struct cam_hw_soc_info *soc_info = + &s_ctrl->soc_info; + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "failed: %pK", s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + slave_info = &(s_ctrl->sensordata->slave_info); + + if (!power_info || !slave_info) { + CAM_ERR(CAM_SENSOR, "failed: %pK %pK", power_info, slave_info); + return -EINVAL; + } + + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, true); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up the core is failed:%d", rc); + return rc; + } + + rc = camera_io_init(&(s_ctrl->io_master_info)); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "cci_init failed: rc: %d", rc); + + return rc; +} + +int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl) +{ + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "failed: s_ctrl %pK", s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + soc_info = &s_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_SENSOR, "failed: power_info %pK", power_info); + return -EINVAL; + } + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power down the core is failed:%d", rc); + return rc; + } + + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, false); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + + camera_io_release(&(s_ctrl->io_master_info)); + + return rc; +} + +int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, + int64_t req_id, enum cam_sensor_packet_opcodes opcode) +{ + int rc = 0, offset, i; + uint64_t top = 0, del_req_id = 0; + struct i2c_settings_array *i2c_set = NULL; + struct i2c_settings_list *i2c_list; + + if (req_id == 0) { + switch (opcode) { + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { + i2c_set = &s_ctrl->i2c_data.streamon_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG: { + i2c_set = &s_ctrl->i2c_data.init_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG: { + i2c_set = &s_ctrl->i2c_data.config_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { + i2c_set = &s_ctrl->i2c_data.streamoff_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: + case CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE: + default: + return 0; + } + if (i2c_set->is_settings_valid == 1) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_i2c_modes_util( + &(s_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to apply settings: %d", + rc); + return rc; + } + } + } + } else { + offset = req_id % MAX_PER_FRAME_ARRAY; + i2c_set = &(s_ctrl->i2c_data.per_frame[offset]); + if (i2c_set->is_settings_valid == 1 && + i2c_set->request_id == req_id) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_i2c_modes_util( + &(s_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to apply settings: %d", + rc); + return rc; + } + } + } else { + CAM_DBG(CAM_SENSOR, + "Invalid/NOP request to apply: %lld", req_id); + } + + /* Change the logic dynamically */ + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((req_id >= + s_ctrl->i2c_data.per_frame[i].request_id) && + (top < + s_ctrl->i2c_data.per_frame[i].request_id) && + (s_ctrl->i2c_data.per_frame[i].is_settings_valid + == 1)) { + del_req_id = top; + top = s_ctrl->i2c_data.per_frame[i].request_id; + } + } + + if (top < req_id) { + if ((((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) || + (((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX)) + del_req_id = req_id; + } + + if (!del_req_id) + return rc; + + CAM_DBG(CAM_SENSOR, "top: %llu, del_req_id:%llu", + top, del_req_id); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((del_req_id > + s_ctrl->i2c_data.per_frame[i].request_id) && ( + s_ctrl->i2c_data.per_frame[i].is_settings_valid + == 1)) { + s_ctrl->i2c_data.per_frame[i].request_id = 0; + rc = delete_request( + &(s_ctrl->i2c_data.per_frame[i])); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "Delete request Fail:%lld rc:%d", + del_req_id, rc); + } + } + } + + return rc; +} + +int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) +{ + int32_t rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + + if (!apply) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(apply->dev_hdl); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + CAM_DBG(CAM_REQ, " Sensor update req id: %lld", apply->request_id); + trace_cam_apply_req("Sensor", apply->request_id); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + rc = cam_sensor_apply_settings(s_ctrl, apply->request_id, + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; +} + +int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) +{ + int32_t rc = 0, i; + uint32_t cancel_req_id_found = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + struct i2c_settings_array *i2c_set = NULL; + + if (!flush_req) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(flush_req->dev_hdl); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if (s_ctrl->sensor_state != CAM_SENSOR_START || + s_ctrl->sensor_state != CAM_SENSOR_CONFIG) { + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; + } + + if (s_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_SENSOR, "i2c frame data is NULL"); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return -EINVAL; + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + s_ctrl->last_flush_req = flush_req->req_id; + CAM_DBG(CAM_SENSOR, "last reqest to flush is %lld", + flush_req->req_id); + } + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(s_ctrl->i2c_data.per_frame[i]); + + if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) + && (i2c_set->request_id != flush_req->req_id)) + continue; + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + + if (flush_req->type == + CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + cancel_req_id_found = 1; + break; + } + } + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_SENSOR, + "Flush request id:%lld not found in the pending list", + flush_req->req_id); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; +} diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h new file mode 100644 index 000000000000..b7a5923a6a70 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_CORE_H_ +#define _CAM_SENSOR_CORE_H_ + +#include "cam_sensor_dev.h" + +/** + * @s_ctrl: Sensor ctrl structure + * + * This API powers up the camera sensor module + */ +int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl); + +/** + * @s_ctrl: Sensor ctrl structure + * + * This API powers down the camera sensor module + */ +int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl); + +/** + * @sd: V4L2 subdevice + * @on: Turn off/on flag + * + * This API powers down the sensor module + */ +int cam_sensor_power(struct v4l2_subdev *sd, int on); + +/** + * @s_ctrl: Sensor ctrl structure + * @req_id: Request id + * @opcode: opcode for settings + * + * This API applies the req_id settings to sensor + */ +int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, int64_t req_id, + enum cam_sensor_packet_opcodes opcode); + +/** + * @apply: Req mgr structure for applying request + * + * This API applies the request that is mentioned + */ +int cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply); + +/** + * @flush: Req mgr structure for flushing request + * + * This API flushes the request that is mentioned + */ +int cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush); + +/** + * @info: Sub device info to req mgr + * + * Publish the subdevice info + */ +int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info); + +/** + * @link: Link setup info + * + * This API establishes link with sensor subdevice with req mgr + */ +int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link); + +/** + * @s_ctrl: Sensor ctrl structure + * @arg: Camera control command argument + * + * This API handles the camera control argument reached to sensor + */ +int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, void *arg); + +/** + * @s_ctrl: Sensor ctrl structure + * + * This API handles the camera sensor close/shutdown + */ +void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl); + +#endif /* _CAM_SENSOR_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c new file mode 100644 index 000000000000..f847079c730a --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_sensor_soc.h" +#include "cam_sensor_core.h" + +static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_sensor_driver_cmd(s_ctrl, arg); + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_sensor_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "s_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_sensor_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_SENSOR, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_sensor_subdev_ioctl(sd, cmd, &cmd_data); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "cam_sensor_subdev_ioctl failed"); + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid compat ioctl cmd_type: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_SENSOR, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} + +#endif +static struct v4l2_subdev_core_ops cam_sensor_subdev_core_ops = { + .ioctl = cam_sensor_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_sensor_init_subdev_do_ioctl, +#endif + .s_power = cam_sensor_power, +}; + +static struct v4l2_subdev_ops cam_sensor_subdev_ops = { + .core = &cam_sensor_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_sensor_internal_ops = { + .close = cam_sensor_subdev_close, +}; + +static int cam_sensor_init_subdev_params(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + + s_ctrl->v4l2_dev_str.internal_ops = + &cam_sensor_internal_ops; + s_ctrl->v4l2_dev_str.ops = + &cam_sensor_subdev_ops; + strlcpy(s_ctrl->device_name, CAMX_SENSOR_DEV_NAME, + sizeof(s_ctrl->device_name)); + s_ctrl->v4l2_dev_str.name = + s_ctrl->device_name; + s_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + s_ctrl->v4l2_dev_str.ent_function = + CAM_SENSOR_DEVICE_TYPE; + s_ctrl->v4l2_dev_str.token = s_ctrl; + + rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev rc: %d", rc); + + return rc; +} + +static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0; + int i = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + struct cam_hw_soc_info *soc_info = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_SENSOR, + "%s :i2c_check_functionality failed", client->name); + return -EFAULT; + } + + /* Create sensor control structure */ + s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); + if (!s_ctrl) + return -ENOMEM; + + i2c_set_clientdata(client, s_ctrl); + + s_ctrl->io_master_info.client = client; + soc_info = &s_ctrl->soc_info; + soc_info->dev = &client->dev; + soc_info->dev_name = client->name; + + /* Initialize sensor device type */ + s_ctrl->of_node = client->dev.of_node; + s_ctrl->io_master_info.master_type = I2C_MASTER; + s_ctrl->is_probe_succeed = 0; + s_ctrl->last_flush_req = 0; + + rc = cam_sensor_parse_dt(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "cam_sensor_parse_dt rc %d", rc); + goto free_s_ctrl; + } + + rc = cam_sensor_init_subdev_params(s_ctrl); + if (rc) + goto free_s_ctrl; + + s_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (s_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(s_ctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); + + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info; + s_ctrl->bridge_intf.ops.link_setup = cam_sensor_establish_link; + s_ctrl->bridge_intf.ops.apply_req = cam_sensor_apply_request; + s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request; + + s_ctrl->sensordata->power_info.dev = soc_info->dev; + + return rc; +unreg_subdev: + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); +free_s_ctrl: + kfree(s_ctrl); + return rc; +} + +static int cam_sensor_platform_remove(struct platform_device *pdev) +{ + int i; + struct cam_sensor_ctrl_t *s_ctrl; + struct cam_hw_soc_info *soc_info; + + s_ctrl = platform_get_drvdata(pdev); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "sensor device is NULL"); + return 0; + } + + CAM_INFO(CAM_SENSOR, "platform remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); + soc_info = &s_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + kfree(s_ctrl->i2c_data.per_frame); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); + devm_kfree(&pdev->dev, s_ctrl); + + return 0; +} + +static int cam_sensor_driver_i2c_remove(struct i2c_client *client) +{ + int i; + struct cam_sensor_ctrl_t *s_ctrl = i2c_get_clientdata(client); + struct cam_hw_soc_info *soc_info; + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "sensor device is NULL"); + return 0; + } + + CAM_INFO(CAM_SENSOR, "i2c remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); + soc_info = &s_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + kfree(s_ctrl->i2c_data.per_frame); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); + kfree(s_ctrl); + + return 0; +} + +static const struct of_device_id cam_sensor_driver_dt_match[] = { + {.compatible = "qcom,cam-sensor"}, + {} +}; + +static int32_t cam_sensor_driver_platform_probe( + struct platform_device *pdev) +{ + int32_t rc = 0, i = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + struct cam_hw_soc_info *soc_info = NULL; + + /* Create sensor control structure */ + s_ctrl = devm_kzalloc(&pdev->dev, + sizeof(struct cam_sensor_ctrl_t), GFP_KERNEL); + if (!s_ctrl) + return -ENOMEM; + + soc_info = &s_ctrl->soc_info; + soc_info->pdev = pdev; + soc_info->dev = &pdev->dev; + soc_info->dev_name = pdev->name; + + /* Initialize sensor device type */ + s_ctrl->of_node = pdev->dev.of_node; + s_ctrl->is_probe_succeed = 0; + s_ctrl->last_flush_req = 0; + + /*fill in platform device*/ + s_ctrl->pdev = pdev; + + s_ctrl->io_master_info.master_type = CCI_MASTER; + + rc = cam_sensor_parse_dt(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed: cam_sensor_parse_dt rc %d", rc); + goto free_s_ctrl; + } + + /* Fill platform device id*/ + pdev->id = soc_info->index; + + rc = cam_sensor_init_subdev_params(s_ctrl); + if (rc) + goto free_s_ctrl; + + s_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (s_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(s_ctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); + + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info; + s_ctrl->bridge_intf.ops.link_setup = cam_sensor_establish_link; + s_ctrl->bridge_intf.ops.apply_req = cam_sensor_apply_request; + s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request; + + s_ctrl->sensordata->power_info.dev = &pdev->dev; + platform_set_drvdata(pdev, s_ctrl); + s_ctrl->sensor_state = CAM_SENSOR_INIT; + + return rc; +unreg_subdev: + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); +free_s_ctrl: + devm_kfree(&pdev->dev, s_ctrl); + return rc; +} + +MODULE_DEVICE_TABLE(of, cam_sensor_driver_dt_match); + +static struct platform_driver cam_sensor_platform_driver = { + .probe = cam_sensor_driver_platform_probe, + .driver = { + .name = "qcom,camera", + .owner = THIS_MODULE, + .of_match_table = cam_sensor_driver_dt_match, + .suppress_bind_attrs = true, + }, + .remove = cam_sensor_platform_remove, +}; + +static const struct i2c_device_id i2c_id[] = { + {SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_sensor_driver_i2c = { + .id_table = i2c_id, + .probe = cam_sensor_driver_i2c_probe, + .remove = cam_sensor_driver_i2c_remove, + .driver = { + .name = SENSOR_DRIVER_I2C, + }, +}; + +static int __init cam_sensor_driver_init(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_sensor_platform_driver); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "platform_driver_register Failed: rc = %d", + rc); + return rc; + } + + rc = i2c_add_driver(&cam_sensor_driver_i2c); + if (rc) + CAM_ERR(CAM_SENSOR, "i2c_add_driver failed rc = %d", rc); + + return rc; +} + +static void __exit cam_sensor_driver_exit(void) +{ + platform_driver_unregister(&cam_sensor_platform_driver); + i2c_del_driver(&cam_sensor_driver_i2c); +} + +module_init(cam_sensor_driver_init); +module_exit(cam_sensor_driver_exit); +MODULE_DESCRIPTION("cam_sensor_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h new file mode 100644 index 000000000000..86676a4c8f0a --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_DEV_H_ +#define _CAM_SENSOR_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_debug_util.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#undef CDBG +#ifdef CAM_SENSOR_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define SENSOR_DRIVER_I2C "i2c_camera" +#define CAMX_SENSOR_DEV_NAME "cam-sensor-driver" + +enum cam_sensor_state_t { + CAM_SENSOR_INIT, + CAM_SENSOR_ACQUIRE, + CAM_SENSOR_CONFIG, + CAM_SENSOR_START, +}; + +/** + * struct intf_params + * @device_hdl: Device Handle + * @session_hdl: Session Handle + * @link_hdl: Link Handle + * @ops: KMD operations + * @crm_cb: Callback API pointers + */ +struct intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_sensor_ctrl_t: Camera control structure + * @pdev: Platform device + * @cam_sensor_mutex: Sensor mutex + * @sensordata: Sensor board Information + * @cci_i2c_master: I2C structure + * @io_master_info: Information about the communication master + * @sensor_state: Sensor states + * @is_probe_succeed: Probe succeeded or not + * @id: Cell Index + * @of_node: Of node ptr + * @v4l2_dev_str: V4L2 device structure + * @sensor_probe_addr_type: Sensor probe address type + * @sensor_probe_data_type: Sensor probe data type + * @i2c_data: Sensor I2C register settings + * @sensor_info: Sensor query cap structure + * @bridge_intf: Bridge interface structure + * @device_name: Sensor device structure + * @streamon_count: Count to hold the number of times stream on called + * @streamoff_count: Count to hold the number of times stream off called + * @bob_reg_index: Hold to BoB regulator index + * @bob_pwm_switch: Boolean flag to switch into PWM mode for BoB regulator + * @last_flush_req: Last request to flush + * @pipeline_delay: Sensor pipeline delay + */ +struct cam_sensor_ctrl_t { + struct platform_device *pdev; + struct cam_hw_soc_info soc_info; + struct mutex cam_sensor_mutex; + struct cam_sensor_board_info *sensordata; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct camera_io_master io_master_info; + enum cam_sensor_state_t sensor_state; + uint8_t is_probe_succeed; + uint32_t id; + struct device_node *of_node; + struct cam_subdev v4l2_dev_str; + uint8_t sensor_probe_addr_type; + uint8_t sensor_probe_data_type; + struct i2c_data_settings i2c_data; + struct cam_sensor_query_cap sensor_info; + struct intf_params bridge_intf; + char device_name[20]; + uint32_t streamon_count; + uint32_t streamoff_count; + int bob_reg_index; + bool bob_pwm_switch; + uint32_t last_flush_req; + uint16_t pipeline_delay; +}; + +#endif /* _CAM_SENSOR_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c new file mode 100644 index 000000000000..2c25ee0aa6f0 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_sensor_soc.h" +#include "cam_soc_util.h" + +int32_t cam_sensor_get_sub_module_index(struct device_node *of_node, + struct cam_sensor_board_info *s_info) +{ + int rc = 0, i = 0; + uint32_t val = 0; + struct device_node *src_node = NULL; + struct cam_sensor_board_info *sensor_info; + + sensor_info = s_info; + + for (i = 0; i < SUB_MODULE_MAX; i++) + sensor_info->subdev_id[i] = -1; + + src_node = of_parse_phandle(of_node, "actuator-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, "src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, "actuator cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val; + of_node_put(src_node); + } + + src_node = of_parse_phandle(of_node, "ois-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, "src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, " ois cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_OIS] = val; + of_node_put(src_node); + } + + src_node = of_parse_phandle(of_node, "eeprom-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, "eeprom src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, "eeprom cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; + of_node_put(src_node); + } + + src_node = of_parse_phandle(of_node, "led-flash-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, " src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, "led flash cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val; + of_node_put(src_node); + } + + rc = of_property_read_u32(of_node, "csiphy-sd-index", &val); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "paring the dt node for csiphy rc %d", rc); + else + sensor_info->subdev_id[SUB_MODULE_CSIPHY] = val; + + return rc; +} + +static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + int i = 0; + struct cam_sensor_board_info *sensordata = NULL; + struct device_node *of_node = s_ctrl->of_node; + struct device_node *of_parent = NULL; + struct cam_hw_soc_info *soc_info = &s_ctrl->soc_info; + + s_ctrl->sensordata = kzalloc(sizeof(*sensordata), GFP_KERNEL); + if (!s_ctrl->sensordata) + return -ENOMEM; + + sensordata = s_ctrl->sensordata; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to read DT properties rc %d", rc); + goto FREE_SENSOR_DATA; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &sensordata->power_info.gpio_num_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to read gpios %d", rc); + goto FREE_SENSOR_DATA; + } + + s_ctrl->id = soc_info->index; + + /* Validate cell_id */ + if (s_ctrl->id >= MAX_CAMERAS) { + CAM_ERR(CAM_SENSOR, "Failed invalid cell_id %d", s_ctrl->id); + rc = -EINVAL; + goto FREE_SENSOR_DATA; + } + + /* Store the index of BoB regulator if it is available */ + for (i = 0; i < soc_info->num_rgltr; i++) { + if (!strcmp(soc_info->rgltr_name[i], + "cam_bob")) { + CAM_DBG(CAM_SENSOR, + "i: %d cam_bob", i); + s_ctrl->bob_reg_index = i; + soc_info->rgltr[i] = devm_regulator_get(soc_info->dev, + soc_info->rgltr_name[i]); + if (IS_ERR_OR_NULL(soc_info->rgltr[i])) { + CAM_WARN(CAM_SENSOR, + "Regulator: %s get failed", + soc_info->rgltr_name[i]); + soc_info->rgltr[i] = NULL; + } else { + if (!of_property_read_bool(of_node, + "pwm-switch")) { + CAM_DBG(CAM_SENSOR, + "No BoB PWM switch param defined"); + s_ctrl->bob_pwm_switch = false; + } else { + s_ctrl->bob_pwm_switch = true; + } + } + } + } + + /* Read subdev info */ + rc = cam_sensor_get_sub_module_index(of_node, sensordata); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed to get sub module index, rc=%d", + rc); + goto FREE_SENSOR_DATA; + } + + if (s_ctrl->io_master_info.master_type == CCI_MASTER) { + /* Get CCI master */ + rc = of_property_read_u32(of_node, "cci-master", + &s_ctrl->cci_i2c_master); + CAM_DBG(CAM_SENSOR, "cci-master %d, rc %d", + s_ctrl->cci_i2c_master, rc); + if (rc < 0) { + /* Set default master 0 */ + s_ctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &s_ctrl->cci_num) < 0) + /* Set default master 0 */ + s_ctrl->cci_num = CCI_DEVICE_0; + + CAM_DBG(CAM_SENSOR, "cci-index %d", s_ctrl->cci_num); + } + + if (of_property_read_u32(of_node, "sensor-position-pitch", + &sensordata->pos_pitch) < 0) { + CAM_DBG(CAM_SENSOR, "Invalid sensor position"); + sensordata->pos_pitch = 360; + } + if (of_property_read_u32(of_node, "sensor-position-roll", + &sensordata->pos_roll) < 0) { + CAM_DBG(CAM_SENSOR, "Invalid sensor position"); + sensordata->pos_roll = 360; + } + if (of_property_read_u32(of_node, "sensor-position-yaw", + &sensordata->pos_yaw) < 0) { + CAM_DBG(CAM_SENSOR, "Invalid sensor position"); + sensordata->pos_yaw = 360; + } + + return rc; + +FREE_SENSOR_DATA: + kfree(sensordata); + return rc; +} + +int32_t msm_sensor_init_default_params(struct cam_sensor_ctrl_t *s_ctrl) +{ + /* Validate input parameters */ + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "failed: invalid params s_ctrl %pK", + s_ctrl); + return -EINVAL; + } + + CAM_DBG(CAM_SENSOR, + "master_type: %d", s_ctrl->io_master_info.master_type); + /* Initialize cci_client */ + if (s_ctrl->io_master_info.master_type == CCI_MASTER) { + s_ctrl->io_master_info.cci_client = kzalloc(sizeof( + struct cam_sensor_cci_client), GFP_KERNEL); + if (!(s_ctrl->io_master_info.cci_client)) + return -ENOMEM; + + s_ctrl->io_master_info.cci_client->cci_device + = s_ctrl->cci_num; + } else if (s_ctrl->io_master_info.master_type == I2C_MASTER) { + if (!(s_ctrl->io_master_info.client)) + return -EINVAL; + } else { + CAM_ERR(CAM_SENSOR, + "Invalid master / Master type Not supported"); + return -EINVAL; + } + + return 0; +} + +int32_t cam_sensor_parse_dt(struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t i, rc = 0; + struct cam_hw_soc_info *soc_info = &s_ctrl->soc_info; + + /* Parse dt information and store in sensor control structure */ + rc = cam_sensor_driver_get_dt_data(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to get dt data rc %d", rc); + return rc; + } + + /* Initialize mutex */ + mutex_init(&(s_ctrl->cam_sensor_mutex)); + + /* Initialize default parameters */ + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = devm_clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_SENSOR, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + return rc; + } + } + rc = msm_sensor_init_default_params(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "failed: msm_sensor_init_default_params rc %d", rc); + goto FREE_DT_DATA; + } + + return rc; + +FREE_DT_DATA: + kfree(s_ctrl->sensordata); + s_ctrl->sensordata = NULL; + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.h new file mode 100644 index 000000000000..99862da046ff --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_SOC_H_ +#define _CAM_SENSOR_SOC_H_ + +#include "cam_sensor_dev.h" + +/** + * @s_ctrl: Sensor ctrl structure + * + * Parses sensor dt + */ +int cam_sensor_parse_dt(struct cam_sensor_ctrl_t *s_ctrl); + +#endif /* _CAM_SENSOR_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_sensor_io/Makefile b/drivers/cam_sensor_module/cam_sensor_io/Makefile new file mode 100644 index 000000000000..34ab4315aa92 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io.o cam_sensor_cci_i2c.o cam_sensor_qup_i2c.o cam_sensor_spi.o diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c new file mode 100644 index 000000000000..a5e780a2e119 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_cmn_header.h" +#include "cam_sensor_i2c.h" +#include "cam_cci_dev.h" + +int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int32_t rc = -EINVAL; + unsigned char buf[CAMERA_SENSOR_I2C_TYPE_DWORD]; + struct cam_cci_ctrl cci_ctrl; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + return rc; + + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; + rc = v4l2_subdev_call(cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "rc = %d", rc); + return rc; + } + + rc = cci_ctrl.status; + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + *data = buf[0]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) + *data = buf[0] << 8 | buf[1]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) + *data = buf[0] << 16 | buf[1] << 8 | buf[2]; + else + *data = buf[0] << 24 | buf[1] << 16 | + buf[2] << 8 | buf[3]; + + return rc; +} + +int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char *buf = NULL; + int i = 0; + struct cam_cci_ctrl cci_ctrl; + + if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (num_byte > I2C_REG_DATA_MAX)) { + CAM_ERR(CAM_SENSOR, "addr_type %d num_byte %d", addr_type, + num_byte); + return rc; + } + + buf = kzalloc(num_byte, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; + cci_ctrl.status = -EFAULT; + rc = v4l2_subdev_call(cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + rc = cci_ctrl.status; + CAM_DBG(CAM_SENSOR, "addr = 0x%x, rc = %d", addr, rc); + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + CAM_DBG(CAM_SENSOR, "Byte %d: Data: 0x%x\n", i, data[i]); + } + kfree(buf); + return rc; +} + +static int32_t cam_cci_i2c_write_table_cmd( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + enum cam_cci_cmd_type cmd) +{ + int32_t rc = -EINVAL; + struct cam_cci_ctrl cci_ctrl; + + if (!client || !write_setting) + return rc; + + if (write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + return rc; + + cci_ctrl.cmd = cmd; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = + write_setting->reg_setting; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = write_setting->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed rc = %d", rc); + return rc; + } + rc = cci_ctrl.status; + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + + +int32_t cam_cci_i2c_write_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + return cam_cci_i2c_write_table_cmd(client, write_setting, + MSM_CCI_I2C_WRITE); +} + +int32_t cam_cci_i2c_write_continuous_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag) +{ + int32_t rc = 0; + + if (cam_sensor_i2c_write_flag == 1) + rc = cam_cci_i2c_write_table_cmd(client, write_setting, + MSM_CCI_I2C_WRITE_BURST); + else if (cam_sensor_i2c_write_flag == 0) + rc = cam_cci_i2c_write_table_cmd(client, write_setting, + MSM_CCI_I2C_WRITE_SEQ); + + return rc; +} + +static int32_t cam_cci_i2c_compare(struct cam_sensor_cci_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type) +{ + int32_t rc; + uint32_t reg_data = 0; + + rc = cam_cci_i2c_read(client, addr, ®_data, + addr_type, data_type); + if (rc < 0) + return rc; + + reg_data = reg_data & 0xFFFF; + if (data == (reg_data & ~data_mask)) + return I2C_COMPARE_MATCH; + return I2C_COMPARE_MISMATCH; +} + +int32_t cam_cci_i2c_poll(struct cam_sensor_cci_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type, + uint32_t delay_ms) +{ + int32_t rc = -EINVAL; + int32_t i = 0; + + CAM_DBG(CAM_SENSOR, "addr: 0x%x data: 0x%x dt: %d", + addr, data, data_type); + + if (delay_ms > MAX_POLL_DELAY_MS) { + CAM_ERR(CAM_SENSOR, "invalid delay = %d max_delay = %d", + delay_ms, MAX_POLL_DELAY_MS); + return -EINVAL; + } + for (i = 0; i < delay_ms; i++) { + rc = cam_cci_i2c_compare(client, + addr, data, data_mask, data_type, addr_type); + if (!rc) + return rc; + + usleep_range(1000, 1010); + } + + /* If rc is 1 then read is successful but poll is failure */ + if (rc == 1) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d(non-fatal)", rc); + + if (rc < 0) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d", rc); + + return rc; +} + +int32_t cam_sensor_cci_i2c_util(struct cam_sensor_cci_client *cci_client, + uint16_t cci_cmd) +{ + int32_t rc = 0; + struct cam_cci_ctrl cci_ctrl; + + cci_ctrl.cmd = cci_cmd; + cci_ctrl.cci_info = cci_client; + rc = v4l2_subdev_call(cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed rc = %d", rc); + return rc; + } + return cci_ctrl.status; +} diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h new file mode 100644 index 000000000000..752b7fdd8a22 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_I2C_H_ +#define _CAM_SENSOR_I2C_H_ + +#include +#include +#include +#include "cam_cci_dev.h" +#include "cam_sensor_io.h" + +#define I2C_POLL_TIME_MS 5 +#define MAX_POLL_DELAY_MS 100 + +#define I2C_COMPARE_MATCH 0 +#define I2C_COMPARE_MISMATCH 1 + +#define I2C_REG_DATA_MAX (8*1024) + +/** + * @client: CCI client structure + * @data: I2C data + * @addr_type: I2c address type + * @data_type: I2C data type + * + * This API handles CCI read + */ +int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +/** + * @client: CCI client structure + * @addr: I2c address + * @data: I2C data + * @addr_type: I2c address type + * @data_type: I2c data type + * @num_byte: number of bytes + * + * This API handles CCI sequential read + */ +int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t num_byte); + +/** + * @client: CCI client structure + * @write_setting: I2C register setting + * + * This API handles CCI random write + */ +int32_t cam_cci_i2c_write_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting); + +/** + * @client: CCI client structure + * @write_setting: I2C register setting + * @cam_sensor_i2c_write_flag: burst or seq write + * + * This API handles CCI continuous write + */ +int32_t cam_cci_i2c_write_continuous_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag); + +/** + * @cci_client: CCI client structure + * @cci_cmd: CCI command type + * + * Does I2C call to I2C functionalities + */ +int32_t cam_sensor_cci_i2c_util(struct cam_sensor_cci_client *cci_client, + uint16_t cci_cmd); + +/** + * @client: CCI client structure + * @addr: I2C address + * @data: I2C data + * @data_mask: I2C data mask + * @data_type: I2C data type + * @addr_type: I2C addr type + * @delay_ms: Delay in milli seconds + * + * This API implements CCI based I2C poll + */ +int32_t cam_cci_i2c_poll(struct cam_sensor_cci_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type, + uint32_t delay_ms); + + +/** + * cam_qup_i2c_read : QUP based i2c read + * @client : QUP I2C client structure + * @data : I2C data + * @addr_type : I2c address type + * @data_type : I2C data type + * + * This API handles QUP I2C read + */ + +int32_t cam_qup_i2c_read(struct i2c_client *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +/** + * cam_qup_i2c_read_seq : QUP based I2C sequential read + * @client : QUP I2C client structure + * @data : I2C data + * @addr_type : I2c address type + * @num_bytes : number of bytes to read + * This API handles QUP I2C Sequential read + */ + +int32_t cam_qup_i2c_read_seq(struct i2c_client *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte); + +/** + * cam_qup_i2c_poll : QUP based I2C poll operation + * @client : QUP I2C client structure + * @addr : I2C address + * @data : I2C data + * @data_mask : I2C data mask + * @data_type : I2C data type + * @addr_type : I2C addr type + * @delay_ms : Delay in milli seconds + * + * This API implements QUP based I2C poll + */ + +int32_t cam_qup_i2c_poll(struct i2c_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms); + +/** + * cam_qup_i2c_write_table : QUP based I2C write random + * @client : QUP I2C client structure + * @write_setting : I2C register settings + * + * This API handles QUP I2C random write + */ + +int32_t cam_qup_i2c_write_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting); + +/** + * cam_qup_i2c_write_continuous_write: QUP based I2C write continuous(Burst/Seq) + * @client: QUP I2C client structure + * @write_setting: I2C register setting + * @cam_sensor_i2c_write_flag: burst or seq write + * + * This API handles QUP continuous write + */ +int32_t cam_qup_i2c_write_continuous_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag); + +#endif /*_CAM_SENSOR_I2C_H*/ diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c new file mode 100644 index 000000000000..108c47923eb7 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_io.h" +#include "cam_sensor_i2c.h" + +int32_t camera_io_dev_poll(struct camera_io_master *io_master_info, + uint32_t addr, uint16_t data, uint32_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms) +{ + int16_t mask = data_mask & 0xFF; + + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_poll(io_master_info->cci_client, + addr, data, mask, data_type, addr_type, delay_ms); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_poll(io_master_info->client, + addr, data, data_mask, addr_type, data_type, + delay_ms); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } +} + +int32_t camera_io_dev_erase(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t size) +{ + int rc = 0; + + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (size == 0) + return rc; + + if (io_master_info->master_type == SPI_MASTER) { + CAM_DBG(CAM_SENSOR, "Calling SPI Erase"); + return cam_spi_erase(io_master_info, addr, + CAMERA_SENSOR_I2C_TYPE_WORD, size); + } else if (io_master_info->master_type == I2C_MASTER || + io_master_info->master_type == CCI_MASTER) { + CAM_ERR(CAM_SENSOR, "Erase not supported on master :%d", + io_master_info->master_type); + rc = -EINVAL; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + rc = -EINVAL; + } + return rc; +} + +int32_t camera_io_dev_read(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_read(io_master_info->cci_client, + addr, data, addr_type, data_type); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_read(io_master_info->client, + addr, data, addr_type, data_type); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_read(io_master_info, + addr, data, addr_type, data_type); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } + return 0; +} + +int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, int32_t num_bytes) +{ + if (io_master_info->master_type == CCI_MASTER) { + return cam_camera_cci_i2c_read_seq(io_master_info->cci_client, + addr, data, addr_type, data_type, num_bytes); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_read_seq(io_master_info->client, + addr, data, addr_type, num_bytes); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_read_seq(io_master_info, + addr, data, addr_type, num_bytes); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_write_seq(io_master_info, + addr, data, addr_type, num_bytes); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } + return 0; +} + +int32_t camera_io_dev_write(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + if (!write_setting || !io_master_info) { + CAM_ERR(CAM_SENSOR, + "Input parameters not valid ws: %pK ioinfo: %pK", + write_setting, io_master_info); + return -EINVAL; + } + + if (!write_setting->reg_setting) { + CAM_ERR(CAM_SENSOR, "Invalid Register Settings"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_write_table(io_master_info, + write_setting); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_write_table(io_master_info, + write_setting); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_write_table(io_master_info, + write_setting); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } +} + +int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag) +{ + if (!write_setting || !io_master_info) { + CAM_ERR(CAM_SENSOR, + "Input parameters not valid ws: %pK ioinfo: %pK", + write_setting, io_master_info); + return -EINVAL; + } + + if (!write_setting->reg_setting) { + CAM_ERR(CAM_SENSOR, "Invalid Register Settings"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_write_continuous_table(io_master_info, + write_setting, cam_sensor_i2c_write_flag); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_write_continuous_table(io_master_info, + write_setting, cam_sensor_i2c_write_flag); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_write_table(io_master_info, + write_setting); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } +} + +int32_t camera_io_init(struct camera_io_master *io_master_info) +{ + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + io_master_info->cci_client->cci_subdev = + cam_cci_get_subdev(io_master_info->cci_client->cci_device); + return cam_sensor_cci_i2c_util(io_master_info->cci_client, + MSM_CCI_INIT); + } else if ((io_master_info->master_type == I2C_MASTER) || + (io_master_info->master_type == SPI_MASTER)) { + return 0; + } + + return -EINVAL; +} + +int32_t camera_io_release(struct camera_io_master *io_master_info) +{ + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_sensor_cci_i2c_util(io_master_info->cci_client, + MSM_CCI_RELEASE); + } else if ((io_master_info->master_type == I2C_MASTER) || + (io_master_info->master_type == SPI_MASTER)) { + return 0; + } + + return -EINVAL; +} diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h new file mode 100644 index 000000000000..3c49212d2d6f --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_IO_H_ +#define _CAM_SENSOR_IO_H_ + +#include + +#include "cam_sensor_cmn_header.h" + +#define CCI_MASTER 1 +#define I2C_MASTER 2 +#define SPI_MASTER 3 + +/** + * @master_type: CCI master type + * @client: I2C client information structure + * @cci_client: CCI client information structure + * @spi_client: SPI client information structure + */ +struct camera_io_master { + int master_type; + struct i2c_client *client; + struct cam_sensor_cci_client *cci_client; + struct cam_sensor_spi_client *spi_client; +}; + +/** + * @io_master_info: I2C/SPI master information + * @addr: I2C address + * @data: I2C data + * @addr_type: I2C addr_type + * @data_type: I2C data type + * + * This API abstracts read functionality based on master type + */ +int32_t camera_io_dev_read(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +/** + * @io_master_info: I2C/SPI master information + * @addr: I2C address + * @data: I2C data + * @addr_type: I2C addr type + * @data_type: I2C data type + * @num_bytes: number of bytes + * + * This API abstracts read functionality based on master type + */ +int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + int32_t num_bytes); + +/** + * @io_master_info: I2C/SPI master information + * + * This API initializes the I2C/SPI master based on master type + */ +int32_t camera_io_init(struct camera_io_master *io_master_info); + +/** + * @io_master_info: I2C/SPI master information + * + * This API releases the I2C/SPI master based on master type + */ +int32_t camera_io_release(struct camera_io_master *io_master_info); + +/** + * @io_master_info: I2C/SPI master information + * @write_setting: write settings information + * + * This API abstracts write functionality based on master type + */ +int32_t camera_io_dev_write(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting); + +/** + * @io_master_info: I2C/SPI master information + * @write_setting: write settings information + * @cam_sensor_i2c_write_flag: differentiate between burst & seq + * + * This API abstracts write functionality based on master type and + * write flag for continuous write + */ +int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag); + +int32_t camera_io_dev_erase(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t size); +/** + * @io_master_info: I2C/SPI master information + * @addr: I2C address + * @data: I2C data + * @data_mask: I2C data mask + * @data_type: I2C data type + * @addr_type: I2C address type + * @delay_ms: delay in milli seconds + * + * This API abstracts poll functionality based on master type + */ +int32_t camera_io_dev_poll(struct camera_io_master *io_master_info, + uint32_t addr, uint16_t data, uint32_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms); + +#include "cam_sensor_i2c.h" +#include "cam_sensor_spi.h" +#endif /* _CAM_SENSOR_IO_H_ */ diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c new file mode 100644 index 000000000000..a9fd0881aabf --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_cmn_header.h" +#include "cam_sensor_i2c.h" +#include "cam_sensor_io.h" + +#define I2C_REG_DATA_MAX (8*1024) +#define I2C_REG_MAX_BUF_SIZE 8 + +static int32_t cam_qup_i2c_rxdata( + struct i2c_client *dev_client, unsigned char *rxdata, + enum camera_sensor_i2c_type addr_type, + int data_length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->addr >> 1; + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = addr_type, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = data_length, + .buf = rxdata, + }, + }; + rc = i2c_transfer(dev_client->adapter, msgs, 2); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed 0x%x", saddr); + return rc; +} + + +static int32_t cam_qup_i2c_txdata( + struct camera_io_master *dev_client, unsigned char *txdata, + int length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msg, 1); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed 0x%x", saddr); + return rc; +} + +int32_t cam_qup_i2c_read(struct i2c_client *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int32_t rc = -EINVAL; + unsigned char *buf = NULL; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "Failed with addr/data_type verfication"); + return rc; + } + + buf = kzalloc(addr_type + data_type, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = addr >> 8; + buf[1] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = addr >> 16; + buf[1] = addr >> 8; + buf[2] = addr; + } else { + buf[0] = addr >> 24; + buf[1] = addr >> 16; + buf[2] = addr >> 8; + buf[3] = addr; + } + + rc = cam_qup_i2c_rxdata(client, buf, addr_type, data_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + goto read_fail; + } + + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + *data = buf[0]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) + *data = buf[0] << 8 | buf[1]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) + *data = buf[0] << 16 | buf[1] << 8 | buf[2]; + else + *data = buf[0] << 24 | buf[1] << 16 | + buf[2] << 8 | buf[3]; + + CAM_DBG(CAM_SENSOR, "addr = 0x%x data: 0x%x", addr, *data); +read_fail: + kfree(buf); + buf = NULL; + return rc; +} + +int32_t cam_qup_i2c_read_seq(struct i2c_client *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char *buf = NULL; + int i; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "Failed with addr_type verification"); + return rc; + } + + if ((num_byte == 0) || (num_byte > I2C_REG_DATA_MAX)) { + CAM_ERR(CAM_SENSOR, "num_byte:0x%x max supported:0x%x", + num_byte, I2C_REG_DATA_MAX); + return rc; + } + + buf = kzalloc(addr_type + num_byte, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = addr >> 16; + buf[1] = addr >> 8; + buf[2] = addr; + } else { + buf[0] = addr >> 24; + buf[1] = addr >> 16; + buf[2] = addr >> 8; + buf[3] = addr; + } + + rc = cam_qup_i2c_rxdata(client, buf, addr_type, num_byte); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + goto read_seq_fail; + } + + for (i = 0; i < num_byte; i++) + data[i] = buf[i]; + +read_seq_fail: + kfree(buf); + buf = NULL; + return rc; +} + +static int32_t cam_qup_i2c_compare(struct i2c_client *client, + uint32_t addr, uint32_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type) +{ + int32_t rc; + uint32_t reg_data = 0; + + rc = cam_qup_i2c_read(client, addr, ®_data, + addr_type, data_type); + if (rc < 0) + return rc; + + reg_data = reg_data & 0xFFFF; + if (data != (reg_data & ~data_mask)) + return I2C_COMPARE_MISMATCH; + + return I2C_COMPARE_MATCH; +} + +int32_t cam_qup_i2c_poll(struct i2c_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms) +{ + int32_t rc = 0; + int i = 0; + + if ((delay_ms > MAX_POLL_DELAY_MS) || (delay_ms == 0)) { + CAM_ERR(CAM_SENSOR, "invalid delay = %d max_delay = %d", + delay_ms, MAX_POLL_DELAY_MS); + return -EINVAL; + } + + if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) + return -EINVAL; + + for (i = 0; i < delay_ms; i++) { + rc = cam_qup_i2c_compare(client, + addr, data, data_mask, data_type, addr_type); + if (rc == I2C_COMPARE_MATCH) + return rc; + + usleep_range(1000, 1010); + } + /* If rc is MISMATCH then read is successful but poll is failure */ + if (rc == I2C_COMPARE_MISMATCH) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d(non-fatal)", rc); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d", rc); + + return rc; +} + +static int32_t cam_qup_i2c_write(struct camera_io_master *client, + struct cam_sensor_i2c_reg_array *reg_setting, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int32_t rc = 0; + unsigned char *buf = NULL; + uint8_t len = 0; + + buf = kzalloc(I2C_REG_MAX_BUF_SIZE, GFP_KERNEL | GFP_DMA); + if (!buf) { + CAM_ERR(CAM_SENSOR, "Buffer memory allocation failed"); + return -ENOMEM; + } + + CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d", + reg_setting->reg_addr, data_type); + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + len = 1; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = reg_setting->reg_addr >> 8; + buf[1] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len+1, buf[len+1]); + len = 2; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = reg_setting->reg_addr >> 16; + buf[1] = reg_setting->reg_addr >> 8; + buf[2] = reg_setting->reg_addr; + len = 3; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[0] = reg_setting->reg_addr >> 24; + buf[1] = reg_setting->reg_addr >> 16; + buf[2] = reg_setting->reg_addr >> 8; + buf[3] = reg_setting->reg_addr; + len = 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid I2C addr type"); + rc = -EINVAL; + goto deallocate_buffer; + } + + CAM_DBG(CAM_SENSOR, "Data: 0x%x", reg_setting->reg_data); + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[len] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + len += 1; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[len] = reg_setting->reg_data >> 8; + buf[len+1] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]); + len += 2; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[len] = reg_setting->reg_data >> 16; + buf[len + 1] = reg_setting->reg_data >> 8; + buf[len + 2] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+2, buf[len+2]); + len += 3; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[len] = reg_setting->reg_data >> 24; + buf[len + 1] = reg_setting->reg_data >> 16; + buf[len + 2] = reg_setting->reg_data >> 8; + buf[len + 3] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+2, buf[len+2]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+3, buf[len+3]); + len += 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Data Type"); + rc = -EINVAL; + goto deallocate_buffer; + } + + rc = cam_qup_i2c_txdata(client, buf, len); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + +deallocate_buffer: + kfree(buf); + return rc; +} + +int32_t cam_qup_i2c_write_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = -EINVAL; + struct cam_sensor_i2c_reg_array *reg_setting; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || (write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))) + return rc; + + reg_setting = write_setting->reg_setting; + + for (i = 0; i < write_setting->size; i++) { + CAM_DBG(CAM_SENSOR, "addr 0x%x data 0x%x", + reg_setting->reg_addr, reg_setting->reg_data); + + rc = cam_qup_i2c_write(client, reg_setting, + write_setting->addr_type, write_setting->data_type); + if (rc < 0) + break; + reg_setting++; + } + + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + +static int32_t cam_qup_i2c_write_seq(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = 0; + struct cam_sensor_i2c_reg_array *reg_setting; + + reg_setting = write_setting->reg_setting; + + for (i = 0; i < write_setting->size; i++) { + reg_setting->reg_addr += i; + rc = cam_qup_i2c_write(client, reg_setting, + write_setting->addr_type, write_setting->data_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Sequential i2c write failed: rc: %d", rc); + break; + } + reg_setting++; + } + + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + +static int32_t cam_qup_i2c_write_burst(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = 0; + uint32_t len = 0; + unsigned char *buf = NULL; + struct cam_sensor_i2c_reg_array *reg_setting; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + + buf = kzalloc((write_setting->addr_type + + (write_setting->size * write_setting->data_type)), + GFP_KERNEL); + + if (!buf) { + CAM_ERR(CAM_SENSOR, "BUF is NULL"); + return -ENOMEM; + } + + reg_setting = write_setting->reg_setting; + addr_type = write_setting->addr_type; + data_type = write_setting->data_type; + + CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d", + reg_setting->reg_addr, data_type); + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + len = 1; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = reg_setting->reg_addr >> 8; + buf[1] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len+1, buf[len+1]); + len = 2; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = reg_setting->reg_addr >> 16; + buf[1] = reg_setting->reg_addr >> 8; + buf[2] = reg_setting->reg_addr; + len = 3; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[0] = reg_setting->reg_addr >> 24; + buf[1] = reg_setting->reg_addr >> 16; + buf[2] = reg_setting->reg_addr >> 8; + buf[3] = reg_setting->reg_addr; + len = 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid I2C addr type"); + rc = -EINVAL; + goto free_res; + } + + for (i = 0; i < write_setting->size; i++) { + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[len] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + len += 1; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[len] = reg_setting->reg_data >> 8; + buf[len+1] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+1, buf[len+1]); + len += 2; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[len] = reg_setting->reg_data >> 16; + buf[len + 1] = reg_setting->reg_data >> 8; + buf[len + 2] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+2, buf[len+2]); + len += 3; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[len] = reg_setting->reg_data >> 24; + buf[len + 1] = reg_setting->reg_data >> 16; + buf[len + 2] = reg_setting->reg_data >> 8; + buf[len + 3] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+2, buf[len+2]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+3, buf[len+3]); + len += 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Data Type"); + rc = -EINVAL; + goto free_res; + } + reg_setting++; + } + + if (len > (write_setting->addr_type + + (write_setting->size * write_setting->data_type))) { + CAM_ERR(CAM_SENSOR, "Invalid Length: %u | Expected length: %u", + len, (write_setting->addr_type + + (write_setting->size * write_setting->data_type))); + rc = -EINVAL; + goto free_res; + } + + rc = cam_qup_i2c_txdata(client, buf, len); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + +free_res: + kfree(buf); + return rc; +} + +int32_t cam_qup_i2c_write_continuous_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_settings, + uint8_t cam_sensor_i2c_write_flag) +{ + int32_t rc = 0; + + if (!client || !write_settings) + return -EINVAL; + + if ((write_settings->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_settings->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || (write_settings->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_settings->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))) + return -EINVAL; + + if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_BURST) + rc = cam_qup_i2c_write_burst(client, write_settings); + else if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_SEQ) + rc = cam_qup_i2c_write_seq(client, write_settings); + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c new file mode 100644 index 000000000000..cf6987b09eac --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_sensor_spi.h" +#include "cam_debug_util.h" + +static int cam_spi_txfr(struct spi_device *spi, char *txbuf, + char *rxbuf, int num_byte) +{ + struct spi_transfer txfr; + struct spi_message msg; + + memset(&txfr, 0, sizeof(txfr)); + txfr.tx_buf = txbuf; + txfr.rx_buf = rxbuf; + txfr.len = num_byte; + spi_message_init(&msg); + spi_message_add_tail(&txfr, &msg); + + return spi_sync(spi, &msg); +} + +static int cam_spi_txfr_read(struct spi_device *spi, char *txbuf, + char *rxbuf, int txlen, int rxlen) +{ + struct spi_transfer tx; + struct spi_transfer rx; + struct spi_message m; + + memset(&tx, 0, sizeof(tx)); + memset(&rx, 0, sizeof(rx)); + tx.tx_buf = txbuf; + rx.rx_buf = rxbuf; + tx.len = txlen; + rx.len = rxlen; + spi_message_init(&m); + spi_message_add_tail(&tx, &m); + spi_message_add_tail(&rx, &m); + return spi_sync(spi, &m); +} + +/** + * cam_set_addr() - helper function to set transfer address + * @addr: device address + * @addr_len: the addr field length of an instruction + * @type: type (i.e. byte-length) of @addr + * @str: shifted address output, must be zeroed when passed in + * + * This helper function sets @str based on the addr field length of an + * instruction and the data length. + */ +static void cam_set_addr(uint32_t addr, uint8_t addr_len, + enum camera_sensor_i2c_type addr_type, + char *str) +{ + if (!addr_len) + return; + + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + str[0] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + str[0] = addr >> 8; + str[1] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + str[0] = addr >> 16; + str[1] = addr >> 8; + str[2] = addr; + } else { + str[0] = addr >> 24; + str[1] = addr >> 16; + str[2] = addr >> 8; + str[3] = addr; + } +} + +/** + * cam_spi_tx_helper() - wrapper for SPI transaction + * @client: io client + * @inst: inst of this transaction + * @addr: device addr following the inst + * @data: output byte array (could be NULL) + * @num_byte: size of @data + * @tx, rx: optional transfer buffer. It must be at least header + * + @num_byte long. + * + * This is the core function for SPI transaction, except for writes. It first + * checks address type, then allocates required memory for tx/rx buffers. + * It sends out , and optionally receives @num_byte of response, + * if @data is not NULL. This function does not check for wait conditions, + * and will return immediately once bus transaction finishes. + * + * This function will allocate buffers of header + @num_byte long. For + * large transfers, the allocation could fail. External buffer @tx, @rx + * should be passed in to bypass allocation. The size of buffer should be + * at least header + num_byte long. Since buffer is managed externally, + * @data will be ignored, and read results will be in @rx. + * @tx, @rx also can be used for repeated transfers to improve performance. + */ +static int32_t cam_spi_tx_helper(struct camera_io_master *client, + struct cam_camera_spi_inst *inst, uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte, char *tx, char *rx) +{ + int32_t rc = -EINVAL; + struct spi_device *spi = client->spi_client->spi_master; + struct device *dev = NULL; + char *ctx = NULL, *crx = NULL; + uint32_t len, hlen; + uint8_t retries = client->spi_client->retries; + uint32_t txr = 0, rxr = 0; + struct page *page_tx = NULL, *page_rx = NULL; + + hlen = cam_camera_spi_get_hlen(inst); + len = hlen + num_byte; + dev = &(spi->dev); + + if (!dev) { + CAM_ERR(CAM_SENSOR, "Invalid arguments"); + return -EINVAL; + } + + if (tx) { + ctx = tx; + } else { + txr = PAGE_ALIGN(len) >> PAGE_SHIFT; + page_tx = cma_alloc(dev_get_cma_area(dev), + txr, 0, GFP_KERNEL); + if (!page_tx) + return -ENOMEM; + + ctx = page_address(page_tx); + } + + if (num_byte) { + if (rx) { + crx = rx; + } else { + rxr = PAGE_ALIGN(len) >> PAGE_SHIFT; + page_rx = cma_alloc(dev_get_cma_area(dev), + rxr, 0, GFP_KERNEL); + if (!page_rx) { + if (!tx) + cma_release(dev_get_cma_area(dev), + page_tx, txr); + + return -ENOMEM; + } + crx = page_address(page_rx); + } + } else { + crx = NULL; + } + + ctx[0] = inst->opcode; + cam_set_addr(addr, inst->addr_len, addr_type, ctx + 1); + while ((rc = cam_spi_txfr(spi, ctx, crx, len)) && retries) { + retries--; + msleep(client->spi_client->retry_delay); + } + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: spi txfr rc %d", rc); + goto out; + } + if (data && num_byte && !rx) + memcpy(data, crx + hlen, num_byte); + +out: + if (!tx) + cma_release(dev_get_cma_area(dev), page_tx, txr); + if (!rx) + cma_release(dev_get_cma_area(dev), page_rx, rxr); + return rc; +} + +static int32_t cam_spi_tx_read(struct camera_io_master *client, + struct cam_camera_spi_inst *inst, uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte, char *tx, char *rx) +{ + int32_t rc = -EINVAL; + struct spi_device *spi = client->spi_client->spi_master; + char *ctx = NULL, *crx = NULL; + uint32_t hlen; + uint8_t retries = client->spi_client->retries; + + hlen = cam_camera_spi_get_hlen(inst); + if (tx) { + ctx = tx; + } else { + ctx = kzalloc(hlen, GFP_KERNEL | GFP_DMA); + if (!ctx) + return -ENOMEM; + } + if (num_byte) { + if (rx) { + crx = rx; + } else { + crx = kzalloc(num_byte, GFP_KERNEL | GFP_DMA); + if (!crx) { + if (!tx) + kfree(ctx); + return -ENOMEM; + } + } + } else { + crx = NULL; + } + + ctx[0] = inst->opcode; + cam_set_addr(addr, inst->addr_len, addr_type, ctx + 1); + + CAM_DBG(CAM_EEPROM, "tx(%u): %02x %02x %02x %02x", hlen, ctx[0], + ctx[1], ctx[2], ctx[3]); + while ((rc = cam_spi_txfr_read(spi, ctx, crx, hlen, num_byte)) + && retries) { + retries--; + msleep(client->spi_client->retry_delay); + } + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + goto out; + } + if (data && num_byte && !rx) + memcpy(data, crx, num_byte); +out: + if (!tx) + kfree(ctx); + if (!rx) + kfree(crx); + return rc; +} + +int cam_spi_read(struct camera_io_master *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int rc = -EINVAL; + uint8_t temp[CAMERA_SENSOR_I2C_TYPE_MAX]; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "Failed with addr/data_type verification"); + return rc; + } + + rc = cam_spi_tx_read(client, + &client->spi_client->cmd_tbl.read, addr, &temp[0], + addr_type, data_type, NULL, NULL); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + return rc; + } + + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + *data = temp[0]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) + *data = (temp[0] << BITS_PER_BYTE) | temp[1]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) + *data = (temp[0] << 16 | temp[1] << 8 | temp[2]); + else + *data = (temp[0] << 24 | temp[1] << 16 | temp[2] << 8 | + temp[3]); + + CAM_DBG(CAM_SENSOR, "addr 0x%x, data %u", addr, *data); + return rc; +} + +int32_t cam_spi_read_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, int32_t num_bytes) +{ + if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) { + CAM_ERR(CAM_SENSOR, "Failed with addr_type verification"); + return -EINVAL; + } + + if (num_bytes == 0) { + CAM_ERR(CAM_SENSOR, "num_byte: 0x%x", num_bytes); + return -EINVAL; + } + + CAM_DBG(CAM_SENSOR, "Read Seq addr: 0x%x NB:%d", + addr, num_bytes); + return cam_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read_seq, addr, data, + addr_type, num_bytes, NULL, NULL); +} + +int cam_spi_query_id(struct camera_io_master *client, + uint32_t addr, enum camera_sensor_i2c_type addr_type, + uint8_t *data, uint32_t num_byte) +{ + CAM_DBG(CAM_SENSOR, "SPI Queryid : 0x%x, addr: 0x%x", + client->spi_client->cmd_tbl.query_id, addr); + return cam_spi_tx_helper(client, + &client->spi_client->cmd_tbl.query_id, + addr, data, addr_type, num_byte, NULL, NULL); +} + +static int32_t cam_spi_read_status_reg( + struct camera_io_master *client, uint8_t *status, + enum camera_sensor_i2c_type addr_type) +{ + struct cam_camera_spi_inst *rs = + &client->spi_client->cmd_tbl.read_status; + + if (rs->addr_len != 0) { + CAM_ERR(CAM_SENSOR, "not implemented yet"); + return -ENXIO; + } + return cam_spi_tx_helper(client, rs, 0, status, + addr_type, 1, NULL, NULL); +} + +static int32_t cam_spi_device_busy(struct camera_io_master *client, + uint8_t *busy, enum camera_sensor_i2c_type addr_type) +{ + int rc; + uint8_t st = 0; + + rc = cam_spi_read_status_reg(client, &st, addr_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed to read status reg"); + return rc; + } + *busy = st & client->spi_client->busy_mask; + return 0; +} + +static int32_t cam_spi_wait(struct camera_io_master *client, + struct cam_camera_spi_inst *inst, + enum camera_sensor_i2c_type addr_type) +{ + uint8_t busy; + int i, rc; + + CAM_DBG(CAM_SENSOR, "op 0x%x wait start", inst->opcode); + for (i = 0; i < inst->delay_count; i++) { + rc = cam_spi_device_busy(client, &busy, addr_type); + if (rc < 0) + return rc; + if (!busy) + break; + msleep(inst->delay_intv); + CAM_DBG(CAM_SENSOR, "op 0x%x wait", inst->opcode); + } + if (i > inst->delay_count) { + CAM_ERR(CAM_SENSOR, "op %x timed out", inst->opcode); + return -ETIMEDOUT; + } + CAM_DBG(CAM_SENSOR, "op %x finished", inst->opcode); + return 0; +} + +static int32_t cam_spi_write_enable(struct camera_io_master *client, + enum camera_sensor_i2c_type addr_type) +{ + struct cam_camera_spi_inst *we = + &client->spi_client->cmd_tbl.write_enable; + int rc; + + if (we->opcode == 0) + return 0; + if (we->addr_len != 0) { + CAM_ERR(CAM_SENSOR, "not implemented yet"); + return -EINVAL; + } + rc = cam_spi_tx_helper(client, we, 0, NULL, addr_type, + 0, NULL, NULL); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "write enable failed"); + return rc; +} + +/** + * cam_spi_page_program() - core function to perform write + * @client: need for obtaining SPI device + * @addr: address to program on device + * @data: data to write + * @len: size of data + * @tx: tx buffer, size >= header + len + * + * This function performs SPI write, and has no boundary check. Writing range + * should not cross page boundary, or data will be corrupted. Transaction is + * guaranteed to be finished when it returns. This function should never be + * used outside cam_spi_write_seq(). + */ +static int32_t cam_spi_page_program(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint16_t len, uint8_t *tx) +{ + int rc; + struct cam_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + struct spi_device *spi = client->spi_client->spi_master; + uint8_t retries = client->spi_client->retries; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + + CAM_DBG(CAM_SENSOR, "addr 0x%x, size 0x%x", addr, len); + rc = cam_spi_write_enable(client, addr_type); + if (rc < 0) + return rc; + memset(tx, 0, header_len); + tx[0] = pg->opcode; + cam_set_addr(addr, pg->addr_len, addr_type, tx + 1); + memcpy(tx + header_len, data, len); + CAM_DBG(CAM_SENSOR, "tx(%u): %02x %02x %02x %02x", + len, tx[0], tx[1], tx[2], tx[3]); + while ((rc = spi_write(spi, tx, len + header_len)) && retries) { + rc = cam_spi_wait(client, pg, addr_type); + msleep(client->spi_client->retry_delay); + retries--; + } + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + return rc; + } + rc = cam_spi_wait(client, pg, addr_type); + return rc; +} + +int cam_spi_write(struct camera_io_master *client, + uint32_t addr, uint32_t data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + struct cam_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + uint16_t len = 0; + char buf[CAMERA_SENSOR_I2C_TYPE_MAX]; + char *tx; + int rc = -EINVAL; + + if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (data_type != CAMERA_SENSOR_I2C_TYPE_MAX)) + return rc; + + CAM_DBG(CAM_EEPROM, "Data: 0x%x", data); + len = header_len + (uint8_t)data_type; + tx = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!tx) + goto NOMEM; + + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = data; + CAM_DBG(CAM_EEPROM, "Byte %d: 0x%x", len, buf[0]); + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = (data >> BITS_PER_BYTE) & 0x00FF; + buf[1] = (data & 0x00FF); + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = (data >> 16) & 0x00FF; + buf[1] = (data >> 8) & 0x00FF; + buf[2] = (data & 0x00FF); + } else { + buf[0] = (data >> 24) & 0x00FF; + buf[1] = (data >> 16) & 0x00FF; + buf[2] = (data >> 8) & 0x00FF; + buf[3] = (data & 0x00FF); + } + + rc = cam_spi_page_program(client, addr, buf, + addr_type, data_type, tx); + if (rc < 0) + goto ERROR; + goto OUT; +NOMEM: + CAM_ERR(CAM_SENSOR, "memory allocation failed"); + return -ENOMEM; +ERROR: + CAM_ERR(CAM_SENSOR, "error write"); +OUT: + kfree(tx); + return rc; +} + +int32_t cam_spi_write_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, uint32_t num_byte) +{ + struct cam_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + const uint32_t page_size = client->spi_client->page_size; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + uint16_t len; + uint32_t cur_len, end; + char *tx, *pdata = data; + int rc = -EINVAL; + + if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) || + (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)) + return rc; + /* single page write */ + if ((addr % page_size) + num_byte <= page_size) { + len = header_len + num_byte; + tx = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!tx) + goto NOMEM; + rc = cam_spi_page_program(client, addr, data, addr_type, + num_byte, tx); + if (rc < 0) + goto ERROR; + goto OUT; + } + /* multi page write */ + len = header_len + page_size; + tx = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!tx) + goto NOMEM; + while (num_byte) { + end = min(page_size, (addr % page_size) + num_byte); + cur_len = end - (addr % page_size); + CAM_ERR(CAM_SENSOR, "Addr: 0x%x curr_len: 0x%x pgSize: %d", + addr, cur_len, page_size); + rc = cam_spi_page_program(client, addr, pdata, addr_type, + cur_len, tx); + if (rc < 0) + goto ERROR; + addr += cur_len; + pdata += cur_len; + num_byte -= cur_len; + } + goto OUT; +NOMEM: + pr_err("%s: memory allocation failed\n", __func__); + return -ENOMEM; +ERROR: + pr_err("%s: error write\n", __func__); +OUT: + kfree(tx); + return rc; +} + +int cam_spi_write_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int rc = -EFAULT; + struct cam_sensor_i2c_reg_array *reg_setting; + uint16_t client_addr_type; + enum camera_sensor_i2c_type addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) + return rc; + + reg_setting = write_setting->reg_setting; + client_addr_type = write_setting->addr_type; + addr_type = write_setting->addr_type; + for (i = 0; i < write_setting->size; i++) { + CAM_DBG(CAM_SENSOR, "addr %x data %x", + reg_setting->reg_addr, reg_setting->reg_data); + rc = cam_spi_write(client, + reg_setting->reg_addr, reg_setting->reg_data, + write_setting->addr_type, write_setting->data_type); + if (rc < 0) + break; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, + (write_setting->delay + * 1000) + 1000); + addr_type = client_addr_type; + return rc; +} + +int cam_spi_erase(struct camera_io_master *client, uint32_t addr, + enum camera_sensor_i2c_type addr_type, uint32_t size) +{ + struct cam_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase; + int rc = 0; + uint32_t cur; + uint32_t end = addr + size; + uint32_t erase_size = client->spi_client->erase_size; + + end = addr + size; + for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) { + CAM_ERR(CAM_SENSOR, "%s: erasing 0x%x size: %d\n", + __func__, cur, erase_size); + rc = cam_spi_write_enable(client, addr_type); + if (rc < 0) + return rc; + rc = cam_spi_tx_helper(client, se, cur, NULL, addr_type, 0, + NULL, NULL); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "%s: erase failed\n", __func__); + return rc; + } + rc = cam_spi_wait(client, se, addr_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "%s: erase timedout\n", __func__); + return rc; + } + } + + return rc; +} diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h new file mode 100644 index 000000000000..7a9c44332c49 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_SPI_H_ +#define _CAM_SENSOR_SPI_H_ + +#include +#include +#include +#include "cam_sensor_i2c.h" + +#define MAX_SPI_SIZE 110 +#define SPI_DYNAMIC_ALLOC + +struct cam_camera_spi_inst { + uint8_t opcode; + uint8_t addr_len; + uint8_t dummy_len; + uint8_t delay_intv; + uint8_t delay_count; +}; + +struct cam_spi_write_burst_data { + u8 data_msb; + u8 data_lsb; +}; + +struct cam_spi_write_burst_packet { + u8 cmd; + u8 addr_msb; + u8 addr_lsb; + struct cam_spi_write_burst_data data_arr[MAX_SPI_SIZE]; +}; + +struct cam_camera_burst_info { + uint32_t burst_addr; + uint32_t burst_start; + uint32_t burst_len; + uint32_t chunk_size; +}; + +struct cam_camera_spi_inst_tbl { + struct cam_camera_spi_inst read; + struct cam_camera_spi_inst read_seq; + struct cam_camera_spi_inst query_id; + struct cam_camera_spi_inst page_program; + struct cam_camera_spi_inst write_enable; + struct cam_camera_spi_inst read_status; + struct cam_camera_spi_inst erase; +}; + +struct cam_sensor_spi_client { + struct spi_device *spi_master; + struct cam_camera_spi_inst_tbl cmd_tbl; + uint8_t device_id0; + uint8_t device_id1; + uint8_t mfr_id0; + uint8_t mfr_id1; + uint8_t retry_delay; + uint8_t retries; + uint8_t busy_mask; + uint16_t page_size; + uint32_t erase_size; +}; +static __always_inline +uint16_t cam_camera_spi_get_hlen(struct cam_camera_spi_inst *inst) +{ + return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len; +} + +int cam_spi_read(struct camera_io_master *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +int cam_spi_read_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + int32_t num_bytes); + +int cam_spi_query_id(struct camera_io_master *client, + uint32_t addr, + enum camera_sensor_i2c_type addr_type, + uint8_t *data, uint32_t num_byte); + +int cam_spi_write(struct camera_io_master *client, + uint32_t addr, uint32_t data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +int cam_spi_write_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting); + +int cam_spi_erase(struct camera_io_master *client, + uint32_t addr, enum camera_sensor_i2c_type addr_type, + uint32_t size); + +int cam_spi_write_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, uint32_t num_byte); +#endif diff --git a/drivers/cam_sensor_module/cam_sensor_utils/Makefile b/drivers/cam_sensor_module/cam_sensor_utils/Makefile new file mode 100644 index 000000000000..4813d33a5bc5 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_utils/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_util.o diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h new file mode 100644 index 000000000000..a5699342dce0 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -0,0 +1,396 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_CMN_HEADER_ +#define _CAM_SENSOR_CMN_HEADER_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_REGULATOR 5 +#define MAX_POWER_CONFIG 12 + +#define MAX_PER_FRAME_ARRAY 32 +#define BATCH_SIZE_MAX 16 + +#define CAM_SENSOR_NAME "cam-sensor" +#define CAM_ACTUATOR_NAME "cam-actuator" +#define CAM_CSIPHY_NAME "cam-csiphy" +#define CAM_FLASH_NAME "cam-flash" +#define CAM_EEPROM_NAME "cam-eeprom" +#define CAM_OIS_NAME "cam-ois" + +#define MAX_SYSTEM_PIPELINE_DELAY 2 + +#define CAM_PKT_NOP_OPCODE 127 + +enum camera_sensor_cmd_type { + CAMERA_SENSOR_CMD_TYPE_INVALID, + CAMERA_SENSOR_CMD_TYPE_PROBE, + CAMERA_SENSOR_CMD_TYPE_PWR_UP, + CAMERA_SENSOR_CMD_TYPE_PWR_DOWN, + CAMERA_SENSOR_CMD_TYPE_I2C_INFO, + CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR, + CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_RD, + CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR, + CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD, + CAMERA_SENSOR_CMD_TYPE_WAIT, + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO, + CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE, + CAMERA_SENSOR_FLASH_CMD_TYPE_RER, + CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR, + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET, + CAMERA_SENSOR_CMD_TYPE_RD_DATA, + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE, + CAMERA_SENSOR_CMD_TYPE_MAX, +}; + +enum camera_sensor_i2c_op_code { + CAMERA_SENSOR_I2C_OP_INVALID, + CAMERA_SENSOR_I2C_OP_RNDM_WR, + CAMERA_SENSOR_I2C_OP_RNDM_WR_VERF, + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST, + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST_VERF, + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN, + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN_VERF, + CAMERA_SENSOR_I2C_OP_MAX, +}; + +enum camera_sensor_wait_op_code { + CAMERA_SENSOR_WAIT_OP_INVALID, + CAMERA_SENSOR_WAIT_OP_COND, + CAMERA_SENSOR_WAIT_OP_HW_UCND, + CAMERA_SENSOR_WAIT_OP_SW_UCND, + CAMERA_SENSOR_WAIT_OP_MAX, +}; + +enum camera_flash_opcode { + CAMERA_SENSOR_FLASH_OP_INVALID, + CAMERA_SENSOR_FLASH_OP_OFF, + CAMERA_SENSOR_FLASH_OP_FIRELOW, + CAMERA_SENSOR_FLASH_OP_FIREHIGH, + CAMERA_SENSOR_FLASH_OP_MAX, +}; + +enum camera_sensor_i2c_type { + CAMERA_SENSOR_I2C_TYPE_INVALID, + CAMERA_SENSOR_I2C_TYPE_BYTE, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_3B, + CAMERA_SENSOR_I2C_TYPE_DWORD, + CAMERA_SENSOR_I2C_TYPE_MAX, +}; + +enum i2c_freq_mode { + I2C_STANDARD_MODE, + I2C_FAST_MODE, + I2C_CUSTOM_MODE, + I2C_FAST_PLUS_MODE, + I2C_MAX_MODES, +}; + +enum position_roll { + ROLL_0 = 0, + ROLL_90 = 90, + ROLL_180 = 180, + ROLL_270 = 270, + ROLL_INVALID = 360, +}; + +enum position_yaw { + FRONT_CAMERA_YAW = 0, + REAR_CAMERA_YAW = 180, + INVALID_YAW = 360, +}; + +enum position_pitch { + LEVEL_PITCH = 0, + INVALID_PITCH = 360, +}; + +enum sensor_sub_module { + SUB_MODULE_SENSOR, + SUB_MODULE_ACTUATOR, + SUB_MODULE_EEPROM, + SUB_MODULE_LED_FLASH, + SUB_MODULE_CSID, + SUB_MODULE_CSIPHY, + SUB_MODULE_OIS, + SUB_MODULE_EXT, + SUB_MODULE_MAX, +}; + +enum msm_camera_power_seq_type { + SENSOR_MCLK, + SENSOR_VANA, + SENSOR_VDIG, + SENSOR_VIO, + SENSOR_VAF, + SENSOR_VAF_PWDM, + SENSOR_CUSTOM_REG1, + SENSOR_CUSTOM_REG2, + SENSOR_RESET, + SENSOR_STANDBY, + SENSOR_CUSTOM_GPIO1, + SENSOR_CUSTOM_GPIO2, + SENSOR_SEQ_TYPE_MAX, +}; + +enum cam_sensor_packet_opcodes { + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON, + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE, + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG, + CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE, + CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF, + CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP = 127 +}; + +enum cam_actuator_packet_opcodes { + CAM_ACTUATOR_PACKET_OPCODE_INIT, + CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS, + CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS +}; + +enum cam_eeprom_packet_opcodes { + CAM_EEPROM_PACKET_OPCODE_INIT, + CAM_EEPROM_WRITE +}; + +enum cam_ois_packet_opcodes { + CAM_OIS_PACKET_OPCODE_INIT, + CAM_OIS_PACKET_OPCODE_OIS_CONTROL +}; + +enum msm_bus_perf_setting { + S_INIT, + S_PREVIEW, + S_VIDEO, + S_CAPTURE, + S_ZSL, + S_STEREO_VIDEO, + S_STEREO_CAPTURE, + S_DEFAULT, + S_LIVESHOT, + S_DUAL, + S_EXIT +}; + +enum msm_camera_device_type_t { + MSM_CAMERA_I2C_DEVICE, + MSM_CAMERA_PLATFORM_DEVICE, + MSM_CAMERA_SPI_DEVICE, +}; + +enum cam_flash_device_type { + CAMERA_FLASH_DEVICE_TYPE_PMIC = 0, + CAMERA_FLASH_DEVICE_TYPE_I2C, + CAMERA_FLASH_DEVICE_TYPE_GPIO, +}; + +enum cci_i2c_master_t { + MASTER_0, + MASTER_1, + MASTER_MAX, +}; + +enum cci_device_num { + CCI_DEVICE_0, + CCI_DEVICE_1, + CCI_DEVICE_MAX, +}; + +enum camera_vreg_type { + VREG_TYPE_DEFAULT, + VREG_TYPE_CUSTOM, +}; + +enum cam_sensor_i2c_cmd_type { + CAM_SENSOR_I2C_WRITE_RANDOM, + CAM_SENSOR_I2C_WRITE_BURST, + CAM_SENSOR_I2C_WRITE_SEQ, + CAM_SENSOR_I2C_READ, + CAM_SENSOR_I2C_POLL +}; + +struct common_header { + uint32_t first_word; + uint8_t fifth_byte; + uint8_t cmd_type; + uint16_t reserved; +}; + +struct camera_vreg_t { + const char *reg_name; + int min_voltage; + int max_voltage; + int op_mode; + uint32_t delay; + const char *custom_vreg_name; + enum camera_vreg_type type; +}; + +struct msm_camera_gpio_num_info { + uint16_t gpio_num[SENSOR_SEQ_TYPE_MAX]; + uint8_t valid[SENSOR_SEQ_TYPE_MAX]; +}; + +struct msm_cam_clk_info { + const char *clk_name; + long clk_rate; + uint32_t delay; +}; + +struct msm_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + bool use_pinctrl; +}; + +struct cam_sensor_i2c_reg_array { + uint32_t reg_addr; + uint32_t reg_data; + uint32_t delay; + uint32_t data_mask; +}; + +struct cam_sensor_i2c_reg_setting { + struct cam_sensor_i2c_reg_array *reg_setting; + uint32_t size; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + unsigned short delay; +}; + +struct cam_sensor_i2c_seq_reg { + uint32_t reg_addr; + uint8_t *reg_data; + uint32_t size; + enum camera_sensor_i2c_type addr_type; +}; + +struct i2c_settings_list { + struct cam_sensor_i2c_reg_setting i2c_settings; + struct cam_sensor_i2c_seq_reg seq_settings; + enum cam_sensor_i2c_cmd_type op_code; + struct list_head list; +}; + +struct i2c_settings_array { + struct list_head list_head; + int32_t is_settings_valid; + int64_t request_id; +}; + +struct i2c_data_settings { + struct i2c_settings_array init_settings; + struct i2c_settings_array config_settings; + struct i2c_settings_array streamon_settings; + struct i2c_settings_array streamoff_settings; + struct i2c_settings_array *per_frame; +}; + +struct cam_sensor_power_ctrl_t { + struct device *dev; + struct cam_sensor_power_setting *power_setting; + uint16_t power_setting_size; + struct cam_sensor_power_setting *power_down_setting; + uint16_t power_down_setting_size; + struct msm_camera_gpio_num_info *gpio_num_info; + struct msm_pinctrl_info pinctrl_info; + uint8_t cam_pinctrl_status; +}; + +struct cam_camera_slave_info { + uint16_t sensor_slave_addr; + uint16_t sensor_id_reg_addr; + uint16_t sensor_id; + uint16_t sensor_id_mask; +}; + +struct msm_sensor_init_params { + int modes_supported; + unsigned int sensor_mount_angle; +}; + +enum msm_sensor_camera_id_t { + CAMERA_0, + CAMERA_1, + CAMERA_2, + CAMERA_3, + CAMERA_4, + CAMERA_5, + CAMERA_6, + MAX_CAMERAS, +}; + +struct msm_sensor_id_info_t { + unsigned short sensor_id_reg_addr; + unsigned short sensor_id; + unsigned short sensor_id_mask; +}; + +enum msm_sensor_output_format_t { + MSM_SENSOR_BAYER, + MSM_SENSOR_YCBCR, + MSM_SENSOR_META, +}; + +struct cam_sensor_power_setting { + enum msm_camera_power_seq_type seq_type; + unsigned short seq_val; + long config_val; + unsigned short delay; + void *data[10]; +}; + +struct cam_sensor_board_info { + struct cam_camera_slave_info slave_info; + int32_t sensor_mount_angle; + int32_t secure_mode; + int modes_supported; + int32_t pos_roll; + int32_t pos_yaw; + int32_t pos_pitch; + int32_t subdev_id[SUB_MODULE_MAX]; + int32_t subdev_intf[SUB_MODULE_MAX]; + const char *misc_regulator; + struct cam_sensor_power_ctrl_t power_info; +}; + +enum msm_camera_vreg_name_t { + CAM_VDIG, + CAM_VIO, + CAM_VANA, + CAM_VAF, + CAM_V_CUSTOM1, + CAM_V_CUSTOM2, + CAM_VREG_MAX, +}; + +struct msm_camera_gpio_conf { + void *cam_gpiomux_conf_tbl; + uint8_t cam_gpiomux_conf_tbl_size; + struct gpio *cam_gpio_common_tbl; + uint8_t cam_gpio_common_tbl_size; + struct gpio *cam_gpio_req_tbl; + uint8_t cam_gpio_req_tbl_size; + uint32_t gpio_no_mux; + uint32_t *camera_off_table; + uint8_t camera_off_table_size; + uint32_t *camera_on_table; + uint8_t camera_on_table_size; + struct msm_camera_gpio_num_info *gpio_num_info; +}; + +#endif /* _CAM_SENSOR_CMN_HEADER_ */ diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c new file mode 100644 index 000000000000..4a2a2a8855b2 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -0,0 +1,2057 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_sensor_util.h" +#include +#include "cam_res_mgr_api.h" + +#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" +#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default" + +#define VALIDATE_VOLTAGE(min, max, config_val) ((config_val) && \ + (config_val >= min) && (config_val <= max)) + +static struct i2c_settings_list* + cam_sensor_get_i2c_ptr(struct i2c_settings_array *i2c_reg_settings, + uint32_t size) +{ + struct i2c_settings_list *tmp; + + tmp = kzalloc(sizeof(struct i2c_settings_list), GFP_KERNEL); + + if (tmp != NULL) + list_add_tail(&(tmp->list), + &(i2c_reg_settings->list_head)); + else + return NULL; + + tmp->i2c_settings.reg_setting = (struct cam_sensor_i2c_reg_array *) + vzalloc(size * sizeof(struct cam_sensor_i2c_reg_array)); + if (tmp->i2c_settings.reg_setting == NULL) { + list_del(&(tmp->list)); + kfree(tmp); + return NULL; + } + tmp->i2c_settings.size = size; + + return tmp; +} + +int32_t delete_request(struct i2c_settings_array *i2c_array) +{ + struct i2c_settings_list *i2c_list = NULL, *i2c_next = NULL; + int32_t rc = 0; + + if (i2c_array == NULL) { + CAM_ERR(CAM_SENSOR, "FATAL:: Invalid argument"); + return -EINVAL; + } + + list_for_each_entry_safe(i2c_list, i2c_next, + &(i2c_array->list_head), list) { + vfree(i2c_list->i2c_settings.reg_setting); + list_del(&(i2c_list->list)); + kfree(i2c_list); + } + INIT_LIST_HEAD(&(i2c_array->list_head)); + i2c_array->is_settings_valid = 0; + + return rc; +} + +int32_t cam_sensor_handle_delay( + uint32_t **cmd_buf, + uint16_t generic_op_code, + struct i2c_settings_array *i2c_reg_settings, + uint32_t offset, uint32_t *byte_cnt, + struct list_head *list_ptr) +{ + int32_t rc = 0; + struct cam_cmd_unconditional_wait *cmd_uncond_wait = + (struct cam_cmd_unconditional_wait *) *cmd_buf; + struct i2c_settings_list *i2c_list = NULL; + + if (list_ptr == NULL) { + CAM_ERR(CAM_SENSOR, "Invalid list ptr"); + return -EINVAL; + } + + if (offset > 0) { + i2c_list = + list_entry(list_ptr, struct i2c_settings_list, list); + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND) + i2c_list->i2c_settings.reg_setting[offset - 1].delay = + cmd_uncond_wait->delay; + else + i2c_list->i2c_settings.delay = cmd_uncond_wait->delay; + (*cmd_buf) += + sizeof( + struct cam_cmd_unconditional_wait) / sizeof(uint32_t); + (*byte_cnt) += + sizeof( + struct cam_cmd_unconditional_wait); + } else { + CAM_ERR(CAM_SENSOR, "Delay Rxed Before any buffer: %d", offset); + return -EINVAL; + } + + return rc; +} + +int32_t cam_sensor_handle_poll( + uint32_t **cmd_buf, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *byte_cnt, int32_t *offset, + struct list_head **list_ptr) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0; + struct cam_cmd_conditional_wait *cond_wait + = (struct cam_cmd_conditional_wait *) *cmd_buf; + + i2c_list = + cam_sensor_get_i2c_ptr(i2c_reg_settings, 1); + if (!i2c_list || !i2c_list->i2c_settings.reg_setting) { + CAM_ERR(CAM_SENSOR, "Failed in allocating mem for list"); + return -ENOMEM; + } + + i2c_list->op_code = CAM_SENSOR_I2C_POLL; + i2c_list->i2c_settings.data_type = + cond_wait->data_type; + i2c_list->i2c_settings.addr_type = + cond_wait->addr_type; + i2c_list->i2c_settings.reg_setting->reg_addr = + cond_wait->reg_addr; + i2c_list->i2c_settings.reg_setting->reg_data = + cond_wait->reg_data; + i2c_list->i2c_settings.reg_setting->delay = + cond_wait->timeout; + + (*cmd_buf) += sizeof(struct cam_cmd_conditional_wait) / + sizeof(uint32_t); + (*byte_cnt) += sizeof(struct cam_cmd_conditional_wait); + + *offset = 1; + *list_ptr = &(i2c_list->list); + + return rc; +} + +int32_t cam_sensor_handle_random_write( + struct cam_cmd_i2c_random_wr *cam_cmd_i2c_random_wr, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, + cam_cmd_i2c_random_wr->header.count); + if (i2c_list == NULL || + i2c_list->i2c_settings.reg_setting == NULL) { + CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); + return -ENOMEM; + } + + *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + + sizeof(struct i2c_random_wr_payload) * + (cam_cmd_i2c_random_wr->header.count)); + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_RANDOM; + i2c_list->i2c_settings.addr_type = + cam_cmd_i2c_random_wr->header.addr_type; + i2c_list->i2c_settings.data_type = + cam_cmd_i2c_random_wr->header.data_type; + + for (cnt = 0; cnt < (cam_cmd_i2c_random_wr->header.count); + cnt++) { + i2c_list->i2c_settings.reg_setting[cnt].reg_addr = + cam_cmd_i2c_random_wr->random_wr_payload[cnt].reg_addr; + i2c_list->i2c_settings.reg_setting[cnt].reg_data = + cam_cmd_i2c_random_wr->random_wr_payload[cnt].reg_data; + i2c_list->i2c_settings.reg_setting[cnt].data_mask = 0; + } + *offset = cnt; + *list = &(i2c_list->list); + + return rc; +} + +static int32_t cam_sensor_handle_continuous_write( + struct cam_cmd_i2c_continuous_wr *cam_cmd_i2c_continuous_wr, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, + cam_cmd_i2c_continuous_wr->header.count); + if (i2c_list == NULL || + i2c_list->i2c_settings.reg_setting == NULL) { + CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); + return -ENOMEM; + } + + *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + sizeof(struct cam_cmd_read) * + (cam_cmd_i2c_continuous_wr->header.count)); + if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_BURST; + else if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_SEQ; + else + return -EINVAL; + + i2c_list->i2c_settings.addr_type = + cam_cmd_i2c_continuous_wr->header.addr_type; + i2c_list->i2c_settings.data_type = + cam_cmd_i2c_continuous_wr->header.data_type; + i2c_list->i2c_settings.size = + cam_cmd_i2c_continuous_wr->header.count; + + for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count); + cnt++) { + i2c_list->i2c_settings.reg_setting[cnt].reg_addr = + cam_cmd_i2c_continuous_wr->reg_addr; + i2c_list->i2c_settings.reg_setting[cnt].reg_data = + cam_cmd_i2c_continuous_wr->data_read[cnt].reg_data; + i2c_list->i2c_settings.reg_setting[cnt].data_mask = 0; + } + *offset = cnt; + *list = &(i2c_list->list); + + return rc; +} + +static int cam_sensor_handle_slave_info( + struct camera_io_master *io_master, + uint32_t *cmd_buf) +{ + int rc = 0; + struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + + if (io_master == NULL || cmd_buf == NULL) { + CAM_ERR(CAM_SENSOR, "Invalid args"); + return -EINVAL; + } + + switch (io_master->master_type) { + case CCI_MASTER: + io_master->cci_client->sid = (i2c_info->slave_addr >> 1); + io_master->cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + break; + + case I2C_MASTER: + io_master->client->addr = i2c_info->slave_addr; + break; + + case SPI_MASTER: + break; + + default: + CAM_ERR(CAM_SENSOR, "Invalid master type: %d", + io_master->master_type); + rc = -EINVAL; + break; + } + + return rc; +} + +/** + * Name : cam_sensor_i2c_command_parser + * Description : Parse CSL CCI packet and apply register settings + * Parameters : s_ctrl input/output sub_device + * arg input cam_control + * Description : + * Handle multiple I2C RD/WR and WAIT cmd formats in one command + * buffer, for example, a command buffer of m x RND_WR + 1 x HW_ + * WAIT + n x RND_WR with num_cmd_buf = 1. Do not exepect RD/WR + * with different cmd_type and op_code in one command buffer. + */ +int cam_sensor_i2c_command_parser( + struct camera_io_master *io_master, + struct i2c_settings_array *i2c_reg_settings, + struct cam_cmd_buf_desc *cmd_desc, + int32_t num_cmd_buffers) +{ + int16_t rc = 0, i = 0; + size_t len_of_buff = 0; + uintptr_t generic_ptr; + uint16_t cmd_length_in_bytes = 0; + size_t remain_len = 0; + size_t tot_size = 0; + + for (i = 0; i < num_cmd_buffers; i++) { + uint32_t *cmd_buf = NULL; + struct common_header *cmm_hdr; + uint16_t generic_op_code; + uint32_t byte_cnt = 0; + uint32_t j = 0; + struct list_head *list = NULL; + + /* + * It is not expected the same settings to + * be spread across multiple cmd buffers + */ + CAM_DBG(CAM_SENSOR, "Total cmd Buf in Bytes: %d", + cmd_desc[i].length); + + if (!cmd_desc[i].length) + continue; + + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cmd hdl failed:%d, Err: %d, Buffer_len: %zd", + cmd_desc[i].mem_handle, rc, len_of_buff); + return rc; + } + + remain_len = len_of_buff; + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buff - sizeof(struct common_header)))) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + cmd_buf = (uint32_t *)generic_ptr; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + remain_len -= cmd_desc[i].offset; + if (remain_len < cmd_desc[i].length) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + + while (byte_cnt < cmd_desc[i].length) { + if ((remain_len - byte_cnt) < + sizeof(struct common_header)) { + CAM_ERR(CAM_SENSOR, "Not enough buffer"); + rc = -EINVAL; + goto end; + } + cmm_hdr = (struct common_header *)cmd_buf; + generic_op_code = cmm_hdr->fifth_byte; + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: { + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_random_wr + *cam_cmd_i2c_random_wr = + (struct cam_cmd_i2c_random_wr *)cmd_buf; + + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_random_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + tot_size = sizeof(struct i2c_rdwr_header) + + (sizeof(struct i2c_random_wr_payload) * + cam_cmd_i2c_random_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_random_write( + cam_cmd_i2c_random_wr, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in random write %d", rc); + rc = -EINVAL; + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR: { + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_continuous_wr + *cam_cmd_i2c_continuous_wr = + (struct cam_cmd_i2c_continuous_wr *) + cmd_buf; + + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_continuous_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + + tot_size = sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + (sizeof(struct cam_cmd_read) * + cam_cmd_i2c_continuous_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_continuous_write( + cam_cmd_i2c_continuous_wr, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in continuous write %d", rc); + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + case CAMERA_SENSOR_CMD_TYPE_WAIT: { + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_unconditional_wait)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND || + generic_op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) { + rc = cam_sensor_handle_delay( + &cmd_buf, generic_op_code, + i2c_reg_settings, j, &byte_cnt, + list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "delay hdl failed: %d", + rc); + goto end; + } + + } else if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_COND) { + rc = cam_sensor_handle_poll( + &cmd_buf, i2c_reg_settings, + &byte_cnt, &j, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Random read fail: %d", + rc); + goto end; + } + } else { + CAM_ERR(CAM_SENSOR, + "Wrong Wait Command: %d", + generic_op_code); + rc = -EINVAL; + goto end; + } + break; + } + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: { + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + rc = cam_sensor_handle_slave_info( + io_master, cmd_buf); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Handle slave info failed with rc: %d", + rc); + goto end; + } + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + cmd_buf += + cmd_length_in_bytes / sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + default: + CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d", + cmm_hdr->cmd_type); + rc = -EINVAL; + goto end; + } + } + i2c_reg_settings->is_settings_valid = 1; + } + +end: + return rc; +} + +int cam_sensor_util_i2c_apply_setting( + struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list) +{ + int32_t rc = 0; + uint32_t i, size; + + switch (i2c_list->op_code) { + case CAM_SENSOR_I2C_WRITE_RANDOM: { + rc = camera_io_dev_write(io_master_info, + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to random write I2C settings: %d", + rc); + return rc; + } + break; + } + case CAM_SENSOR_I2C_WRITE_SEQ: { + rc = camera_io_dev_write_continuous( + io_master_info, &(i2c_list->i2c_settings), 0); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to seq write I2C settings: %d", + rc); + return rc; + } + break; + } + case CAM_SENSOR_I2C_WRITE_BURST: { + rc = camera_io_dev_write_continuous( + io_master_info, &(i2c_list->i2c_settings), 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to burst write I2C settings: %d", + rc); + return rc; + } + break; + } + case CAM_SENSOR_I2C_POLL: { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + io_master_info, + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "i2c poll apply setting Fail: %d", rc); + return rc; + } + } + break; + } + default: + CAM_ERR(CAM_SENSOR, "Wrong Opcode: %d", i2c_list->op_code); + rc = -EINVAL; + break; + } + + return rc; +} + +int32_t msm_camera_fill_vreg_params( + struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_setting *power_setting, + uint16_t power_setting_size) +{ + int32_t rc = 0, j = 0, i = 0; + int num_vreg; + + /* Validate input parameters */ + if (!soc_info || !power_setting) { + CAM_ERR(CAM_SENSOR, "failed: soc_info %pK power_setting %pK", + soc_info, power_setting); + return -EINVAL; + } + + num_vreg = soc_info->num_rgltr; + + if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) { + CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + for (i = 0; i < power_setting_size; i++) { + + if (power_setting[i].seq_type < SENSOR_MCLK || + power_setting[i].seq_type >= SENSOR_SEQ_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "failed: Invalid Seq type: %d", + power_setting[i].seq_type); + return -EINVAL; + } + + switch (power_setting[i].seq_type) { + case SENSOR_VDIG: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], + "cam_vdig")) { + + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vdig", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_VIO: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_vio")) { + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vio", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_VANA: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_vana")) { + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vana", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_VAF: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_vaf")) { + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vaf", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_CUSTOM_REG1: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_v_custom1")) { + CAM_DBG(CAM_SENSOR, + "i:%d j:%d cam_vcustom1", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + case SENSOR_CUSTOM_REG2: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_v_custom2")) { + CAM_DBG(CAM_SENSOR, + "i:%d j:%d cam_vcustom2", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + default: + break; + } + } + + return rc; +} + +int cam_sensor_util_request_gpio_table( + struct cam_hw_soc_info *soc_info, int gpio_en) +{ + int rc = 0, i = 0; + uint8_t size = 0; + struct cam_soc_gpio_data *gpio_conf = + soc_info->gpio_data; + struct gpio *gpio_tbl = NULL; + + if (!gpio_conf) { + CAM_INFO(CAM_SENSOR, "No GPIO data"); + return 0; + } + + if (gpio_conf->cam_gpio_common_tbl_size <= 0) { + CAM_INFO(CAM_SENSOR, "No GPIO entry"); + return -EINVAL; + } + + gpio_tbl = gpio_conf->cam_gpio_req_tbl; + size = gpio_conf->cam_gpio_req_tbl_size; + + if (!gpio_tbl || !size) { + CAM_ERR(CAM_SENSOR, "invalid gpio_tbl %pK / size %d", + gpio_tbl, size); + return -EINVAL; + } + + for (i = 0; i < size; i++) { + CAM_DBG(CAM_SENSOR, "i: %d, gpio %d dir %ld", i, + gpio_tbl[i].gpio, gpio_tbl[i].flags); + } + + if (gpio_en) { + for (i = 0; i < size; i++) { + rc = cam_res_mgr_gpio_request(soc_info->dev, + gpio_tbl[i].gpio, + gpio_tbl[i].flags, gpio_tbl[i].label); + if (rc) { + /* + * After GPIO request fails, contine to + * apply new gpios, outout a error message + * for driver bringup debug + */ + CAM_ERR(CAM_SENSOR, "gpio %d:%s request fails", + gpio_tbl[i].gpio, gpio_tbl[i].label); + } + } + } else { + cam_res_mgr_gpio_free_arry(soc_info->dev, gpio_tbl, size); + } + + return rc; +} + + +static int32_t cam_sensor_validate(void *ptr, size_t remain_buf) +{ + struct common_header *cmm_hdr = (struct common_header *)ptr; + size_t validate_size = 0; + + if (remain_buf < sizeof(struct common_header)) + return -EINVAL; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP || + cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) + validate_size = sizeof(struct cam_cmd_power); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf < validate_size) { + CAM_ERR(CAM_SENSOR, "Invalid cmd_buf len %zu min %zu", + remain_buf, validate_size); + return -EINVAL; + } + return 0; +} + +int32_t cam_sensor_update_power_settings(void *cmd_buf, + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len) +{ + int32_t rc = 0, tot_size = 0, last_cmd_type = 0; + int32_t i = 0, pwr_up = 0, pwr_down = 0; + struct cam_sensor_power_setting *pwr_settings; + void *ptr = cmd_buf, *scr; + struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf; + struct common_header *cmm_hdr = (struct common_header *)cmd_buf; + + if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length || + cam_sensor_validate(cmd_buf, cmd_buf_len)) { + CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d", + pwr_cmd, cmd_length); + return -EINVAL; + } + + power_info->power_setting_size = 0; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_down_setting_size = 0; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_down_setting) { + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return -ENOMEM; + } + + while (tot_size < cmd_length) { + if (cam_sensor_validate(ptr, (cmd_length - tot_size))) { + rc = -EINVAL; + goto free_power_settings; + } + if (cmm_hdr->cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_UP) { + struct cam_cmd_power *pwr_cmd = + (struct cam_cmd_power *)ptr; + + if ((U16_MAX - power_info->power_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow occurs"); + rc = -EINVAL; + goto free_power_settings; + } + + power_info->power_setting_size += pwr_cmd->count; + if ((power_info->power_setting_size > MAX_POWER_CONFIG) + || (pwr_cmd->count >= SENSOR_SEQ_TYPE_MAX)) { + CAM_ERR(CAM_SENSOR, + "pwr_up setting size %d, pwr_cmd->count: %d", + power_info->power_setting_size, + pwr_cmd->count); + rc = -EINVAL; + goto free_power_settings; + } + scr = ptr + sizeof(struct cam_cmd_power); + tot_size = tot_size + sizeof(struct cam_cmd_power); + + if (pwr_cmd->count == 0) + CAM_WARN(CAM_SENSOR, "pwr_up_size is zero"); + + for (i = 0; i < pwr_cmd->count; i++, pwr_up++) { + power_info->power_setting[pwr_up].seq_type = + pwr_cmd->power_settings[i].power_seq_type; + power_info->power_setting[pwr_up].config_val = + pwr_cmd->power_settings[i].config_val_low; + power_info->power_setting[pwr_up].delay = 0; + if (i) { + scr = scr + + sizeof( + struct cam_power_settings); + tot_size = tot_size + + sizeof( + struct cam_power_settings); + } + if (tot_size > cmd_length) { + CAM_ERR(CAM_SENSOR, + "Error: Cmd Buffer is wrong"); + rc = -EINVAL; + goto free_power_settings; + } + CAM_DBG(CAM_SENSOR, + "Seq Type[%d]: %d Config_val: %ld", pwr_up, + power_info->power_setting[pwr_up].seq_type, + power_info->power_setting[pwr_up].config_val); + } + last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; + ptr = (void *) scr; + cmm_hdr = (struct common_header *)ptr; + } else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) { + struct cam_cmd_unconditional_wait *wait_cmd = + (struct cam_cmd_unconditional_wait *)ptr; + if ((wait_cmd->op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) && + (last_cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_UP)) { + if (pwr_up > 0) { + pwr_settings = + &power_info->power_setting[pwr_up - 1]; + pwr_settings->delay += + wait_cmd->delay; + } else { + CAM_ERR(CAM_SENSOR, + "Delay is expected only after valid power up setting"); + } + } else if ((wait_cmd->op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) && + (last_cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_DOWN)) { + if (pwr_down > 0) { + pwr_settings = + &power_info->power_down_setting[ + pwr_down - 1]; + pwr_settings->delay += + wait_cmd->delay; + } else { + CAM_ERR(CAM_SENSOR, + "Delay is expected only after valid power up setting"); + } + } else { + CAM_DBG(CAM_SENSOR, "Invalid op code: %d", + wait_cmd->op_code); + } + + tot_size = tot_size + + sizeof(struct cam_cmd_unconditional_wait); + if (tot_size > cmd_length) { + CAM_ERR(CAM_SENSOR, "Command Buffer is wrong"); + return -EINVAL; + } + scr = (void *) (wait_cmd); + ptr = (void *) + (scr + + sizeof(struct cam_cmd_unconditional_wait)); + CAM_DBG(CAM_SENSOR, "ptr: %pK sizeof: %d Next: %pK", + scr, (int32_t)sizeof( + struct cam_cmd_unconditional_wait), ptr); + + cmm_hdr = (struct common_header *)ptr; + } else if (cmm_hdr->cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) { + struct cam_cmd_power *pwr_cmd = + (struct cam_cmd_power *)ptr; + + scr = ptr + sizeof(struct cam_cmd_power); + tot_size = tot_size + sizeof(struct cam_cmd_power); + if ((U16_MAX - power_info->power_down_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow"); + rc = -EINVAL; + goto free_power_settings; + } + + power_info->power_down_setting_size += pwr_cmd->count; + if ((power_info->power_down_setting_size > + MAX_POWER_CONFIG) || (pwr_cmd->count >= + SENSOR_SEQ_TYPE_MAX)) { + CAM_ERR(CAM_SENSOR, + "pwr_down_setting_size %d, pwr_cmd->count: %d", + power_info->power_down_setting_size, + pwr_cmd->count); + rc = -EINVAL; + goto free_power_settings; + } + + if (pwr_cmd->count == 0) + CAM_ERR(CAM_SENSOR, "pwr_down size is zero"); + + for (i = 0; i < pwr_cmd->count; i++, pwr_down++) { + pwr_settings = + &power_info->power_down_setting[pwr_down]; + pwr_settings->seq_type = + pwr_cmd->power_settings[i].power_seq_type; + pwr_settings->config_val = + pwr_cmd->power_settings[i].config_val_low; + power_info->power_down_setting[pwr_down].delay + = 0; + if (i) { + scr = scr + + sizeof( + struct cam_power_settings); + tot_size = + tot_size + + sizeof( + struct cam_power_settings); + } + if (tot_size > cmd_length) { + CAM_ERR(CAM_SENSOR, + "Command Buffer is wrong"); + rc = -EINVAL; + goto free_power_settings; + } + CAM_DBG(CAM_SENSOR, + "Seq Type[%d]: %d Config_val: %ld", + pwr_down, pwr_settings->seq_type, + pwr_settings->config_val); + } + last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_DOWN; + ptr = (void *) scr; + cmm_hdr = (struct common_header *)ptr; + } else { + CAM_ERR(CAM_SENSOR, + "Error: Un expected Header Type: %d", + cmm_hdr->cmd_type); + rc = -EINVAL; + goto free_power_settings; + } + } + + return rc; +free_power_settings: + kfree(power_info->power_down_setting); + kfree(power_info->power_setting); + power_info->power_down_setting = NULL; + power_info->power_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + return rc; +} + +int cam_get_dt_power_setting_data(struct device_node *of_node, + struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0, i; + int count = 0; + const char *seq_name = NULL; + uint32_t *array = NULL; + struct cam_sensor_power_setting *ps; + int c, end; + + if (!power_info) + return -EINVAL; + + count = of_property_count_strings(of_node, "qcom,cam-power-seq-type"); + power_info->power_setting_size = count; + + CAM_DBG(CAM_SENSOR, "qcom,cam-power-seq-type count %d", count); + + if (count <= 0) + return 0; + + ps = kcalloc(count, sizeof(*ps), GFP_KERNEL); + if (!ps) + return -ENOMEM; + power_info->power_setting = ps; + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-power-seq-type", i, &seq_name); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed"); + goto ERROR1; + } + CAM_DBG(CAM_SENSOR, "seq_name[%d] = %s", i, seq_name); + if (!strcmp(seq_name, "cam_vio")) { + ps[i].seq_type = SENSOR_VIO; + } else if (!strcmp(seq_name, "cam_vana")) { + ps[i].seq_type = SENSOR_VANA; + } else if (!strcmp(seq_name, "cam_clk")) { + ps[i].seq_type = SENSOR_MCLK; + } else { + CAM_ERR(CAM_SENSOR, "unrecognized seq-type %s", + seq_name); + rc = -EILSEQ; + goto ERROR1; + } + CAM_DBG(CAM_SENSOR, "seq_type[%d] %d", i, ps[i].seq_type); + } + + array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); + if (!array) { + rc = -ENOMEM; + goto ERROR1; + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val", + array, count); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed "); + goto ERROR2; + } + + for (i = 0; i < count; i++) { + ps[i].config_val = array[i]; + CAM_DBG(CAM_SENSOR, "power_setting[%d].config_val = %ld", i, + ps[i].config_val); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay", + array, count); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed"); + goto ERROR2; + } + for (i = 0; i < count; i++) { + ps[i].delay = array[i]; + CAM_DBG(CAM_SENSOR, "power_setting[%d].delay = %d", i, + ps[i].delay); + } + kfree(array); + + power_info->power_down_setting = + kcalloc(count, sizeof(*ps), GFP_KERNEL); + + if (!power_info->power_down_setting) { + CAM_ERR(CAM_SENSOR, "failed"); + rc = -ENOMEM; + goto ERROR1; + } + + power_info->power_down_setting_size = count; + + end = count - 1; + + for (c = 0; c < count; c++) { + power_info->power_down_setting[c] = ps[end]; + end--; + } + return rc; +ERROR2: + kfree(array); +ERROR1: + kfree(ps); + return rc; +} + +int cam_sensor_util_init_gpio_pin_tbl( + struct cam_hw_soc_info *soc_info, + struct msm_camera_gpio_num_info **pgpio_num_info) +{ + int rc = 0, val = 0; + uint32_t gpio_array_size; + struct device_node *of_node = NULL; + struct cam_soc_gpio_data *gconf = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + if (!soc_info->dev) { + CAM_ERR(CAM_SENSOR, "device node NULL"); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + + gconf = soc_info->gpio_data; + if (!gconf) { + CAM_ERR(CAM_SENSOR, "No gpio_common_table is found"); + return -EINVAL; + } + + if (!gconf->cam_gpio_common_tbl) { + CAM_ERR(CAM_SENSOR, "gpio_common_table is not initialized"); + return -EINVAL; + } + + gpio_array_size = gconf->cam_gpio_common_tbl_size; + + if (!gpio_array_size) { + CAM_ERR(CAM_SENSOR, "invalid size of gpio table"); + return -EINVAL; + } + + *pgpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info), + GFP_KERNEL); + if (!*pgpio_num_info) + return -ENOMEM; + gpio_num_info = *pgpio_num_info; + + rc = of_property_read_u32(of_node, "gpio-vana", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vana failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vana invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VANA] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VANA] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vana %d", + gpio_num_info->gpio_num[SENSOR_VANA]); + } + + rc = of_property_read_u32(of_node, "gpio-vio", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vio failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vio invalid %d", val); + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VIO] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VIO] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vio %d", + gpio_num_info->gpio_num[SENSOR_VIO]); + } + + rc = of_property_read_u32(of_node, "gpio-vaf", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vaf failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vaf invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VAF] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VAF] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vaf %d", + gpio_num_info->gpio_num[SENSOR_VAF]); + } + + rc = of_property_read_u32(of_node, "gpio-vdig", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vdig failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vdig invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VDIG] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VDIG] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vdig %d", + gpio_num_info->gpio_num[SENSOR_VDIG]); + } + + rc = of_property_read_u32(of_node, "gpio-reset", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-reset failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-reset invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_RESET] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_RESET] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-reset %d", + gpio_num_info->gpio_num[SENSOR_RESET]); + } + + rc = of_property_read_u32(of_node, "gpio-standby", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-standby failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-standby invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_STANDBY] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_STANDBY] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-standby %d", + gpio_num_info->gpio_num[SENSOR_STANDBY]); + } + + rc = of_property_read_u32(of_node, "gpio-af-pwdm", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-af-pwdm failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-af-pwdm invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VAF_PWDM] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VAF_PWDM] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-af-pwdm %d", + gpio_num_info->gpio_num[SENSOR_VAF_PWDM]); + } + + rc = of_property_read_u32(of_node, "gpio-custom1", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-custom1 failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-custom1 invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO1] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_CUSTOM_GPIO1] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-custom1 %d", + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO1]); + } + + rc = of_property_read_u32(of_node, "gpio-custom2", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-custom2 failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-custom2 invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO2] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_CUSTOM_GPIO2] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-custom2 %d", + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO2]); + } else { + rc = 0; + } + + return rc; + +free_gpio_info: + kfree(gpio_num_info); + gpio_num_info = NULL; + return rc; +} + +int msm_camera_pinctrl_init( + struct msm_pinctrl_info *sensor_pctrl, struct device *dev) +{ + + sensor_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { + CAM_DBG(CAM_SENSOR, "Getting pinctrl handle failed"); + return -EINVAL; + } + sensor_pctrl->gpio_state_active = + pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) { + CAM_ERR(CAM_SENSOR, + "Failed to get the active state pinctrl handle"); + return -EINVAL; + } + sensor_pctrl->gpio_state_suspend + = pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) { + CAM_ERR(CAM_SENSOR, + "Failed to get the suspend state pinctrl handle"); + return -EINVAL; + } + + return 0; +} + +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag) +{ + int rc = 0; + uint32_t op_current = + (flag == true) ? soc_info->rgltr_op_mode[bob_reg_idx] : 0; + + if (soc_info->rgltr[bob_reg_idx] != NULL) { + rc = regulator_set_load(soc_info->rgltr[bob_reg_idx], + op_current); + if (rc) + CAM_WARN(CAM_SENSOR, + "BoB PWM SetLoad failed rc: %d", rc); + } + + return rc; +} + +int msm_cam_sensor_handle_reg_gpio(int seq_type, + struct msm_camera_gpio_num_info *gpio_num_info, int val) +{ + int gpio_offset = -1; + + if (!gpio_num_info) { + CAM_INFO(CAM_SENSOR, "Input Parameters are not proper"); + return 0; + } + + CAM_DBG(CAM_SENSOR, "Seq type: %d, config: %d", seq_type, val); + + gpio_offset = seq_type; + + if (gpio_num_info->valid[gpio_offset] == 1) { + CAM_DBG(CAM_SENSOR, "VALID GPIO offset: %d, seqtype: %d", + gpio_offset, seq_type); + cam_res_mgr_gpio_set_value( + gpio_num_info->gpio_num + [gpio_offset], val); + } + + return 0; +} + +static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info, int32_t index) +{ + int32_t num_vreg = 0, j = 0, rc = 0, idx = 0; + struct cam_sensor_power_setting *ps = NULL; + struct cam_sensor_power_setting *pd = NULL; + + num_vreg = soc_info->num_rgltr; + + pd = &ctrl->power_down_setting[index]; + + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { + ps = NULL; + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + if (ctrl->power_setting[idx].seq_type == + pd->seq_type) { + ps = &ctrl->power_setting[idx]; + break; + } + } + + if (ps != NULL) { + CAM_DBG(CAM_SENSOR, "Disable MCLK Regulator"); + rc = cam_soc_util_regulator_disable( + soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + + if (rc) { + CAM_ERR(CAM_SENSOR, + "MCLK REG DISALBE FAILED: %d", + rc); + return rc; + } + + ps->data[0] = + soc_info->rgltr[j]; + + regulator_put( + soc_info->rgltr[j]); + soc_info->rgltr[j] = NULL; + } + } + } + + return rc; +} + +int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info) +{ + int rc = 0, index = 0, no_gpio = 0, ret = 0, num_vreg, j = 0, i = 0; + int32_t vreg_idx = -1; + struct cam_sensor_power_setting *power_setting = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + CAM_DBG(CAM_SENSOR, "Enter"); + if (!ctrl) { + CAM_ERR(CAM_SENSOR, "Invalid ctrl handle"); + return -EINVAL; + } + + gpio_num_info = ctrl->gpio_num_info; + num_vreg = soc_info->num_rgltr; + + if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) { + CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(true); + + ret = msm_camera_pinctrl_init(&(ctrl->pinctrl_info), ctrl->dev); + if (ret < 0) { + /* Some sensor subdev no pinctrl. */ + CAM_DBG(CAM_SENSOR, "Initialization of pinctrl failed"); + ctrl->cam_pinctrl_status = 0; + } else { + ctrl->cam_pinctrl_status = 1; + } + + if (cam_res_mgr_shared_pinctrl_init()) { + CAM_ERR(CAM_SENSOR, + "Failed to init shared pinctrl"); + return -EINVAL; + } + + rc = cam_sensor_util_request_gpio_table(soc_info, 1); + if (rc < 0) + no_gpio = rc; + + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state( + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_active); + if (ret) + CAM_ERR(CAM_SENSOR, "cannot set pin to active state"); + } + + ret = cam_res_mgr_shared_pinctrl_select_state(true); + if (ret) + CAM_ERR(CAM_SENSOR, + "Cannot set shared pin to active state"); + + CAM_DBG(CAM_SENSOR, "power setting size: %d", ctrl->power_setting_size); + + for (index = 0; index < ctrl->power_setting_size; index++) { + CAM_DBG(CAM_SENSOR, "index: %d", index); + power_setting = &ctrl->power_setting[index]; + if (!power_setting) { + CAM_ERR(CAM_SENSOR, + "Invalid power up settings for index %d", + index); + return -EINVAL; + } + + CAM_DBG(CAM_SENSOR, "seq_type %d", power_setting->seq_type); + + switch (power_setting->seq_type) { + case SENSOR_MCLK: + if (power_setting->seq_val >= soc_info->num_clk) { + CAM_ERR(CAM_SENSOR, "clk index %d >= max %u", + power_setting->seq_val, + soc_info->num_clk); + goto power_up_failed; + } + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], + "cam_clk")) { + CAM_DBG(CAM_SENSOR, + "Enable cam_clk: %d", j); + + soc_info->rgltr[j] = + regulator_get( + soc_info->dev, + soc_info->rgltr_name[j]); + + if (IS_ERR_OR_NULL( + soc_info->rgltr[j])) { + rc = PTR_ERR( + soc_info->rgltr[j]); + rc = rc ? rc : -EINVAL; + CAM_ERR(CAM_SENSOR, + "vreg %s %d", + soc_info->rgltr_name[j], + rc); + soc_info->rgltr[j] = NULL; + goto power_up_failed; + } + + rc = cam_soc_util_regulator_enable( + soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg enable failed"); + goto power_up_failed; + } + power_setting->data[0] = + soc_info->rgltr[j]; + } + } + if (power_setting->config_val) + soc_info->clk_rate[0][power_setting->seq_val] = + power_setting->config_val; + + for (j = 0; j < soc_info->num_clk; j++) { + rc = cam_soc_util_clk_enable(soc_info->clk[j], + soc_info->clk_name[j], + soc_info->clk_rate[0][j]); + if (rc) + break; + } + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "clk enable failed"); + goto power_up_failed; + } + break; + case SENSOR_RESET: + case SENSOR_STANDBY: + case SENSOR_CUSTOM_GPIO1: + case SENSOR_CUSTOM_GPIO2: + if (no_gpio) { + CAM_ERR(CAM_SENSOR, "request gpio failed"); + return no_gpio; + } + if (!gpio_num_info) { + CAM_ERR(CAM_SENSOR, "Invalid gpio_num_info"); + goto power_up_failed; + } + CAM_DBG(CAM_SENSOR, "gpio set val %d", + gpio_num_info->gpio_num + [power_setting->seq_type]); + + rc = msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, + (int) power_setting->config_val); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Error in handling VREG GPIO"); + goto power_up_failed; + } + break; + case SENSOR_VANA: + case SENSOR_VDIG: + case SENSOR_VIO: + case SENSOR_VAF: + case SENSOR_VAF_PWDM: + case SENSOR_CUSTOM_REG1: + case SENSOR_CUSTOM_REG2: + if (power_setting->seq_val == INVALID_VREG) + break; + + if (power_setting->seq_val >= CAM_VREG_MAX) { + CAM_ERR(CAM_SENSOR, "vreg index %d >= max %d", + power_setting->seq_val, + CAM_VREG_MAX); + goto power_up_failed; + } + if (power_setting->seq_val < num_vreg) { + CAM_DBG(CAM_SENSOR, "Enable Regulator"); + vreg_idx = power_setting->seq_val; + + soc_info->rgltr[vreg_idx] = + regulator_get(soc_info->dev, + soc_info->rgltr_name[vreg_idx]); + if (IS_ERR_OR_NULL( + soc_info->rgltr[vreg_idx])) { + rc = PTR_ERR(soc_info->rgltr[vreg_idx]); + rc = rc ? rc : -EINVAL; + + CAM_ERR(CAM_SENSOR, "%s get failed %d", + soc_info->rgltr_name[vreg_idx], + rc); + + soc_info->rgltr[vreg_idx] = NULL; + goto power_up_failed; + } + + rc = cam_soc_util_regulator_enable( + soc_info->rgltr[vreg_idx], + soc_info->rgltr_name[vreg_idx], + soc_info->rgltr_min_volt[vreg_idx], + soc_info->rgltr_max_volt[vreg_idx], + soc_info->rgltr_op_mode[vreg_idx], + soc_info->rgltr_delay[vreg_idx]); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg Enable failed for %s", + soc_info->rgltr_name[vreg_idx]); + goto power_up_failed; + } + power_setting->data[0] = + soc_info->rgltr[vreg_idx]; + } else { + CAM_ERR(CAM_SENSOR, "usr_idx:%d dts_idx:%d", + power_setting->seq_val, num_vreg); + } + + rc = msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Error in handling VREG GPIO"); + goto power_up_failed; + } + break; + default: + CAM_ERR(CAM_SENSOR, "error power seq type %d", + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) + msleep(power_setting->delay); + else if (power_setting->delay) + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + + ret = cam_res_mgr_shared_pinctrl_post_init(); + if (ret) + CAM_ERR(CAM_SENSOR, + "Failed to post init shared pinctrl"); + + return 0; +power_up_failed: + CAM_ERR(CAM_SENSOR, "failed"); + for (index--; index >= 0; index--) { + CAM_DBG(CAM_SENSOR, "index %d", index); + power_setting = &ctrl->power_setting[index]; + CAM_DBG(CAM_SENSOR, "type %d", + power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_MCLK: + for (i = soc_info->num_clk - 1; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } + break; + case SENSOR_RESET: + case SENSOR_STANDBY: + case SENSOR_CUSTOM_GPIO1: + case SENSOR_CUSTOM_GPIO2: + if (!gpio_num_info) + continue; + if (!gpio_num_info->valid + [power_setting->seq_type]) + continue; + cam_res_mgr_gpio_set_value( + gpio_num_info->gpio_num + [power_setting->seq_type], GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VANA: + case SENSOR_VDIG: + case SENSOR_VIO: + case SENSOR_VAF: + case SENSOR_VAF_PWDM: + case SENSOR_CUSTOM_REG1: + case SENSOR_CUSTOM_REG2: + if (power_setting->seq_val < num_vreg) { + CAM_DBG(CAM_SENSOR, "Disable Regulator"); + vreg_idx = power_setting->seq_val; + + rc = cam_soc_util_regulator_disable( + soc_info->rgltr[vreg_idx], + soc_info->rgltr_name[vreg_idx], + soc_info->rgltr_min_volt[vreg_idx], + soc_info->rgltr_max_volt[vreg_idx], + soc_info->rgltr_op_mode[vreg_idx], + soc_info->rgltr_delay[vreg_idx]); + + if (rc) { + CAM_ERR(CAM_SENSOR, + "Fail to disalbe reg: %s", + soc_info->rgltr_name[vreg_idx]); + soc_info->rgltr[vreg_idx] = NULL; + msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } + power_setting->data[0] = + soc_info->rgltr[vreg_idx]; + + regulator_put(soc_info->rgltr[vreg_idx]); + soc_info->rgltr[vreg_idx] = NULL; + } else { + CAM_ERR(CAM_SENSOR, "seq_val:%d > num_vreg: %d", + power_setting->seq_val, num_vreg); + } + + msm_cam_sensor_handle_reg_gpio(power_setting->seq_type, + gpio_num_info, GPIOF_OUT_INIT_LOW); + + break; + default: + CAM_ERR(CAM_SENSOR, "error power seq type %d", + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state( + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(false); + + cam_res_mgr_shared_pinctrl_select_state(false); + cam_res_mgr_shared_pinctrl_put(); + + ctrl->cam_pinctrl_status = 0; + + cam_sensor_util_request_gpio_table(soc_info, 0); + + return rc; +} + +static struct cam_sensor_power_setting* +msm_camera_get_power_settings(struct cam_sensor_power_ctrl_t *ctrl, + enum msm_camera_power_seq_type seq_type, + uint16_t seq_val) +{ + struct cam_sensor_power_setting *power_setting, *ps = NULL; + int idx; + + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + power_setting = &ctrl->power_setting[idx]; + if (power_setting->seq_type == seq_type && + power_setting->seq_val == seq_val) { + ps = power_setting; + return ps; + } + + } + + return ps; +} + +int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info) +{ + int index = 0, ret = 0, num_vreg = 0, i; + struct cam_sensor_power_setting *pd = NULL; + struct cam_sensor_power_setting *ps = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + CAM_DBG(CAM_SENSOR, "Enter"); + if (!ctrl || !soc_info) { + CAM_ERR(CAM_SENSOR, "failed ctrl %pK", ctrl); + return -EINVAL; + } + + gpio_num_info = ctrl->gpio_num_info; + num_vreg = soc_info->num_rgltr; + + if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) { + CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + if (ctrl->power_down_setting_size > MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, "Invalid: power setting size %d", + ctrl->power_setting_size); + return -EINVAL; + } + + for (index = 0; index < ctrl->power_down_setting_size; index++) { + CAM_DBG(CAM_SENSOR, "power_down_index %d", index); + pd = &ctrl->power_down_setting[index]; + if (!pd) { + CAM_ERR(CAM_SENSOR, + "Invalid power down settings for index %d", + index); + return -EINVAL; + } + + ps = NULL; + CAM_DBG(CAM_SENSOR, "seq_type %d", pd->seq_type); + switch (pd->seq_type) { + case SENSOR_MCLK: + for (i = soc_info->num_clk - 1; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } + break; + case SENSOR_RESET: + case SENSOR_STANDBY: + case SENSOR_CUSTOM_GPIO1: + case SENSOR_CUSTOM_GPIO2: + + if (!gpio_num_info->valid[pd->seq_type]) + continue; + + cam_res_mgr_gpio_set_value( + gpio_num_info->gpio_num + [pd->seq_type], + (int) pd->config_val); + + break; + case SENSOR_VANA: + case SENSOR_VDIG: + case SENSOR_VIO: + case SENSOR_VAF: + case SENSOR_VAF_PWDM: + case SENSOR_CUSTOM_REG1: + case SENSOR_CUSTOM_REG2: + if (pd->seq_val == INVALID_VREG) + break; + + ps = msm_camera_get_power_settings( + ctrl, pd->seq_type, + pd->seq_val); + if (ps) { + if (pd->seq_val < num_vreg) { + CAM_DBG(CAM_SENSOR, + "Disable Regulator"); + ret = cam_soc_util_regulator_disable( + soc_info->rgltr[ps->seq_val], + soc_info->rgltr_name[ps->seq_val], + soc_info->rgltr_min_volt[ps->seq_val], + soc_info->rgltr_max_volt[ps->seq_val], + soc_info->rgltr_op_mode[ps->seq_val], + soc_info->rgltr_delay[ps->seq_val]); + if (ret) { + CAM_ERR(CAM_SENSOR, + "Reg: %s disable failed", + soc_info->rgltr_name[ + ps->seq_val]); + soc_info->rgltr[ps->seq_val] = + NULL; + msm_cam_sensor_handle_reg_gpio( + pd->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } + ps->data[0] = + soc_info->rgltr[ps->seq_val]; + regulator_put( + soc_info->rgltr[ps->seq_val]); + soc_info->rgltr[ps->seq_val] = NULL; + } else { + CAM_ERR(CAM_SENSOR, + "seq_val:%d > num_vreg: %d", + pd->seq_val, + num_vreg); + } + } else + CAM_ERR(CAM_SENSOR, + "error in power up/down seq"); + + ret = msm_cam_sensor_handle_reg_gpio(pd->seq_type, + gpio_num_info, GPIOF_OUT_INIT_LOW); + + if (ret < 0) + CAM_ERR(CAM_SENSOR, + "Error disabling VREG GPIO"); + break; + default: + CAM_ERR(CAM_SENSOR, "error power seq type %d", + pd->seq_type); + break; + } + if (pd->delay > 20) + msleep(pd->delay); + else if (pd->delay) + usleep_range(pd->delay * 1000, + (pd->delay * 1000) + 1000); + } + + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state( + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); + + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(false); + + cam_res_mgr_shared_pinctrl_select_state(false); + cam_res_mgr_shared_pinctrl_put(); + + ctrl->cam_pinctrl_status = 0; + + cam_sensor_util_request_gpio_table(soc_info, 0); + + return 0; +} diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h new file mode 100644 index 000000000000..69679f8c76e7 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_UTIL_H_ +#define _CAM_SENSOR_UTIL_H_ + +#include +#include +#include +#include +#include +#include "cam_sensor_cmn_header.h" +#include "../../cam_req_mgr/cam_req_mgr_util.h" +#include "../../cam_req_mgr/cam_req_mgr_interface.h" +#include "../../cam_req_mgr/cam_mem_mgr.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_sensor_io.h" + +#define INVALID_VREG 100 + +int cam_get_dt_power_setting_data(struct device_node *of_node, + struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_ctrl_t *power_info); + +int msm_camera_pinctrl_init + (struct msm_pinctrl_info *sensor_pctrl, struct device *dev); + +int cam_sensor_i2c_command_parser(struct camera_io_master *io_master, + struct i2c_settings_array *i2c_reg_settings, + struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers); + +int cam_sensor_util_i2c_apply_setting(struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list); + +int32_t delete_request(struct i2c_settings_array *i2c_array); +int cam_sensor_util_request_gpio_table( + struct cam_hw_soc_info *soc_info, int gpio_en); + +int cam_sensor_util_init_gpio_pin_tbl( + struct cam_hw_soc_info *soc_info, + struct msm_camera_gpio_num_info **pgpio_num_info); +int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info); + +int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info); + +int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_setting *power_setting, + uint16_t power_setting_size); + +int32_t cam_sensor_update_power_settings(void *cmd_buf, + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len); + +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag); +#endif /* _CAM_SENSOR_UTIL_H_ */ diff --git a/drivers/cam_smmu/Makefile b/drivers/cam_smmu/Makefile new file mode 100644 index 000000000000..c82e3978d028 --- /dev/null +++ b/drivers/cam_smmu/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu_api.o diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c new file mode 100644 index 000000000000..7084f38daaaa --- /dev/null +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -0,0 +1,3570 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_smmu_api.h" +#include "cam_debug_util.h" + +#define SHARED_MEM_POOL_GRANULARITY 16 + +#define IOMMU_INVALID_DIR -1 +#define BYTE_SIZE 8 +#define COOKIE_NUM_BYTE 2 +#define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE) +#define COOKIE_MASK ((1<> COOKIE_SIZE) & COOKIE_MASK) + +static int g_num_pf_handled = 4; +module_param(g_num_pf_handled, int, 0644); + +struct firmware_alloc_info { + struct device *fw_dev; + void *fw_kva; + dma_addr_t fw_dma_hdl; +}; + +struct firmware_alloc_info icp_fw; + +struct cam_smmu_work_payload { + int idx; + struct iommu_domain *domain; + struct device *dev; + unsigned long iova; + int flags; + void *token; + struct list_head list; +}; + +enum cam_protection_type { + CAM_PROT_INVALID, + CAM_NON_SECURE, + CAM_SECURE, + CAM_PROT_MAX, +}; + +enum cam_iommu_type { + CAM_SMMU_INVALID, + CAM_QSMMU, + CAM_ARM_SMMU, + CAM_SMMU_MAX, +}; + +enum cam_smmu_buf_state { + CAM_SMMU_BUFF_EXIST, + CAM_SMMU_BUFF_NOT_EXIST, +}; + +enum cam_smmu_init_dir { + CAM_SMMU_TABLE_INIT, + CAM_SMMU_TABLE_DEINIT, +}; + +struct scratch_mapping { + void *bitmap; + size_t bits; + unsigned int order; + dma_addr_t base; +}; + +struct secheap_buf_info { + struct dma_buf *buf; + struct dma_buf_attachment *attach; + struct sg_table *table; +}; + +struct cam_context_bank_info { + struct device *dev; + struct iommu_domain *domain; + dma_addr_t va_start; + size_t va_len; + const char *name; + bool is_secure; + uint8_t scratch_buf_support; + uint8_t firmware_support; + uint8_t shared_support; + uint8_t io_support; + uint8_t secheap_support; + uint8_t qdss_support; + dma_addr_t qdss_phy_addr; + bool is_fw_allocated; + bool is_secheap_allocated; + bool is_qdss_allocated; + + struct scratch_mapping scratch_map; + struct gen_pool *shared_mem_pool; + + struct cam_smmu_region_info scratch_info; + struct cam_smmu_region_info firmware_info; + struct cam_smmu_region_info shared_info; + struct cam_smmu_region_info io_info; + struct cam_smmu_region_info secheap_info; + struct cam_smmu_region_info qdss_info; + struct secheap_buf_info secheap_buf; + + struct list_head smmu_buf_list; + struct list_head smmu_buf_kernel_list; + struct mutex lock; + int handle; + enum cam_smmu_ops_param state; + + cam_smmu_client_page_fault_handler handler[CAM_SMMU_CB_MAX]; + void *token[CAM_SMMU_CB_MAX]; + int cb_count; + int secure_count; + int pf_count; +}; + +struct cam_iommu_cb_set { + struct cam_context_bank_info *cb_info; + u32 cb_num; + u32 cb_init_count; + struct work_struct smmu_work; + struct mutex payload_list_lock; + struct list_head payload_list; + u32 non_fatal_fault; +}; + +static const struct of_device_id msm_cam_smmu_dt_match[] = { + { .compatible = "qcom,msm-cam-smmu", }, + { .compatible = "qcom,msm-cam-smmu-cb", }, + { .compatible = "qcom,msm-cam-smmu-fw-dev", }, + {} +}; + +struct cam_dma_buff_info { + struct dma_buf *buf; + struct dma_buf_attachment *attach; + struct sg_table *table; + enum dma_data_direction dir; + enum cam_smmu_region_id region_id; + int iommu_dir; + int ref_count; + dma_addr_t paddr; + struct list_head list; + int ion_fd; + size_t len; + size_t phys_len; +}; + +struct cam_sec_buff_info { + struct dma_buf *buf; + enum dma_data_direction dir; + int ref_count; + dma_addr_t paddr; + struct list_head list; + int ion_fd; + size_t len; +}; + +static const char *qdss_region_name = "qdss"; + +static struct cam_iommu_cb_set iommu_cb_set; + +static enum dma_data_direction cam_smmu_translate_dir( + enum cam_smmu_map_dir dir); + +static int cam_smmu_check_handle_unique(int hdl); + +static int cam_smmu_create_iommu_handle(int idx); + +static int cam_smmu_create_add_handle_in_table(char *name, + int *hdl); + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, + int ion_fd); + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_dma_buf(int idx, + struct dma_buf *buf); + +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd); + +static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, + dma_addr_t base, size_t size, + int order); + +static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping, + size_t size, + dma_addr_t *iova); + +static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping, + dma_addr_t addr, size_t size); + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, + dma_addr_t virt_addr); + +static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, + enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id); + +static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, + struct dma_buf *buf, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id); + +static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx, + size_t virt_len, + size_t phys_len, + unsigned int iommu_dir, + dma_addr_t *virt_addr); + +static int cam_smmu_unmap_buf_and_remove_from_list( + struct cam_dma_buff_info *mapping_info, int idx); + +static int cam_smmu_free_scratch_buffer_remove_from_list( + struct cam_dma_buff_info *mapping_info, + int idx); + +static void cam_smmu_clean_user_buffer_list(int idx); + +static void cam_smmu_clean_kernel_buffer_list(int idx); + +static void cam_smmu_print_user_list(int idx); + +static void cam_smmu_print_kernel_list(int idx); + +static void cam_smmu_print_table(void); + +static int cam_smmu_probe(struct platform_device *pdev); + +static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr); + +static void cam_smmu_page_fault_work(struct work_struct *work) +{ + int j; + int idx; + struct cam_smmu_work_payload *payload; + uint32_t buf_info; + + mutex_lock(&iommu_cb_set.payload_list_lock); + if (list_empty(&iommu_cb_set.payload_list)) { + CAM_ERR(CAM_SMMU, "Payload list empty"); + mutex_unlock(&iommu_cb_set.payload_list_lock); + return; + } + + payload = list_first_entry(&iommu_cb_set.payload_list, + struct cam_smmu_work_payload, + list); + list_del(&payload->list); + mutex_unlock(&iommu_cb_set.payload_list_lock); + + /* Dereference the payload to call the handler */ + idx = payload->idx; + buf_info = cam_smmu_find_closest_mapping(idx, (void *)payload->iova); + if (buf_info != 0) + CAM_INFO(CAM_SMMU, "closest buf 0x%x idx %d", buf_info, idx); + + for (j = 0; j < CAM_SMMU_CB_MAX; j++) { + if ((iommu_cb_set.cb_info[idx].handler[j])) { + iommu_cb_set.cb_info[idx].handler[j]( + payload->domain, + payload->dev, + payload->iova, + payload->flags, + iommu_cb_set.cb_info[idx].token[j], + buf_info); + } + } + kfree(payload); +} + +static void cam_smmu_print_user_list(int idx) +{ + struct cam_dma_buff_info *mapping; + + CAM_ERR(CAM_SMMU, "index = %d", idx); + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + CAM_ERR(CAM_SMMU, + "ion_fd = %d, paddr= 0x%pK, len = %u, region = %d", + mapping->ion_fd, (void *)mapping->paddr, + (unsigned int)mapping->len, + mapping->region_id); + } +} + +static void cam_smmu_print_kernel_list(int idx) +{ + struct cam_dma_buff_info *mapping; + + CAM_ERR(CAM_SMMU, "index = %d", idx); + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, list) { + CAM_ERR(CAM_SMMU, + "dma_buf = %pK, paddr= 0x%pK, len = %u, region = %d", + mapping->buf, (void *)mapping->paddr, + (unsigned int)mapping->len, + mapping->region_id); + } +} + +static void cam_smmu_print_table(void) +{ + int i; + + for (i = 0; i < iommu_cb_set.cb_num; i++) { + CAM_ERR(CAM_SMMU, "i= %d, handle= %d, name_addr=%pK", i, + (int)iommu_cb_set.cb_info[i].handle, + (void *)iommu_cb_set.cb_info[i].name); + CAM_ERR(CAM_SMMU, "dev = %pK", iommu_cb_set.cb_info[i].dev); + } +} + +static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr) +{ + struct cam_dma_buff_info *mapping, *closest_mapping = NULL; + unsigned long start_addr, end_addr, current_addr; + uint32_t buf_handle = 0; + + long delta = 0, lowest_delta = 0; + + current_addr = (unsigned long)vaddr; + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + start_addr = (unsigned long)mapping->paddr; + end_addr = (unsigned long)mapping->paddr + mapping->len; + + if (start_addr <= current_addr && current_addr <= end_addr) { + closest_mapping = mapping; + CAM_INFO(CAM_SMMU, + "Found va 0x%lx in:0x%lx-0x%lx, fd %d cb:%s", + current_addr, start_addr, + end_addr, mapping->ion_fd, + iommu_cb_set.cb_info[idx].name); + goto end; + } else { + if (start_addr > current_addr) + delta = start_addr - current_addr; + else + delta = current_addr - end_addr - 1; + + if (delta < lowest_delta || lowest_delta == 0) { + lowest_delta = delta; + closest_mapping = mapping; + } + CAM_DBG(CAM_SMMU, + "approx va %lx not in range: %lx-%lx fd = %0x", + current_addr, start_addr, + end_addr, mapping->ion_fd); + } + } + +end: + if (closest_mapping) { + buf_handle = GET_MEM_HANDLE(idx, closest_mapping->ion_fd); + CAM_INFO(CAM_SMMU, + "Closest map fd %d 0x%lx 0x%lx-0x%lx buf=%pK mem %0x", + closest_mapping->ion_fd, current_addr, + (unsigned long)closest_mapping->paddr, + (unsigned long)closest_mapping->paddr + mapping->len, + closest_mapping->buf, + buf_handle); + } else + CAM_INFO(CAM_SMMU, + "Cannot find vaddr:%lx in SMMU %s virt address", + current_addr, iommu_cb_set.cb_info[idx].name); + + return buf_handle; +} + +void cam_smmu_set_client_page_fault_handler(int handle, + cam_smmu_client_page_fault_handler handler_cb, void *token) +{ + int idx, i = 0; + + if (!token || (handle == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: token is NULL or invalid handle"); + return; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return; + } + + if (handler_cb) { + if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) { + CAM_ERR(CAM_SMMU, + "%s Should not regiester more handlers", + iommu_cb_set.cb_info[idx].name); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return; + } + + iommu_cb_set.cb_info[idx].cb_count++; + + for (i = 0; i < iommu_cb_set.cb_info[idx].cb_count; i++) { + if (iommu_cb_set.cb_info[idx].token[i] == NULL) { + iommu_cb_set.cb_info[idx].token[i] = token; + iommu_cb_set.cb_info[idx].handler[i] = + handler_cb; + break; + } + } + } else { + for (i = 0; i < CAM_SMMU_CB_MAX; i++) { + if (iommu_cb_set.cb_info[idx].token[i] == token) { + iommu_cb_set.cb_info[idx].token[i] = NULL; + iommu_cb_set.cb_info[idx].handler[i] = + NULL; + iommu_cb_set.cb_info[idx].cb_count--; + break; + } + } + if (i == CAM_SMMU_CB_MAX) + CAM_ERR(CAM_SMMU, + "Error: hdl %x no matching tokens: %s", + handle, iommu_cb_set.cb_info[idx].name); + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +} + +void cam_smmu_unset_client_page_fault_handler(int handle, void *token) +{ + int idx, i = 0; + + if (!token || (handle == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: token is NULL or invalid handle"); + return; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return; + } + + for (i = 0; i < CAM_SMMU_CB_MAX; i++) { + if (iommu_cb_set.cb_info[idx].token[i] == token) { + iommu_cb_set.cb_info[idx].token[i] = NULL; + iommu_cb_set.cb_info[idx].handler[i] = + NULL; + iommu_cb_set.cb_info[idx].cb_count--; + break; + } + } + if (i == CAM_SMMU_CB_MAX) + CAM_ERR(CAM_SMMU, "Error: hdl %x no matching tokens: %s", + handle, iommu_cb_set.cb_info[idx].name); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +} + +static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, + int flags, void *token) +{ + char *cb_name; + int idx; + struct cam_smmu_work_payload *payload; + + if (!token) { + CAM_ERR(CAM_SMMU, "Error: token is NULL"); + CAM_ERR(CAM_SMMU, "Error: domain = %pK, device = %pK", + domain, dev); + CAM_ERR(CAM_SMMU, "iova = %lX, flags = %d", iova, flags); + return -EINVAL; + } + + cb_name = (char *)token; + /* Check whether it is in the table */ + for (idx = 0; idx < iommu_cb_set.cb_num; idx++) { + if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name)) + break; + } + + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: index is not valid, index = %d, token = %s", + idx, cb_name); + return -EINVAL; + } + + if (++iommu_cb_set.cb_info[idx].pf_count > g_num_pf_handled) { + CAM_INFO_RATE_LIMIT(CAM_SMMU, "PF already handled %d %d %d", + g_num_pf_handled, idx, + iommu_cb_set.cb_info[idx].pf_count); + return -EINVAL; + } + + payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC); + if (!payload) + return -EINVAL; + + payload->domain = domain; + payload->dev = dev; + payload->iova = iova; + payload->flags = flags; + payload->token = token; + payload->idx = idx; + + mutex_lock(&iommu_cb_set.payload_list_lock); + list_add_tail(&payload->list, &iommu_cb_set.payload_list); + mutex_unlock(&iommu_cb_set.payload_list_lock); + + cam_smmu_page_fault_work(&iommu_cb_set.smmu_work); + + return -EINVAL; +} + +static int cam_smmu_translate_dir_to_iommu_dir( + enum cam_smmu_map_dir dir) +{ + switch (dir) { + case CAM_SMMU_MAP_READ: + return IOMMU_READ; + case CAM_SMMU_MAP_WRITE: + return IOMMU_WRITE; + case CAM_SMMU_MAP_RW: + return IOMMU_READ|IOMMU_WRITE; + case CAM_SMMU_MAP_INVALID: + default: + CAM_ERR(CAM_SMMU, "Error: Direction is invalid. dir = %d", dir); + break; + }; + return IOMMU_INVALID_DIR; +} + +static enum dma_data_direction cam_smmu_translate_dir( + enum cam_smmu_map_dir dir) +{ + switch (dir) { + case CAM_SMMU_MAP_READ: + return DMA_FROM_DEVICE; + case CAM_SMMU_MAP_WRITE: + return DMA_TO_DEVICE; + case CAM_SMMU_MAP_RW: + return DMA_BIDIRECTIONAL; + case CAM_SMMU_MAP_INVALID: + default: + CAM_ERR(CAM_SMMU, "Error: Direction is invalid. dir = %d", + (int)dir); + break; + } + return DMA_NONE; +} + +void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops) +{ + unsigned int i; + int j = 0; + + for (i = 0; i < iommu_cb_set.cb_num; i++) { + iommu_cb_set.cb_info[i].handle = HANDLE_INIT; + INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_list); + INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_kernel_list); + iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH; + iommu_cb_set.cb_info[i].dev = NULL; + iommu_cb_set.cb_info[i].cb_count = 0; + iommu_cb_set.cb_info[i].pf_count = 0; + for (j = 0; j < CAM_SMMU_CB_MAX; j++) { + iommu_cb_set.cb_info[i].token[j] = NULL; + iommu_cb_set.cb_info[i].handler[j] = NULL; + } + if (ops == CAM_SMMU_TABLE_INIT) + mutex_init(&iommu_cb_set.cb_info[i].lock); + else + mutex_destroy(&iommu_cb_set.cb_info[i].lock); + } +} + +static int cam_smmu_check_handle_unique(int hdl) +{ + int i; + + if (hdl == HANDLE_INIT) { + CAM_DBG(CAM_SMMU, + "iommu handle is init number. Need to try again"); + return 1; + } + + for (i = 0; i < iommu_cb_set.cb_num; i++) { + if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT) + continue; + + if (iommu_cb_set.cb_info[i].handle == hdl) { + CAM_DBG(CAM_SMMU, "iommu handle %d conflicts", + (int)hdl); + return 1; + } + } + return 0; +} + +/** + * use low 2 bytes for handle cookie + */ +static int cam_smmu_create_iommu_handle(int idx) +{ + int rand, hdl = 0; + + get_random_bytes(&rand, COOKIE_NUM_BYTE); + hdl = GET_SMMU_HDL(idx, rand); + CAM_DBG(CAM_SMMU, "create handle value = %x", (int)hdl); + return hdl; +} + +static int cam_smmu_attach_device(int idx) +{ + int rc; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + /* attach the mapping to device */ + rc = iommu_attach_device(cb->domain, cb->dev); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: ARM IOMMU attach failed. ret = %d", + rc); + rc = -ENODEV; + } + + return rc; +} + +static int cam_smmu_create_add_handle_in_table(char *name, + int *hdl) +{ + int i; + int handle; + + /* create handle and add in the iommu hardware table */ + for (i = 0; i < iommu_cb_set.cb_num; i++) { + if (!strcmp(iommu_cb_set.cb_info[i].name, name)) { + mutex_lock(&iommu_cb_set.cb_info[i].lock); + if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) { + if (iommu_cb_set.cb_info[i].is_secure) + iommu_cb_set.cb_info[i].secure_count++; + + mutex_unlock(&iommu_cb_set.cb_info[i].lock); + if (iommu_cb_set.cb_info[i].is_secure) { + *hdl = iommu_cb_set.cb_info[i].handle; + return 0; + } + + CAM_ERR(CAM_SMMU, + "Error: %s already got handle 0x%x", + name, iommu_cb_set.cb_info[i].handle); + + return -EINVAL; + } + + /* make sure handle is unique */ + do { + handle = cam_smmu_create_iommu_handle(i); + } while (cam_smmu_check_handle_unique(handle)); + + /* put handle in the table */ + iommu_cb_set.cb_info[i].handle = handle; + iommu_cb_set.cb_info[i].cb_count = 0; + if (iommu_cb_set.cb_info[i].is_secure) + iommu_cb_set.cb_info[i].secure_count++; + *hdl = handle; + CAM_DBG(CAM_SMMU, "%s creates handle 0x%x", + name, handle); + mutex_unlock(&iommu_cb_set.cb_info[i].lock); + return 0; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find name %s or all handle exist", + name); + cam_smmu_print_table(); + return -EINVAL; +} + +static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, + dma_addr_t base, size_t size, + int order) +{ + unsigned int count = size >> (PAGE_SHIFT + order); + unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long); + int err = 0; + + if (!count) { + err = -EINVAL; + CAM_ERR(CAM_SMMU, "Page count is zero, size passed = %zu", + size); + goto bail; + } + + scratch_map->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!scratch_map->bitmap) { + err = -ENOMEM; + goto bail; + } + + scratch_map->base = base; + scratch_map->bits = BITS_PER_BYTE * bitmap_size; + scratch_map->order = order; + +bail: + return err; +} + +static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping, + size_t size, + dma_addr_t *iova) +{ + unsigned int order = get_order(size); + unsigned int align = 0; + unsigned int count, start; + + count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) + + (1 << mapping->order) - 1) >> mapping->order; + + /* + * Transparently, add a guard page to the total count of pages + * to be allocated + */ + count++; + + if (order > mapping->order) + align = (1 << (order - mapping->order)) - 1; + + start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0, + count, align); + + if (start > mapping->bits) + return -ENOMEM; + + bitmap_set(mapping->bitmap, start, count); + *iova = mapping->base + (start << (mapping->order + PAGE_SHIFT)); + + return 0; +} + +static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping, + dma_addr_t addr, size_t size) +{ + unsigned int start = (addr - mapping->base) >> + (mapping->order + PAGE_SHIFT); + unsigned int count = ((size >> PAGE_SHIFT) + + (1 << mapping->order) - 1) >> mapping->order; + + if (!addr) { + CAM_ERR(CAM_SMMU, "Error: Invalid address"); + return -EINVAL; + } + + if (start + count > mapping->bits) { + CAM_ERR(CAM_SMMU, "Error: Invalid page bits in scratch map"); + return -EINVAL; + } + + /* + * Transparently, add a guard page to the total count of pages + * to be freed + */ + count++; + bitmap_clear(mapping->bitmap, start, count); + + return 0; +} + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, + dma_addr_t virt_addr) +{ + struct cam_dma_buff_info *mapping; + + list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->paddr == virt_addr) { + CAM_DBG(CAM_SMMU, "Found virtual address %lx", + (unsigned long)virt_addr); + return mapping; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find virtual address %lx by index %d", + (unsigned long)virt_addr, idx); + return NULL; +} + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, + int ion_fd) +{ + struct cam_dma_buff_info *mapping; + + if (ion_fd < 0) { + CAM_ERR(CAM_SMMU, "Invalid fd %d", ion_fd); + return NULL; + } + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + CAM_DBG(CAM_SMMU, "find ion_fd %d", ion_fd); + return mapping; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find entry by index %d", idx); + + return NULL; +} + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_dma_buf(int idx, + struct dma_buf *buf) +{ + struct cam_dma_buff_info *mapping; + + if (!buf) { + CAM_ERR(CAM_SMMU, "Invalid dma_buf"); + return NULL; + } + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, + list) { + if (mapping->buf == buf) { + CAM_DBG(CAM_SMMU, "find dma_buf %pK", buf); + return mapping; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find entry by index %d", idx); + + return NULL; +} + +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + CAM_DBG(CAM_SMMU, "find ion_fd %d", ion_fd); + return mapping; + } + } + CAM_ERR(CAM_SMMU, "Error: Cannot find fd %d by index %d", + ion_fd, idx); + return NULL; +} + +static void cam_smmu_clean_user_buffer_list(int idx) +{ + int ret; + struct cam_dma_buff_info *mapping_info, *temp; + + list_for_each_entry_safe(mapping_info, temp, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + CAM_DBG(CAM_SMMU, "Free mapping address %pK, i = %d, fd = %d", + (void *)mapping_info->paddr, idx, + mapping_info->ion_fd); + + if (mapping_info->ion_fd == 0xDEADBEEF) + /* Clean up scratch buffers */ + ret = cam_smmu_free_scratch_buffer_remove_from_list( + mapping_info, idx); + else + /* Clean up regular mapped buffers */ + ret = cam_smmu_unmap_buf_and_remove_from_list( + mapping_info, + idx); + + if (ret < 0) { + CAM_ERR(CAM_SMMU, "Buffer delete failed: idx = %d", + idx); + CAM_ERR(CAM_SMMU, + "Buffer delete failed: addr = %lx, fd = %d", + (unsigned long)mapping_info->paddr, + mapping_info->ion_fd); + /* + * Ignore this error and continue to delete other + * buffers in the list + */ + continue; + } + } +} + +static void cam_smmu_clean_kernel_buffer_list(int idx) +{ + int ret; + struct cam_dma_buff_info *mapping_info, *temp; + + list_for_each_entry_safe(mapping_info, temp, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, list) { + CAM_DBG(CAM_SMMU, + "Free mapping address %pK, i = %d, dma_buf = %pK", + (void *)mapping_info->paddr, idx, + mapping_info->buf); + + /* Clean up regular mapped buffers */ + ret = cam_smmu_unmap_buf_and_remove_from_list( + mapping_info, + idx); + + if (ret < 0) { + CAM_ERR(CAM_SMMU, + "Buffer delete in kernel list failed: idx = %d", + idx); + CAM_ERR(CAM_SMMU, + "Buffer delete failed: addr = %lx, dma_buf = %pK", + (unsigned long)mapping_info->paddr, + mapping_info->buf); + /* + * Ignore this error and continue to delete other + * buffers in the list + */ + continue; + } + } +} + +static int cam_smmu_attach(int idx) +{ + int ret; + + if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) { + ret = -EALREADY; + } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) { + ret = cam_smmu_attach_device(idx); + if (ret < 0) { + CAM_ERR(CAM_SMMU, "Error: ATTACH fail"); + return -ENODEV; + } + iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH; + ret = 0; + } else { + CAM_ERR(CAM_SMMU, "Error: Not detach/attach: %d", + iommu_cb_set.cb_info[idx].state); + ret = -EINVAL; + } + + return ret; +} + +static int cam_smmu_detach_device(int idx) +{ + int rc = 0; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + /* detach the mapping to device if not already detached */ + if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) { + rc = -EALREADY; + } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) { + iommu_detach_device(cb->domain, cb->dev); + iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH; + } + + return rc; +} + +static int cam_smmu_alloc_iova(size_t size, + int32_t smmu_hdl, uint32_t *iova) +{ + int rc = 0; + int idx; + uint32_t vaddr = 0; + + if (!iova || !size || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + CAM_DBG(CAM_SMMU, "Allocating iova size = %zu for smmu hdl=%X", + size, smmu_hdl); + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, smmu_hdl); + rc = -EINVAL; + goto get_addr_end; + } + + if (!iommu_cb_set.cb_info[idx].shared_support) { + CAM_ERR(CAM_SMMU, + "Error: Shared memory not supported for hdl = %X", + smmu_hdl); + rc = -EINVAL; + goto get_addr_end; + } + + vaddr = gen_pool_alloc(iommu_cb_set.cb_info[idx].shared_mem_pool, size); + if (!vaddr) + return -ENOMEM; + + *iova = vaddr; + +get_addr_end: + return rc; +} + +static int cam_smmu_free_iova(uint32_t addr, size_t size, + int32_t smmu_hdl) +{ + int rc = 0; + int idx; + + if (!size || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, smmu_hdl); + rc = -EINVAL; + goto get_addr_end; + } + + gen_pool_free(iommu_cb_set.cb_info[idx].shared_mem_pool, addr, size); + +get_addr_end: + return rc; +} + +int cam_smmu_alloc_firmware(int32_t smmu_hdl, + dma_addr_t *iova, + uintptr_t *cpuva, + size_t *len) +{ + int rc; + int32_t idx; + size_t firmware_len = 0; + size_t firmware_start = 0; + struct iommu_domain *domain; + + if (!iova || !len || !cpuva || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].firmware_support) { + CAM_ERR(CAM_SMMU, + "Firmware memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_fw_allocated) { + CAM_ERR(CAM_SMMU, "Trying to allocate twice"); + rc = -ENOMEM; + goto unlock_and_end; + } + + firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len; + firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start; + CAM_DBG(CAM_SMMU, "Firmware area len from DT = %zu", firmware_len); + + icp_fw.fw_kva = dma_alloc_coherent(icp_fw.fw_dev, + firmware_len, + &icp_fw.fw_dma_hdl, + GFP_KERNEL); + if (!icp_fw.fw_kva) { + CAM_ERR(CAM_SMMU, "FW memory alloc failed"); + rc = -ENOMEM; + goto unlock_and_end; + } else { + CAM_DBG(CAM_SMMU, "DMA alloc returned fw = %pK, hdl = %pK", + icp_fw.fw_kva, (void *)icp_fw.fw_dma_hdl); + } + + domain = iommu_cb_set.cb_info[idx].domain; + rc = iommu_map(domain, + firmware_start, + icp_fw.fw_dma_hdl, + firmware_len, + IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV); + + if (rc) { + CAM_ERR(CAM_SMMU, "Failed to map FW into IOMMU"); + rc = -ENOMEM; + goto alloc_fail; + } + iommu_cb_set.cb_info[idx].is_fw_allocated = true; + + *iova = iommu_cb_set.cb_info[idx].firmware_info.iova_start; + *cpuva = (uintptr_t)icp_fw.fw_kva; + *len = firmware_len; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return rc; + +alloc_fail: + dma_free_coherent(icp_fw.fw_dev, + firmware_len, + icp_fw.fw_kva, + icp_fw.fw_dma_hdl); +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_alloc_firmware); + +int cam_smmu_dealloc_firmware(int32_t smmu_hdl) +{ + int rc = 0; + int32_t idx; + size_t firmware_len = 0; + size_t firmware_start = 0; + struct iommu_domain *domain; + size_t unmapped = 0; + + if (smmu_hdl == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].firmware_support) { + CAM_ERR(CAM_SMMU, + "Firmware memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (!iommu_cb_set.cb_info[idx].is_fw_allocated) { + CAM_ERR(CAM_SMMU, + "Trying to deallocate firmware that is not allocated"); + rc = -ENOMEM; + goto unlock_and_end; + } + + firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len; + firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start; + domain = iommu_cb_set.cb_info[idx].domain; + unmapped = iommu_unmap(domain, + firmware_start, + firmware_len); + + if (unmapped != firmware_len) { + CAM_ERR(CAM_SMMU, "Only %zu unmapped out of total %zu", + unmapped, + firmware_len); + rc = -EINVAL; + } + + dma_free_coherent(icp_fw.fw_dev, + firmware_len, + icp_fw.fw_kva, + icp_fw.fw_dma_hdl); + + icp_fw.fw_kva = 0; + icp_fw.fw_dma_hdl = 0; + + iommu_cb_set.cb_info[idx].is_fw_allocated = false; + +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_dealloc_firmware); + +int cam_smmu_alloc_qdss(int32_t smmu_hdl, + dma_addr_t *iova, + size_t *len) +{ + int rc; + int32_t idx; + size_t qdss_len = 0; + size_t qdss_start = 0; + dma_addr_t qdss_phy_addr; + struct iommu_domain *domain; + + if (!iova || !len || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].qdss_support) { + CAM_ERR(CAM_SMMU, + "QDSS memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_qdss_allocated) { + CAM_ERR(CAM_SMMU, "Trying to allocate twice"); + rc = -ENOMEM; + goto unlock_and_end; + } + + qdss_len = iommu_cb_set.cb_info[idx].qdss_info.iova_len; + qdss_start = iommu_cb_set.cb_info[idx].qdss_info.iova_start; + qdss_phy_addr = iommu_cb_set.cb_info[idx].qdss_phy_addr; + CAM_DBG(CAM_SMMU, "QDSS area len from DT = %zu", qdss_len); + + domain = iommu_cb_set.cb_info[idx].domain; + rc = iommu_map(domain, + qdss_start, + qdss_phy_addr, + qdss_len, + IOMMU_READ|IOMMU_WRITE); + + if (rc) { + CAM_ERR(CAM_SMMU, "Failed to map QDSS into IOMMU"); + goto unlock_and_end; + } + + iommu_cb_set.cb_info[idx].is_qdss_allocated = true; + + *iova = iommu_cb_set.cb_info[idx].qdss_info.iova_start; + *len = qdss_len; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return rc; + +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_alloc_qdss); + +int cam_smmu_dealloc_qdss(int32_t smmu_hdl) +{ + int rc = 0; + int32_t idx; + size_t qdss_len = 0; + size_t qdss_start = 0; + struct iommu_domain *domain; + size_t unmapped = 0; + + if (smmu_hdl == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].qdss_support) { + CAM_ERR(CAM_SMMU, + "QDSS memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (!iommu_cb_set.cb_info[idx].is_qdss_allocated) { + CAM_ERR(CAM_SMMU, + "Trying to deallocate qdss that is not allocated"); + rc = -ENOMEM; + goto unlock_and_end; + } + + qdss_len = iommu_cb_set.cb_info[idx].qdss_info.iova_len; + qdss_start = iommu_cb_set.cb_info[idx].qdss_info.iova_start; + domain = iommu_cb_set.cb_info[idx].domain; + unmapped = iommu_unmap(domain, qdss_start, qdss_len); + + if (unmapped != qdss_len) { + CAM_ERR(CAM_SMMU, "Only %zu unmapped out of total %zu", + unmapped, + qdss_len); + rc = -EINVAL; + } + + iommu_cb_set.cb_info[idx].is_qdss_allocated = false; + +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_dealloc_qdss); + +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len) +{ + int32_t idx; + + if (!iova || !len || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].io_support) { + CAM_ERR(CAM_SMMU, + "I/O memory not supported for this SMMU handle"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + *iova = iommu_cb_set.cb_info[idx].io_info.iova_start; + *len = iommu_cb_set.cb_info[idx].io_info.iova_len; + + CAM_DBG(CAM_SMMU, + "I/O area for hdl = %x start addr = %pK len = %zu", + smmu_hdl, *iova, *len); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return 0; +} + +int cam_smmu_get_region_info(int32_t smmu_hdl, + enum cam_smmu_region_id region_id, + struct cam_smmu_region_info *region_info) +{ + int32_t idx; + struct cam_context_bank_info *cb = NULL; + + if (!region_info) { + CAM_ERR(CAM_SMMU, "Invalid region_info pointer"); + return -EINVAL; + } + + if (smmu_hdl == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "Handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + cb = &iommu_cb_set.cb_info[idx]; + if (!cb) { + CAM_ERR(CAM_SMMU, "SMMU context bank pointer invalid"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + switch (region_id) { + case CAM_SMMU_REGION_FIRMWARE: + if (!cb->firmware_support) { + CAM_ERR(CAM_SMMU, "Firmware not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->firmware_info.iova_start; + region_info->iova_len = cb->firmware_info.iova_len; + break; + case CAM_SMMU_REGION_SHARED: + if (!cb->shared_support) { + CAM_ERR(CAM_SMMU, "Shared mem not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->shared_info.iova_start; + region_info->iova_len = cb->shared_info.iova_len; + break; + case CAM_SMMU_REGION_SCRATCH: + if (!cb->scratch_buf_support) { + CAM_ERR(CAM_SMMU, "Scratch memory not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->scratch_info.iova_start; + region_info->iova_len = cb->scratch_info.iova_len; + break; + case CAM_SMMU_REGION_IO: + if (!cb->io_support) { + CAM_ERR(CAM_SMMU, "IO memory not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->io_info.iova_start; + region_info->iova_len = cb->io_info.iova_len; + break; + case CAM_SMMU_REGION_SECHEAP: + if (!cb->secheap_support) { + CAM_ERR(CAM_SMMU, "Secondary heap not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->secheap_info.iova_start; + region_info->iova_len = cb->secheap_info.iova_len; + break; + default: + CAM_ERR(CAM_SMMU, "Invalid region id: %d for smmu hdl: %X", + smmu_hdl, region_id); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; +} +EXPORT_SYMBOL(cam_smmu_get_region_info); + +int cam_smmu_reserve_sec_heap(int32_t smmu_hdl, + struct dma_buf *buf, + dma_addr_t *iova, + size_t *request_len) +{ + struct secheap_buf_info *secheap_buf = NULL; + size_t size = 0; + uint32_t sec_heap_iova = 0; + size_t sec_heap_iova_len = 0; + int idx; + int rc = 0; + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].secheap_support) { + CAM_ERR(CAM_SMMU, "Secondary heap not supported"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + + if (iommu_cb_set.cb_info[idx].is_secheap_allocated) { + CAM_ERR(CAM_SMMU, "Trying to allocate secheap twice"); + rc = -ENOMEM; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; + } + + if (IS_ERR_OR_NULL(buf)) { + rc = PTR_ERR(buf); + CAM_ERR(CAM_SMMU, + "Error: dma get buf failed. rc = %d", rc); + goto err_out; + } + + secheap_buf = &iommu_cb_set.cb_info[idx].secheap_buf; + secheap_buf->buf = buf; + secheap_buf->attach = dma_buf_attach(secheap_buf->buf, + iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(secheap_buf->attach)) { + rc = PTR_ERR(secheap_buf->attach); + CAM_ERR(CAM_SMMU, "Error: dma buf attach failed"); + goto err_put; + } + + secheap_buf->table = dma_buf_map_attachment(secheap_buf->attach, + DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(secheap_buf->table)) { + rc = PTR_ERR(secheap_buf->table); + CAM_ERR(CAM_SMMU, "Error: dma buf map attachment failed"); + goto err_detach; + } + + sec_heap_iova = iommu_cb_set.cb_info[idx].secheap_info.iova_start; + sec_heap_iova_len = iommu_cb_set.cb_info[idx].secheap_info.iova_len; + size = iommu_map_sg(iommu_cb_set.cb_info[idx].domain, + sec_heap_iova, + secheap_buf->table->sgl, + secheap_buf->table->nents, + IOMMU_READ | IOMMU_WRITE); + if (size != sec_heap_iova_len) { + CAM_ERR(CAM_SMMU, "IOMMU mapping failed"); + goto err_unmap_sg; + } + + iommu_cb_set.cb_info[idx].is_secheap_allocated = true; + *iova = (uint32_t)sec_heap_iova; + *request_len = sec_heap_iova_len; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return rc; + +err_unmap_sg: + dma_buf_unmap_attachment(secheap_buf->attach, + secheap_buf->table, + DMA_BIDIRECTIONAL); +err_detach: + dma_buf_detach(secheap_buf->buf, + secheap_buf->attach); +err_put: + dma_buf_put(secheap_buf->buf); +err_out: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_reserve_sec_heap); + +int cam_smmu_release_sec_heap(int32_t smmu_hdl) +{ + int idx; + size_t size = 0; + uint32_t sec_heap_iova = 0; + size_t sec_heap_iova_len = 0; + struct secheap_buf_info *secheap_buf = NULL; + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].secheap_support) { + CAM_ERR(CAM_SMMU, "Secondary heap not supported"); + return -EINVAL; + } + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + + if (!iommu_cb_set.cb_info[idx].is_secheap_allocated) { + CAM_ERR(CAM_SMMU, "Trying to release secheap twice"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENOMEM; + } + + secheap_buf = &iommu_cb_set.cb_info[idx].secheap_buf; + sec_heap_iova = iommu_cb_set.cb_info[idx].secheap_info.iova_start; + sec_heap_iova_len = iommu_cb_set.cb_info[idx].secheap_info.iova_len; + + size = iommu_unmap(iommu_cb_set.cb_info[idx].domain, + sec_heap_iova, + sec_heap_iova_len); + if (size != sec_heap_iova_len) { + CAM_ERR(CAM_SMMU, "Failed: Unmapped = %zu, requested = %zu", + size, + sec_heap_iova_len); + } + + dma_buf_unmap_attachment(secheap_buf->attach, + secheap_buf->table, DMA_BIDIRECTIONAL); + dma_buf_detach(secheap_buf->buf, secheap_buf->attach); + dma_buf_put(secheap_buf->buf); + iommu_cb_set.cb_info[idx].is_secheap_allocated = false; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return 0; +} +EXPORT_SYMBOL(cam_smmu_release_sec_heap); + +static int cam_smmu_map_buffer_validate(struct dma_buf *buf, + int idx, enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id, + struct cam_dma_buff_info **mapping_info) +{ + struct dma_buf_attachment *attach = NULL; + struct sg_table *table = NULL; + struct iommu_domain *domain; + size_t size = 0; + uint32_t iova = 0; + int rc = 0; + + if (IS_ERR_OR_NULL(buf)) { + rc = PTR_ERR(buf); + CAM_ERR(CAM_SMMU, + "Error: dma get buf failed. rc = %d", rc); + goto err_out; + } + + if (!mapping_info) { + rc = -EINVAL; + CAM_ERR(CAM_SMMU, "Error: mapping_info is invalid"); + goto err_out; + } + + attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach); + CAM_ERR(CAM_SMMU, "Error: dma buf attach failed"); + goto err_put; + } + + if (region_id == CAM_SMMU_REGION_SHARED) { + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table); + CAM_ERR(CAM_SMMU, "Error: dma map attachment failed"); + goto err_detach; + } + + domain = iommu_cb_set.cb_info[idx].domain; + if (!domain) { + CAM_ERR(CAM_SMMU, "CB has no domain set"); + goto err_unmap_sg; + } + + rc = cam_smmu_alloc_iova(*len_ptr, + iommu_cb_set.cb_info[idx].handle, + &iova); + + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "IOVA alloc failed for shared memory, size=%zu, idx=%d, handle=%d", + *len_ptr, idx, + iommu_cb_set.cb_info[idx].handle); + goto err_unmap_sg; + } + + size = iommu_map_sg(domain, iova, table->sgl, table->nents, + IOMMU_READ | IOMMU_WRITE); + + if (size < 0) { + CAM_ERR(CAM_SMMU, "IOMMU mapping failed"); + rc = cam_smmu_free_iova(iova, + size, iommu_cb_set.cb_info[idx].handle); + if (rc) + CAM_ERR(CAM_SMMU, "IOVA free failed"); + rc = -ENOMEM; + goto err_unmap_sg; + } else { + CAM_DBG(CAM_SMMU, + "iommu_map_sg returned iova=%pK, size=%zu", + iova, size); + *paddr_ptr = iova; + *len_ptr = size; + } + } else if (region_id == CAM_SMMU_REGION_IO) { + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table); + CAM_ERR(CAM_SMMU, "Error: dma map attachment failed"); + goto err_detach; + } + + *paddr_ptr = sg_dma_address(table->sgl); + *len_ptr = (size_t)buf->size; + } else { + CAM_ERR(CAM_SMMU, "Error: Wrong region id passed"); + rc = -EINVAL; + goto err_unmap_sg; + } + + CAM_DBG(CAM_SMMU, "iova=%pK, region_id=%d, paddr=%pK, len=%d", + iova, region_id, *paddr_ptr, *len_ptr); + + if (table->sgl) { + CAM_DBG(CAM_SMMU, + "DMA buf: %pK, device: %pK, attach: %pK, table: %pK", + (void *)buf, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)attach, (void *)table); + CAM_DBG(CAM_SMMU, "table sgl: %pK, rc: %d, dma_address: 0x%x", + (void *)table->sgl, rc, + (unsigned int)table->sgl->dma_address); + } else { + rc = -EINVAL; + CAM_ERR(CAM_SMMU, "Error: table sgl is null"); + goto err_unmap_sg; + } + + /* fill up mapping_info */ + *mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); + if (!(*mapping_info)) { + rc = -ENOSPC; + goto err_alloc; + } + + (*mapping_info)->buf = buf; + (*mapping_info)->attach = attach; + (*mapping_info)->table = table; + (*mapping_info)->paddr = *paddr_ptr; + (*mapping_info)->len = *len_ptr; + (*mapping_info)->dir = dma_dir; + (*mapping_info)->ref_count = 1; + (*mapping_info)->region_id = region_id; + + if (!*paddr_ptr || !*len_ptr) { + CAM_ERR(CAM_SMMU, "Error: Space Allocation failed"); + kfree(*mapping_info); + *mapping_info = NULL; + rc = -ENOSPC; + goto err_alloc; + } + CAM_DBG(CAM_SMMU, "idx=%d, dma_buf=%pK, dev=%pK, paddr=%pK, len=%u", + idx, buf, (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + return 0; + +err_alloc: + if (region_id == CAM_SMMU_REGION_SHARED) { + cam_smmu_free_iova(iova, + size, + iommu_cb_set.cb_info[idx].handle); + + iommu_unmap(iommu_cb_set.cb_info[idx].domain, + *paddr_ptr, + *len_ptr); + } +err_unmap_sg: + dma_buf_unmap_attachment(attach, table, dma_dir); +err_detach: + dma_buf_detach(buf, attach); +err_put: + dma_buf_put(buf); +err_out: + return rc; +} + + +static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, + enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id) +{ + int rc = -1; + struct cam_dma_buff_info *mapping_info = NULL; + struct dma_buf *buf = NULL; + + /* returns the dma_buf structure related to an fd */ + buf = dma_buf_get(ion_fd); + + rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, + region_id, &mapping_info); + + if (rc) { + CAM_ERR(CAM_SMMU, "buffer validation failure"); + return rc; + } + + mapping_info->ion_fd = ion_fd; + /* add to the list */ + list_add(&mapping_info->list, + &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return 0; +} + +static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, + struct dma_buf *buf, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id) +{ + int rc = -1; + struct cam_dma_buff_info *mapping_info = NULL; + + rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, + region_id, &mapping_info); + + if (rc) { + CAM_ERR(CAM_SMMU, "buffer validation failure"); + return rc; + } + + mapping_info->ion_fd = -1; + + /* add to the list */ + list_add(&mapping_info->list, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list); + + return 0; +} + + +static int cam_smmu_unmap_buf_and_remove_from_list( + struct cam_dma_buff_info *mapping_info, + int idx) +{ + int rc; + size_t size; + struct iommu_domain *domain; + + if ((!mapping_info->buf) || (!mapping_info->table) || + (!mapping_info->attach)) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params dev = %pK, table = %pK", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)mapping_info->table); + CAM_ERR(CAM_SMMU, "Error:dma_buf = %pK, attach = %pK", + (void *)mapping_info->buf, + (void *)mapping_info->attach); + return -EINVAL; + } + + if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) { + CAM_DBG(CAM_SMMU, + "Removing SHARED buffer paddr = %pK, len = %zu", + (void *)mapping_info->paddr, mapping_info->len); + + domain = iommu_cb_set.cb_info[idx].domain; + + size = iommu_unmap(domain, + mapping_info->paddr, + mapping_info->len); + + if (size != mapping_info->len) { + CAM_ERR(CAM_SMMU, "IOMMU unmap failed"); + CAM_ERR(CAM_SMMU, "Unmapped = %zu, requested = %zu", + size, + mapping_info->len); + } + + rc = cam_smmu_free_iova(mapping_info->paddr, + mapping_info->len, + iommu_cb_set.cb_info[idx].handle); + + if (rc) + CAM_ERR(CAM_SMMU, "IOVA free failed"); + + } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) { + mapping_info->attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + } + + dma_buf_unmap_attachment(mapping_info->attach, + mapping_info->table, mapping_info->dir); + dma_buf_detach(mapping_info->buf, mapping_info->attach); + dma_buf_put(mapping_info->buf); + + mapping_info->buf = NULL; + + list_del_init(&mapping_info->list); + + /* free one buffer */ + kfree(mapping_info); + return 0; +} + +static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx, + int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + struct cam_dma_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + if (mapping->ion_fd == ion_fd) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +static enum cam_smmu_buf_state cam_smmu_check_dma_buf_in_list(int idx, + struct dma_buf *buf, dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + struct cam_dma_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, list) { + if (mapping->buf == buf) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +static enum cam_smmu_buf_state cam_smmu_check_secure_fd_in_list(int idx, + int ion_fd, dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + mapping->ref_count++; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +static enum cam_smmu_buf_state cam_smmu_validate_secure_fd_in_list(int idx, + int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +int cam_smmu_get_handle(char *identifier, int *handle_ptr) +{ + int ret = 0; + + if (!identifier) { + CAM_ERR(CAM_SMMU, "Error: iommu hardware name is NULL"); + return -EINVAL; + } + + if (!handle_ptr) { + CAM_ERR(CAM_SMMU, "Error: handle pointer is NULL"); + return -EINVAL; + } + + /* create and put handle in the table */ + ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr); + if (ret < 0) + CAM_ERR(CAM_SMMU, "Error: %s get handle fail", identifier); + + return ret; +} +EXPORT_SYMBOL(cam_smmu_get_handle); + +int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops) +{ + int ret = 0, idx; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "Error: Index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + switch (ops) { + case CAM_SMMU_ATTACH: { + ret = cam_smmu_attach(idx); + break; + } + case CAM_SMMU_DETACH: { + ret = cam_smmu_detach_device(idx); + break; + } + case CAM_SMMU_VOTE: + case CAM_SMMU_DEVOTE: + default: + CAM_ERR(CAM_SMMU, "Error: idx = %d, ops = %d", idx, ops); + ret = -EINVAL; + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return ret; +} +EXPORT_SYMBOL(cam_smmu_ops); + +static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx, + size_t virt_len, + size_t phys_len, + unsigned int iommu_dir, + dma_addr_t *virt_addr) +{ + unsigned long nents = virt_len / phys_len; + struct cam_dma_buff_info *mapping_info = NULL; + size_t unmapped; + dma_addr_t iova = 0; + struct scatterlist *sg; + int i = 0; + int rc; + struct iommu_domain *domain = NULL; + struct page *page; + struct sg_table *table = NULL; + + CAM_DBG(CAM_SMMU, "nents = %lu, idx = %d, virt_len = %zx", + nents, idx, virt_len); + CAM_DBG(CAM_SMMU, "phys_len = %zx, iommu_dir = %d, virt_addr = %pK", + phys_len, iommu_dir, virt_addr); + + /* + * This table will go inside the 'mapping' structure + * where it will be held until put_scratch_buffer is called + */ + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!table) { + rc = -ENOMEM; + goto err_table_alloc; + } + + rc = sg_alloc_table(table, nents, GFP_KERNEL); + if (rc < 0) { + rc = -EINVAL; + goto err_sg_alloc; + } + + page = alloc_pages(GFP_KERNEL, get_order(phys_len)); + if (!page) { + rc = -ENOMEM; + goto err_page_alloc; + } + + /* Now we create the sg list */ + for_each_sg(table->sgl, sg, table->nents, i) + sg_set_page(sg, page, phys_len, 0); + + + /* Get the domain from within our cb_set struct and map it*/ + domain = iommu_cb_set.cb_info[idx].domain; + + rc = cam_smmu_alloc_scratch_va(&iommu_cb_set.cb_info[idx].scratch_map, + virt_len, &iova); + + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Could not find valid iova for scratch buffer"); + goto err_iommu_map; + } + + if (iommu_map_sg(domain, + iova, + table->sgl, + table->nents, + iommu_dir) != virt_len) { + CAM_ERR(CAM_SMMU, "iommu_map_sg() failed"); + goto err_iommu_map; + } + + /* Now update our mapping information within the cb_set struct */ + mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); + if (!mapping_info) { + rc = -ENOMEM; + goto err_mapping_info; + } + + mapping_info->ion_fd = 0xDEADBEEF; + mapping_info->buf = NULL; + mapping_info->attach = NULL; + mapping_info->table = table; + mapping_info->paddr = iova; + mapping_info->len = virt_len; + mapping_info->iommu_dir = iommu_dir; + mapping_info->ref_count = 1; + mapping_info->phys_len = phys_len; + mapping_info->region_id = CAM_SMMU_REGION_SCRATCH; + + CAM_DBG(CAM_SMMU, "paddr = %pK, len = %zx, phys_len = %zx", + (void *)mapping_info->paddr, + mapping_info->len, mapping_info->phys_len); + + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + *virt_addr = (dma_addr_t)iova; + + CAM_DBG(CAM_SMMU, "mapped virtual address = %lx", + (unsigned long)*virt_addr); + return 0; + +err_mapping_info: + unmapped = iommu_unmap(domain, iova, virt_len); + if (unmapped != virt_len) + CAM_ERR(CAM_SMMU, "Unmapped only %zx instead of %zx", + unmapped, virt_len); +err_iommu_map: + __free_pages(page, get_order(phys_len)); +err_page_alloc: + sg_free_table(table); +err_sg_alloc: + kfree(table); +err_table_alloc: + return rc; +} + +static int cam_smmu_free_scratch_buffer_remove_from_list( + struct cam_dma_buff_info *mapping_info, + int idx) +{ + int rc = 0; + size_t unmapped; + struct iommu_domain *domain = + iommu_cb_set.cb_info[idx].domain; + struct scratch_mapping *scratch_map = + &iommu_cb_set.cb_info[idx].scratch_map; + + if (!mapping_info->table) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params: dev = %pK, table = %pK", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)mapping_info->table); + return -EINVAL; + } + + /* Clean up the mapping_info struct from the list */ + unmapped = iommu_unmap(domain, mapping_info->paddr, mapping_info->len); + if (unmapped != mapping_info->len) + CAM_ERR(CAM_SMMU, "Unmapped only %zx instead of %zx", + unmapped, mapping_info->len); + + rc = cam_smmu_free_scratch_va(scratch_map, + mapping_info->paddr, + mapping_info->len); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: Invalid iova while freeing scratch buffer"); + rc = -EINVAL; + } + + __free_pages(sg_page(mapping_info->table->sgl), + get_order(mapping_info->phys_len)); + sg_free_table(mapping_info->table); + kfree(mapping_info->table); + list_del_init(&mapping_info->list); + + kfree(mapping_info); + mapping_info = NULL; + + return rc; +} + +int cam_smmu_get_scratch_iova(int handle, + enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, + size_t virt_len, + size_t phys_len) +{ + int idx, rc; + unsigned int iommu_dir; + + if (!paddr_ptr || !virt_len || !phys_len) { + CAM_ERR(CAM_SMMU, "Error: Input pointer or lengths invalid"); + return -EINVAL; + } + + if (virt_len < phys_len) { + CAM_ERR(CAM_SMMU, "Error: virt_len > phys_len"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + iommu_dir = cam_smmu_translate_dir_to_iommu_dir(dir); + if (iommu_dir == IOMMU_INVALID_DIR) { + CAM_ERR(CAM_SMMU, + "Error: translate direction failed. dir = %d", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto error; + } + + if (!iommu_cb_set.cb_info[idx].scratch_buf_support) { + CAM_ERR(CAM_SMMU, + "Error: Context bank does not support scratch bufs"); + rc = -EINVAL; + goto error; + } + + CAM_DBG(CAM_SMMU, "smmu handle = %x, idx = %d, dir = %d", + handle, idx, dir); + CAM_DBG(CAM_SMMU, "virt_len = %zx, phys_len = %zx", + phys_len, virt_len); + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + CAM_ERR(CAM_SMMU, + "Err:Dev %s should call SMMU attach before map buffer", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto error; + } + + if (!IS_ALIGNED(virt_len, PAGE_SIZE)) { + CAM_ERR(CAM_SMMU, + "Requested scratch buffer length not page aligned"); + rc = -EINVAL; + goto error; + } + + if (!IS_ALIGNED(virt_len, phys_len)) { + CAM_ERR(CAM_SMMU, + "Requested virt length not aligned with phys length"); + rc = -EINVAL; + goto error; + } + + rc = cam_smmu_alloc_scratch_buffer_add_to_list(idx, + virt_len, + phys_len, + iommu_dir, + paddr_ptr); + if (rc < 0) + CAM_ERR(CAM_SMMU, "Error: mapping or add list fail"); + +error: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +int cam_smmu_put_scratch_iova(int handle, + dma_addr_t paddr) +{ + int idx; + int rc = -1; + struct cam_dma_buff_info *mapping_info; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto handle_err; + } + + if (!iommu_cb_set.cb_info[idx].scratch_buf_support) { + CAM_ERR(CAM_SMMU, + "Error: Context bank does not support scratch buffers"); + rc = -EINVAL; + goto handle_err; + } + + /* Based on virtual address and index, we can find mapping info + * of the scratch buffer + */ + mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr); + if (!mapping_info) { + CAM_ERR(CAM_SMMU, "Error: Invalid params"); + rc = -ENODEV; + goto handle_err; + } + + /* unmapping one buffer from device */ + rc = cam_smmu_free_scratch_buffer_remove_from_list(mapping_info, idx); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + goto handle_err; + } + +handle_err: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd, + enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int rc = 0; + struct dma_buf *dmabuf = NULL; + struct dma_buf_attachment *attach = NULL; + struct sg_table *table = NULL; + struct cam_sec_buff_info *mapping_info; + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + dmabuf = dma_buf_get(ion_fd); + if (IS_ERR_OR_NULL((void *)(dmabuf))) { + CAM_ERR(CAM_SMMU, + "Error: dma buf get failed, idx=%d, ion_fd=%d", + idx, ion_fd); + rc = PTR_ERR(dmabuf); + goto err_out; + } + + /* + * ion_phys() is deprecated. call dma_buf_attach() and + * dma_buf_map_attachment() to get the buffer's physical + * address. + */ + attach = dma_buf_attach(dmabuf, iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(attach)) { + CAM_ERR(CAM_SMMU, + "Error: dma buf attach failed, idx=%d, ion_fd=%d", + idx, ion_fd); + rc = PTR_ERR(attach); + goto err_put; + } + + attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + CAM_ERR(CAM_SMMU, "Error: dma buf map attachment failed"); + rc = PTR_ERR(table); + goto err_detach; + } + + /* return addr and len to client */ + *paddr_ptr = sg_phys(table->sgl); + *len_ptr = (size_t)sg_dma_len(table->sgl); + + /* fill up mapping_info */ + mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL); + if (!mapping_info) { + rc = -ENOMEM; + goto err_unmap_sg; + } + + mapping_info->ion_fd = ion_fd; + mapping_info->paddr = *paddr_ptr; + mapping_info->len = *len_ptr; + mapping_info->dir = dma_dir; + mapping_info->ref_count = 1; + mapping_info->buf = dmabuf; + + CAM_DBG(CAM_SMMU, "idx=%d, ion_fd=%d, dev=%pK, paddr=%pK, len=%u", + idx, ion_fd, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + /* add to the list */ + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return 0; + +err_unmap_sg: + dma_buf_unmap_attachment(attach, table, dma_dir); +err_detach: + dma_buf_detach(dmabuf, attach); +err_put: + dma_buf_put(dmabuf); +err_out: + return rc; +} + +int cam_smmu_map_stage2_iova(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + int idx, rc; + enum dma_data_direction dma_dir; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, + "Error: Invalid inputs, paddr_ptr:%pK, len_ptr: %pK", + paddr_ptr, len_ptr); + return -EINVAL; + } + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + CAM_ERR(CAM_SMMU, + "Error: translate direction failed. dir = %d", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if ((handle == HANDLE_INIT) || + (idx < 0) || + (idx >= iommu_cb_set.cb_num)) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't map secure mem to non secure cb, idx=%d", + idx); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, idx=%d, table_hdl=%x, hdl=%x", + idx, iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_secure_fd_in_list(idx, ion_fd, paddr_ptr, + len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CAM_DBG(CAM_SMMU, + "fd:%d already in list idx:%d, handle=%d give same addr back", + ion_fd, idx, handle); + rc = 0; + goto get_addr_end; + } + rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir, + paddr_ptr, len_ptr); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: mapping or add list fail, idx=%d, handle=%d, fd=%d, rc=%d", + idx, handle, ion_fd, rc); + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_map_stage2_iova); + +static int cam_smmu_secure_unmap_buf_and_remove_from_list( + struct cam_sec_buff_info *mapping_info, + int idx) +{ + if (!mapping_info) { + CAM_ERR(CAM_SMMU, "Error: List doesn't exist"); + return -EINVAL; + } + dma_buf_put(mapping_info->buf); + list_del_init(&mapping_info->list); + + CAM_DBG(CAM_SMMU, "unmap fd: %d, idx : %d", mapping_info->ion_fd, idx); + + /* free one buffer */ + kfree(mapping_info); + return 0; +} + +int cam_smmu_unmap_stage2_iova(int handle, int ion_fd) +{ + int idx, rc; + struct cam_sec_buff_info *mapping_info; + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if ((handle == HANDLE_INIT) || + (idx < 0) || + (idx >= iommu_cb_set.cb_num)) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't unmap secure mem from non secure cb"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto put_addr_end; + } + + /* based on ion fd and index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd); + if (!mapping_info) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params! idx = %d, fd = %d", + idx, ion_fd); + rc = -EINVAL; + goto put_addr_end; + } + + mapping_info->ref_count--; + if (mapping_info->ref_count > 0) { + CAM_DBG(CAM_SMMU, + "idx: %d fd = %d ref_count: %d", + idx, ion_fd, mapping_info->ref_count); + rc = 0; + goto put_addr_end; + } + mapping_info->ref_count = 0; + + /* unmapping one buffer from device */ + rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc) { + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + goto put_addr_end; + } + +put_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_unmap_stage2_iova); + +static int cam_smmu_map_iova_validate_params(int handle, + enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id) +{ + int idx, rc = 0; + enum dma_data_direction dma_dir; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, "Input pointers are invalid"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Invalid handle"); + return -EINVAL; + } + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + if (region_id != CAM_SMMU_REGION_SHARED) + *len_ptr = (size_t)0; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + CAM_ERR(CAM_SMMU, "translate direction failed. dir = %d", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + return rc; +} + +int cam_smmu_map_user_iova(int handle, int ion_fd, + enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + enum dma_data_direction dma_dir; + + rc = cam_smmu_map_iova_validate_params(handle, dir, paddr_ptr, + len_ptr, region_id); + if (rc) { + CAM_ERR(CAM_SMMU, "initial checks failed, unable to proceed"); + return rc; + } + + dma_dir = (enum dma_data_direction)dir; + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't map non-secure mem to secure cb idx=%d", + idx); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "hdl is not valid, idx=%d, table_hdl = %x, hdl = %x", + idx, iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + CAM_ERR(CAM_SMMU, + "Err:Dev %s should call SMMU attach before map buffer", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CAM_ERR(CAM_SMMU, + "fd:%d already in list idx:%d, handle=%d, give same addr back", + ion_fd, idx, handle); + rc = -EALREADY; + goto get_addr_end; + } + + rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir, + paddr_ptr, len_ptr, region_id); + if (rc < 0) + CAM_ERR(CAM_SMMU, + "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d", + idx, ion_fd, region_id, rc); + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_map_user_iova); + +int cam_smmu_map_kernel_iova(int handle, struct dma_buf *buf, + enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + enum dma_data_direction dma_dir; + + rc = cam_smmu_map_iova_validate_params(handle, dir, paddr_ptr, + len_ptr, region_id); + if (rc) { + CAM_ERR(CAM_SMMU, "initial checks failed, unable to proceed"); + return rc; + } + + dma_dir = cam_smmu_translate_dir(dir); + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't map non-secure mem to secure cb"); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, "hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + CAM_ERR(CAM_SMMU, + "Err:Dev %s should call SMMU attach before map buffer", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_dma_buf_in_list(idx, buf, + paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CAM_ERR(CAM_SMMU, + "dma_buf :%pK already in the list", buf); + rc = -EALREADY; + goto get_addr_end; + } + + rc = cam_smmu_map_kernel_buffer_and_add_to_list(idx, buf, dma_dir, + paddr_ptr, len_ptr, region_id); + if (rc < 0) + CAM_ERR(CAM_SMMU, "mapping or add list fail"); + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_map_kernel_iova); + +int cam_smmu_get_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, "Error: Input pointers are invalid"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't get non-secure mem from secure cb"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { + CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); + rc = -EINVAL; + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_get_iova); + +int cam_smmu_get_stage2_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, "Error: Input pointers are invalid"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't get secure mem from non secure cb"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_validate_secure_fd_in_list(idx, + ion_fd, + paddr_ptr, + len_ptr); + + if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { + CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); + rc = -EINVAL; + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_get_stage2_iova); + +static int cam_smmu_unmap_validate_params(int handle) +{ + int idx; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + return 0; +} + +int cam_smmu_unmap_user_iova(int handle, + int ion_fd, enum cam_smmu_region_id region_id) +{ + int idx, rc; + struct cam_dma_buff_info *mapping_info; + + rc = cam_smmu_unmap_validate_params(handle); + if (rc) { + CAM_ERR(CAM_SMMU, "unmap util validation failure"); + return rc; + } + + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't unmap non-secure mem from secure cb"); + rc = -EINVAL; + goto unmap_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto unmap_end; + } + + /* Based on ion_fd & index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd); + + if (!mapping_info) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params idx = %d, fd = %d", + idx, ion_fd); + rc = -EINVAL; + goto unmap_end; + } + + /* Unmapping one buffer from device */ + CAM_DBG(CAM_SMMU, "SMMU: removing buffer idx = %d", idx); + rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + +unmap_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_unmap_user_iova); + +int cam_smmu_unmap_kernel_iova(int handle, + struct dma_buf *buf, enum cam_smmu_region_id region_id) +{ + int idx, rc; + struct cam_dma_buff_info *mapping_info; + + rc = cam_smmu_unmap_validate_params(handle); + if (rc) { + CAM_ERR(CAM_SMMU, "unmap util validation failure"); + return rc; + } + + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't unmap non-secure mem from secure cb"); + rc = -EINVAL; + goto unmap_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto unmap_end; + } + + /* Based on dma_buf & index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_dma_buf(idx, buf); + + if (!mapping_info) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params idx = %d, dma_buf = %pK", + idx, buf); + rc = -EINVAL; + goto unmap_end; + } + + /* Unmapping one buffer from device */ + CAM_DBG(CAM_SMMU, "SMMU: removing buffer idx = %d", idx); + rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + +unmap_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_unmap_kernel_iova); + + +int cam_smmu_put_iova(int handle, int ion_fd) +{ + int idx; + int rc = 0; + struct cam_dma_buff_info *mapping_info; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto put_addr_end; + } + + /* based on ion fd and index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd); + if (!mapping_info) { + CAM_ERR(CAM_SMMU, "Error: Invalid params idx = %d, fd = %d", + idx, ion_fd); + rc = -EINVAL; + goto put_addr_end; + } + +put_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_put_iova); + +int cam_smmu_destroy_handle(int handle) +{ + int idx; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) { + CAM_ERR(CAM_SMMU, "UMD %s buffer list is not clean", + iommu_cb_set.cb_info[idx].name); + cam_smmu_print_user_list(idx); + cam_smmu_clean_user_buffer_list(idx); + } + + if (!list_empty_careful( + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list)) { + CAM_ERR(CAM_SMMU, "KMD %s buffer list is not clean", + iommu_cb_set.cb_info[idx].name); + cam_smmu_print_kernel_list(idx); + cam_smmu_clean_kernel_buffer_list(idx); + } + + if (iommu_cb_set.cb_info[idx].is_secure) { + if (iommu_cb_set.cb_info[idx].secure_count == 0) { + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EPERM; + } + + iommu_cb_set.cb_info[idx].secure_count--; + if (iommu_cb_set.cb_info[idx].secure_count == 0) { + iommu_cb_set.cb_info[idx].cb_count = 0; + iommu_cb_set.cb_info[idx].handle = HANDLE_INIT; + } + + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; + } + + iommu_cb_set.cb_info[idx].cb_count = 0; + iommu_cb_set.cb_info[idx].handle = HANDLE_INIT; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; +} +EXPORT_SYMBOL(cam_smmu_destroy_handle); + +static void cam_smmu_deinit_cb(struct cam_context_bank_info *cb) +{ + if (cb->io_support && cb->domain) { + cb->domain = NULL; + } + + if (cb->shared_support) { + gen_pool_destroy(cb->shared_mem_pool); + cb->shared_mem_pool = NULL; + } + + if (cb->scratch_buf_support) { + kfree(cb->scratch_map.bitmap); + cb->scratch_map.bitmap = NULL; + } +} + +static void cam_smmu_release_cb(struct platform_device *pdev) +{ + int i = 0; + + for (i = 0; i < iommu_cb_set.cb_num; i++) + cam_smmu_deinit_cb(&iommu_cb_set.cb_info[i]); + + devm_kfree(&pdev->dev, iommu_cb_set.cb_info); + iommu_cb_set.cb_num = 0; +} + +static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, + struct device *dev) +{ + int rc = 0; + + if (!cb || !dev) { + CAM_ERR(CAM_SMMU, "Error: invalid input params"); + return -EINVAL; + } + + cb->dev = dev; + cb->is_fw_allocated = false; + cb->is_secheap_allocated = false; + + /* Create a pool with 64K granularity for supporting shared memory */ + if (cb->shared_support) { + cb->shared_mem_pool = gen_pool_create( + SHARED_MEM_POOL_GRANULARITY, -1); + + if (!cb->shared_mem_pool) + return -ENOMEM; + + rc = gen_pool_add(cb->shared_mem_pool, + cb->shared_info.iova_start, + cb->shared_info.iova_len, + -1); + + CAM_DBG(CAM_SMMU, "Shared mem start->%lX", + (unsigned long)cb->shared_info.iova_start); + CAM_DBG(CAM_SMMU, "Shared mem len->%zu", + cb->shared_info.iova_len); + + if (rc) { + CAM_ERR(CAM_SMMU, "Genpool chunk creation failed"); + gen_pool_destroy(cb->shared_mem_pool); + cb->shared_mem_pool = NULL; + return rc; + } + } + + if (cb->scratch_buf_support) { + rc = cam_smmu_init_scratch_map(&cb->scratch_map, + cb->scratch_info.iova_start, + cb->scratch_info.iova_len, + 0); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: failed to create scratch map"); + rc = -ENODEV; + goto end; + } + } + + /* create a virtual mapping */ + if (cb->io_support) { + cb->domain = iommu_get_domain_for_dev(dev); + if (IS_ERR(cb->domain)) { + CAM_ERR(CAM_SMMU, "Error: create domain Failed"); + rc = -ENODEV; + goto end; + } + cb->state = CAM_SMMU_ATTACH; + } else { + CAM_ERR(CAM_SMMU, "Context bank does not have IO region"); + rc = -ENODEV; + goto end; + } + + return rc; +end: + if (cb->shared_support) { + gen_pool_destroy(cb->shared_mem_pool); + cb->shared_mem_pool = NULL; + } + + if (cb->scratch_buf_support) { + kfree(cb->scratch_map.bitmap); + cb->scratch_map.bitmap = NULL; + } + + return rc; +} + +static int cam_alloc_smmu_context_banks(struct device *dev) +{ + struct device_node *domains_child_node = NULL; + + if (!dev) { + CAM_ERR(CAM_SMMU, "Error: Invalid device"); + return -ENODEV; + } + + iommu_cb_set.cb_num = 0; + + /* traverse thru all the child nodes and increment the cb count */ + for_each_available_child_of_node(dev->of_node, domains_child_node) { + if (of_device_is_compatible(domains_child_node, + "qcom,msm-cam-smmu-cb")) + iommu_cb_set.cb_num++; + + if (of_device_is_compatible(domains_child_node, + "qcom,qsmmu-cam-cb")) + iommu_cb_set.cb_num++; + } + + if (iommu_cb_set.cb_num == 0) { + CAM_ERR(CAM_SMMU, "Error: no context banks present"); + return -ENOENT; + } + + /* allocate memory for the context banks */ + iommu_cb_set.cb_info = devm_kzalloc(dev, + iommu_cb_set.cb_num * sizeof(struct cam_context_bank_info), + GFP_KERNEL); + + if (!iommu_cb_set.cb_info) { + CAM_ERR(CAM_SMMU, "Error: cannot allocate context banks"); + return -ENOMEM; + } + + cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_INIT); + iommu_cb_set.cb_init_count = 0; + + CAM_DBG(CAM_SMMU, "no of context banks :%d", iommu_cb_set.cb_num); + return 0; +} + +static int cam_smmu_get_memory_regions_info(struct device_node *of_node, + struct cam_context_bank_info *cb) +{ + int rc = 0; + struct device_node *mem_map_node = NULL; + struct device_node *child_node = NULL; + const char *region_name; + int num_regions = 0; + + if (!of_node || !cb) { + CAM_ERR(CAM_SMMU, "Invalid argument(s)"); + return -EINVAL; + } + + mem_map_node = of_get_child_by_name(of_node, "iova-mem-map"); + cb->is_secure = of_property_read_bool(of_node, "qcom,secure-cb"); + + /* + * We always expect a memory map node, except when it is a secure + * context bank. + */ + if (!mem_map_node) { + if (cb->is_secure) + return 0; + CAM_ERR(CAM_SMMU, "iova-mem-map not present"); + return -EINVAL; + } + + for_each_available_child_of_node(mem_map_node, child_node) { + uint32_t region_start; + uint32_t region_len; + uint32_t region_id; + uint32_t qdss_region_phy_addr = 0; + + num_regions++; + rc = of_property_read_string(child_node, + "iova-region-name", ®ion_name); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "IOVA region not found"); + return -EINVAL; + } + + rc = of_property_read_u32(child_node, + "iova-region-start", ®ion_start); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "Failed to read iova-region-start"); + return -EINVAL; + } + + rc = of_property_read_u32(child_node, + "iova-region-len", ®ion_len); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "Failed to read iova-region-len"); + return -EINVAL; + } + + rc = of_property_read_u32(child_node, + "iova-region-id", ®ion_id); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "Failed to read iova-region-id"); + return -EINVAL; + } + + if (strcmp(region_name, qdss_region_name) == 0) { + rc = of_property_read_u32(child_node, + "qdss-phy-addr", &qdss_region_phy_addr); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, + "Failed to read qdss phy addr"); + return -EINVAL; + } + } + + switch (region_id) { + case CAM_SMMU_REGION_FIRMWARE: + cb->firmware_support = 1; + cb->firmware_info.iova_start = region_start; + cb->firmware_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_SHARED: + cb->shared_support = 1; + cb->shared_info.iova_start = region_start; + cb->shared_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_SCRATCH: + cb->scratch_buf_support = 1; + cb->scratch_info.iova_start = region_start; + cb->scratch_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_IO: + cb->io_support = 1; + cb->io_info.iova_start = region_start; + cb->io_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_SECHEAP: + cb->secheap_support = 1; + cb->secheap_info.iova_start = region_start; + cb->secheap_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_QDSS: + cb->qdss_support = 1; + cb->qdss_info.iova_start = region_start; + cb->qdss_info.iova_len = region_len; + cb->qdss_phy_addr = qdss_region_phy_addr; + break; + default: + CAM_ERR(CAM_SMMU, + "Incorrect region id present in DT file: %d", + region_id); + } + + CAM_DBG(CAM_SMMU, "Found label -> %s", cb->name); + CAM_DBG(CAM_SMMU, "Found region -> %s", region_name); + CAM_DBG(CAM_SMMU, "region_start -> %X", region_start); + CAM_DBG(CAM_SMMU, "region_len -> %X", region_len); + CAM_DBG(CAM_SMMU, "region_id -> %X", region_id); + } + of_node_put(mem_map_node); + + if (!num_regions) { + CAM_ERR(CAM_SMMU, + "No memory regions found, at least one needed"); + rc = -ENODEV; + } + + return rc; +} + +static int cam_populate_smmu_context_banks(struct device *dev, + enum cam_iommu_type type) +{ + int rc = 0; + struct cam_context_bank_info *cb; + struct device *ctx = NULL; + + if (!dev) { + CAM_ERR(CAM_SMMU, "Error: Invalid device"); + return -ENODEV; + } + + /* check the bounds */ + if (iommu_cb_set.cb_init_count >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "Error: populate more than allocated cb"); + rc = -EBADHANDLE; + goto cb_init_fail; + } + + /* read the context bank from cb set */ + cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count]; + + /* set the name of the context bank */ + rc = of_property_read_string(dev->of_node, "label", &cb->name); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: failed to read label from sub device"); + goto cb_init_fail; + } + + rc = cam_smmu_get_memory_regions_info(dev->of_node, + cb); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: Getting region info"); + return rc; + } + + if (cb->is_secure) { + /* increment count to next bank */ + cb->dev = dev; + iommu_cb_set.cb_init_count++; + return 0; + } + + /* set up the iommu mapping for the context bank */ + if (type == CAM_QSMMU) { + CAM_ERR(CAM_SMMU, "Error: QSMMU ctx not supported for : %s", + cb->name); + return -ENODEV; + } + + ctx = dev; + CAM_DBG(CAM_SMMU, "getting Arm SMMU ctx : %s", cb->name); + + rc = cam_smmu_setup_cb(cb, ctx); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: failed to setup cb : %s", cb->name); + goto cb_init_fail; + } + if (cb->io_support && cb->domain) + iommu_set_fault_handler(cb->domain, + cam_smmu_iommu_fault_handler, + (void *)cb->name); + /* increment count to next bank */ + iommu_cb_set.cb_init_count++; + + CAM_DBG(CAM_SMMU, "X: cb init count :%d", iommu_cb_set.cb_init_count); + +cb_init_fail: + return rc; +} + +static int cam_smmu_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device *dev = &pdev->dev; + + if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) { + rc = cam_alloc_smmu_context_banks(dev); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: allocating context banks"); + return -ENOMEM; + } + } + if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-cb")) { + rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: populating context banks"); + cam_smmu_release_cb(pdev); + return -ENOMEM; + } + return rc; + } + if (of_device_is_compatible(dev->of_node, "qcom,qsmmu-cam-cb")) { + rc = cam_populate_smmu_context_banks(dev, CAM_QSMMU); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: populating context banks"); + return -ENOMEM; + } + return rc; + } + + if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-fw-dev")) { + icp_fw.fw_dev = &pdev->dev; + icp_fw.fw_kva = NULL; + icp_fw.fw_dma_hdl = 0; + return rc; + } + + /* probe through all the subdevices */ + rc = of_platform_populate(pdev->dev.of_node, msm_cam_smmu_dt_match, + NULL, &pdev->dev); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: populating devices"); + } else { + INIT_WORK(&iommu_cb_set.smmu_work, cam_smmu_page_fault_work); + mutex_init(&iommu_cb_set.payload_list_lock); + INIT_LIST_HEAD(&iommu_cb_set.payload_list); + } + + return rc; +} + +static int cam_smmu_remove(struct platform_device *pdev) +{ + /* release all the context banks and memory allocated */ + cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT); + if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu")) + cam_smmu_release_cb(pdev); + return 0; +} + +static struct platform_driver cam_smmu_driver = { + .probe = cam_smmu_probe, + .remove = cam_smmu_remove, + .driver = { + .name = "msm_cam_smmu", + .owner = THIS_MODULE, + .of_match_table = msm_cam_smmu_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_smmu_init_module(void) +{ + return platform_driver_register(&cam_smmu_driver); +} + +static void __exit cam_smmu_exit_module(void) +{ + platform_driver_unregister(&cam_smmu_driver); +} + +module_init(cam_smmu_init_module); +module_exit(cam_smmu_exit_module); +MODULE_DESCRIPTION("MSM Camera SMMU driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_smmu/cam_smmu_api.h b/drivers/cam_smmu/cam_smmu_api.h new file mode 100644 index 000000000000..6932505f0aaf --- /dev/null +++ b/drivers/cam_smmu/cam_smmu_api.h @@ -0,0 +1,395 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SMMU_API_H_ +#define _CAM_SMMU_API_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*Enum for possible CAM SMMU operations */ +enum cam_smmu_ops_param { + CAM_SMMU_ATTACH, + CAM_SMMU_DETACH, + CAM_SMMU_VOTE, + CAM_SMMU_DEVOTE, + CAM_SMMU_OPS_INVALID +}; + +enum cam_smmu_map_dir { + CAM_SMMU_MAP_READ, + CAM_SMMU_MAP_WRITE, + CAM_SMMU_MAP_RW, + CAM_SMMU_MAP_INVALID +}; + +enum cam_smmu_region_id { + CAM_SMMU_REGION_FIRMWARE, + CAM_SMMU_REGION_SHARED, + CAM_SMMU_REGION_SCRATCH, + CAM_SMMU_REGION_IO, + CAM_SMMU_REGION_SECHEAP, + CAM_SMMU_REGION_QDSS +}; + +/** + * @brief : Callback function type that gets called back on cam + * smmu page fault. + * + * @param domain : Iommu domain received in iommu page fault handler + * @param dev : Device received in iommu page fault handler + * @param iova : IOVA where page fault occurred + * @param flags : Flags received in iommu page fault handler + * @param token : Userdata given during callback registration + * @param buf_info : Closest mapped buffer info + */ +typedef void (*cam_smmu_client_page_fault_handler)(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *token, + uint32_t buf_info); + +/** + * @brief : Structure to store region information + * + * @param iova_start : Start address of region + * @param iova_len : length of region + */ +struct cam_smmu_region_info { + dma_addr_t iova_start; + size_t iova_len; +}; + +/** + * @brief : Gets an smmu handle + * + * @param identifier: Unique identifier to be used by clients which they + * should get from device tree. CAM SMMU driver will + * not enforce how this string is obtained and will + * only validate this against the list of permitted + * identifiers + * @param handle_ptr: Based on the indentifier, CAM SMMU drivier will + * fill the handle pointed by handle_ptr + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_handle(char *identifier, int *handle_ptr); + +/** + * @brief : Performs IOMMU operations + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH + * or CAM_SMMU_DETACH + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); + +/** + * @brief : Maps user space IOVA for calling driver + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param ion_fd: ION handle identifying the memory buffer. + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE + * @dma_addr : Pointer to physical address where mapped address will be + * returned if region_id is CAM_SMMU_REGION_IO. If region_id is + * CAM_SMMU_REGION_SHARED, dma_addr is used as an input parameter + * which specifies the cpu virtual address to map. + * @len_ptr : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_map_user_iova(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + dma_addr_t *dma_addr, size_t *len_ptr, + enum cam_smmu_region_id region_id); + +/** + * @brief : Maps kernel space IOVA for calling driver + * + * @param handle : Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param buf : dma_buf allocated for kernel usage in mem_mgr + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE + * @dma_addr : Pointer to physical address where mapped address will be + * returned if region_id is CAM_SMMU_REGION_IO. If region_id is + * CAM_SMMU_REGION_SHARED, dma_addr is used as an input + * parameter which specifies the cpu virtual address to map. + * @len_ptr : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_map_kernel_iova(int handle, + struct dma_buf *buf, enum cam_smmu_map_dir dir, + dma_addr_t *dma_addr, size_t *len_ptr, + enum cam_smmu_region_id region_id); + +/** + * @brief : Unmaps user space IOVA for calling driver + * + * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param ion_fd: ION handle identifying the memory buffer. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_unmap_user_iova(int handle, + int ion_fd, enum cam_smmu_region_id region_id); + +/** + * @brief : Unmaps kernel IOVA for calling driver + * + * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param buf : dma_buf allocated for the kernel + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_unmap_kernel_iova(int handle, + struct dma_buf *buf, enum cam_smmu_region_id region_id); + +/** + * @brief : Allocates a scratch buffer + * + * This function allocates a scratch virtual buffer of length virt_len in the + * device virtual address space mapped to phys_len physically contiguous bytes + * in that device's SMMU. + * + * virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each + * other, otherwise -EINVAL is returned. + * + * -EINVAL will be returned if virt_len is less than phys_len. + * + * Passing a too large phys_len might also cause failure if that much size is + * not available for allocation in a physically contiguous way. + * + * @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param dir : Direction of mapping which will translate to IOMMU_READ + * IOMMU_WRITE or a bit mask of both. + * @param paddr_ptr: Device virtual address that the client device will be + * able to read from/write to + * @param virt_len : Virtual length of the scratch buffer + * @param phys_len : Physical length of the scratch buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ + +int cam_smmu_get_scratch_iova(int handle, + enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, + size_t virt_len, + size_t phys_len); + +/** + * @brief : Frees a scratch buffer + * + * This function frees a scratch buffer and releases the corresponding SMMU + * mappings. + * + * @param handle : Handle to identify the CAMSMMU client (IFE, ICP, etc.) + * @param paddr : Device virtual address of client's scratch buffer that + * will be freed. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ + +int cam_smmu_put_scratch_iova(int handle, + dma_addr_t paddr); + +/** + *@brief : Destroys an smmu handle + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_destroy_handle(int handle); + +/** + * @brief : Finds index by handle in the smmu client table + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @return Index of SMMU client. Nagative in case of error. + */ +int cam_smmu_find_index_by_handle(int hdl); + +/** + * @brief : Registers smmu fault handler for client + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param handler_cb: It is triggered in IOMMU page fault + * @param token: It is input param when trigger page fault handler + */ +void cam_smmu_set_client_page_fault_handler(int handle, + cam_smmu_client_page_fault_handler handler_cb, void *token); + +/** + * @brief : Unregisters smmu fault handler for client + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param token: It is input param when trigger page fault handler + */ +void cam_smmu_unset_client_page_fault_handler(int handle, void *token); + +/** + * @brief Maps memory from an ION fd into IOVA space + * + * @param handle: SMMU handle identifying the context bank to map to + * @param ion_fd: ION fd of memory to map to + * @param paddr_ptr: Pointer IOVA address that will be returned + * @param len_ptr: Length of memory mapped + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr); + +/** + * @brief Maps memory from an ION fd into IOVA space + * + * @param handle: SMMU handle identifying the secure context bank to map to + * @param ion_fd: ION fd of memory to map to + * @param paddr_ptr: Pointer IOVA address that will be returned + * @param len_ptr: Length of memory mapped + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_stage2_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr); + +/** + * @brief Unmaps memory from context bank + * + * @param handle: SMMU handle identifying the context bank + * @param ion_fd: ION fd of memory to unmap + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_put_iova(int handle, int ion_fd); + +/** + * @brief Maps secure memory for SMMU handle + * + * @param handle: SMMU handle identifying secure context bank + * @param ion_fd: ION fd to map securely + * @param dir: DMA Direction for the mapping + * @param dma_addr: Returned IOVA address after mapping + * @param len_ptr: Length of memory mapped + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_map_stage2_iova(int handle, + int ion_fd, enum cam_smmu_map_dir dir, dma_addr_t *dma_addr, + size_t *len_ptr); + +/** + * @brief Unmaps secure memopry for SMMU handle + * + * @param handle: SMMU handle identifying secure context bank + * @param ion_fd: ION fd to unmap + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_unmap_stage2_iova(int handle, int ion_fd); + +/** + * @brief Allocates firmware for context bank + * + * @param smmu_hdl: SMMU handle identifying context bank + * @param iova: IOVA address of allocated firmware + * @param kvaddr: CPU mapped address of allocated firmware + * @param len: Length of allocated firmware memory + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_alloc_firmware(int32_t smmu_hdl, + dma_addr_t *iova, + uintptr_t *kvaddr, + size_t *len); + +/** + * @brief Deallocates firmware memory for context bank + * + * @param smmu_hdl: SMMU handle identifying the context bank + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_dealloc_firmware(int32_t smmu_hdl); + +/** + * @brief Gets region information specified by smmu handle and region id + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param region_id: Region id for which information is desired + * @param region_info: Struct populated with region information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_region_info(int32_t smmu_hdl, + enum cam_smmu_region_id region_id, + struct cam_smmu_region_info *region_info); + +/** + * @brief Reserves secondary heap + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param iova: IOVA of secondary heap after reservation has completed + * @param buf: Allocated dma_buf for secondary heap + * @param request_len: Length of secondary heap after reservation has completed + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_reserve_sec_heap(int32_t smmu_hdl, + struct dma_buf *buf, + dma_addr_t *iova, + size_t *request_len); + +/** + * @brief Releases secondary heap + * + * @param smmu_hdl: SMMU handle identifying the context bank + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_release_sec_heap(int32_t smmu_hdl); + +/** + * @brief Allocates qdss for context bank + * + * @param smmu_hdl: SMMU handle identifying context bank + * @param iova: IOVA address of allocated qdss + * @param len: Length of allocated qdss memory + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_alloc_qdss(int32_t smmu_hdl, + dma_addr_t *iova, + size_t *len); + +/** + * @brief Deallocates qdss memory for context bank + * + * @param smmu_hdl: SMMU handle identifying the context bank + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_dealloc_qdss(int32_t smmu_hdl); + +/** + * @brief Get start addr & len of I/O region for a given cb + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param iova: IOVA address of allocated I/O region + * @param len: Length of allocated I/O memory + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len); + +#endif /* _CAM_SMMU_API_H_ */ diff --git a/drivers/cam_sync/Makefile b/drivers/cam_sync/Makefile new file mode 100644 index 000000000000..b0868f522549 --- /dev/null +++ b/drivers/cam_sync/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync.o cam_sync_util.o diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c new file mode 100644 index 000000000000..5342de04da8f --- /dev/null +++ b/drivers/cam_sync/cam_sync.c @@ -0,0 +1,1094 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_sync_util.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" + +struct sync_device *sync_dev; + +/* + * Flag to determine whether to enqueue cb of a + * signaled fence onto the workq or invoke it + * directly in the same context + */ +static bool trigger_cb_without_switch; + +int cam_sync_create(int32_t *sync_obj, const char *name) +{ + int rc; + long idx; + bool bit; + + do { + idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + if (idx >= CAM_SYNC_MAX_OBJS) + return -ENOMEM; + CAM_DBG(CAM_SYNC, "Index location available at idx: %ld", idx); + bit = test_and_set_bit(idx, sync_dev->bitmap); + } while (bit); + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + rc = cam_sync_init_row(sync_dev->sync_table, idx, name, + CAM_SYNC_TYPE_INDV); + if (rc) { + CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld", + idx); + clear_bit(idx, sync_dev->bitmap); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + return -EINVAL; + } + + *sync_obj = idx; + CAM_DBG(CAM_SYNC, "sync_obj: %i", *sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + return rc; +} + +int cam_sync_register_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj) +{ + struct sync_callback_info *sync_cb; + struct sync_table_row *row = NULL; + int status = 0; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0 || !cb_func) + return -EINVAL; + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -EINVAL; + } + + sync_cb = kzalloc(sizeof(*sync_cb), GFP_ATOMIC); + if (!sync_cb) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -ENOMEM; + } + + /* Trigger callback if sync object is already in SIGNALED state */ + if ((row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS || + row->state == CAM_SYNC_STATE_SIGNALED_ERROR) && + (!row->remaining)) { + if (trigger_cb_without_switch) { + CAM_DBG(CAM_SYNC, "Invoke callback for sync object:%d", + sync_obj); + status = row->state; + kfree(sync_cb); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + cb_func(sync_obj, status, userdata); + } else { + sync_cb->callback_func = cb_func; + sync_cb->cb_data = userdata; + sync_cb->sync_obj = sync_obj; + INIT_WORK(&sync_cb->cb_dispatch_work, + cam_sync_util_cb_dispatch); + sync_cb->status = row->state; + CAM_DBG(CAM_SYNC, "Enqueue callback for sync object:%d", + sync_cb->sync_obj); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + } + + return 0; + } + + sync_cb->callback_func = cb_func; + sync_cb->cb_data = userdata; + sync_cb->sync_obj = sync_obj; + INIT_WORK(&sync_cb->cb_dispatch_work, cam_sync_util_cb_dispatch); + list_add_tail(&sync_cb->list, &row->callback_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + return 0; +} + +int cam_sync_deregister_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + struct sync_callback_info *sync_cb, *temp; + bool found = false; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -EINVAL; + } + + CAM_DBG(CAM_SYNC, "deregistered callback for sync object:%d", + sync_obj); + list_for_each_entry_safe(sync_cb, temp, &row->callback_list, list) { + if (sync_cb->callback_func == cb_func && + sync_cb->cb_data == userdata) { + list_del_init(&sync_cb->list); + kfree(sync_cb); + found = true; + } + } + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return found ? 0 : -ENOENT; +} + +int cam_sync_signal(int32_t sync_obj, uint32_t status) +{ + struct sync_table_row *row = NULL; + struct sync_table_row *parent_row = NULL; + struct sync_parent_info *parent_info, *temp_parent_info; + struct list_head parents_list; + int rc = 0; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) { + CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)", + sync_obj, CAM_SYNC_MAX_OBJS); + return -EINVAL; + } + row = sync_dev->sync_table + sync_obj; + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + + if (row->type == CAM_SYNC_TYPE_GROUP) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: Signaling a GROUP sync object = %d", + sync_obj); + return -EINVAL; + } + + if (row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: Sync object already signaled sync_obj = %d", + sync_obj); + return -EALREADY; + } + + if (status != CAM_SYNC_STATE_SIGNALED_SUCCESS && + status != CAM_SYNC_STATE_SIGNALED_ERROR) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: signaling with undefined status = %d", + status); + return -EINVAL; + } + + if (!atomic_dec_and_test(&row->ref_cnt)) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return 0; + } + + row->state = status; + cam_sync_util_dispatch_signaled_cb(sync_obj, status); + + /* copy parent list to local and release child lock */ + INIT_LIST_HEAD(&parents_list); + list_splice_init(&row->parents_list, &parents_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + if (list_empty(&parents_list)) + return 0; + + /* + * Now iterate over all parents of this object and if they too need to + * be signaled dispatch cb's + */ + list_for_each_entry_safe(parent_info, + temp_parent_info, + &parents_list, + list) { + parent_row = sync_dev->sync_table + parent_info->sync_id; + spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + parent_row->remaining--; + + rc = cam_sync_util_update_parent_state( + parent_row, + status); + if (rc) { + CAM_ERR(CAM_SYNC, "Invalid parent state %d", + parent_row->state); + spin_unlock_bh( + &sync_dev->row_spinlocks[parent_info->sync_id]); + kfree(parent_info); + continue; + } + + if (!parent_row->remaining) + cam_sync_util_dispatch_signaled_cb( + parent_info->sync_id, parent_row->state); + + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + list_del_init(&parent_info->list); + kfree(parent_info); + } + + return 0; +} + +int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) +{ + int rc; + long idx = 0; + bool bit; + + if (!sync_obj || !merged_obj) { + CAM_ERR(CAM_SYNC, "Invalid pointer(s)"); + return -EINVAL; + } + + if (num_objs <= 1) { + CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); + return -EINVAL; + } + + if (cam_common_util_remove_duplicate_arr(sync_obj, num_objs) + != num_objs) { + CAM_ERR(CAM_SYNC, "The obj list has duplicate fence"); + return -EINVAL; + } + + do { + idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + if (idx >= CAM_SYNC_MAX_OBJS) + return -ENOMEM; + bit = test_and_set_bit(idx, sync_dev->bitmap); + } while (bit); + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + rc = cam_sync_init_group_object(sync_dev->sync_table, + idx, sync_obj, + num_objs); + if (rc < 0) { + CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld", + idx); + clear_bit(idx, sync_dev->bitmap); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + return -EINVAL; + } + CAM_DBG(CAM_SYNC, "Init row at idx:%ld to merge objects", idx); + *merged_obj = idx; + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + return 0; +} + +int cam_sync_get_obj_ref(int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + + spin_lock(&sync_dev->row_spinlocks[sync_obj]); + + if (row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + + atomic_inc(&row->ref_cnt); + spin_unlock(&sync_dev->row_spinlocks[sync_obj]); + CAM_DBG(CAM_SYNC, "get ref for obj %d", sync_obj); + + return 0; +} + +int cam_sync_put_obj_ref(int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + atomic_dec(&row->ref_cnt); + CAM_DBG(CAM_SYNC, "put ref for obj %d", sync_obj); + + return 0; +} + +int cam_sync_destroy(int32_t sync_obj) +{ + CAM_DBG(CAM_SYNC, "sync_obj: %i", sync_obj); + return cam_sync_deinit_object(sync_dev->sync_table, sync_obj); +} + +int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms) +{ + unsigned long timeleft; + int rc = -EINVAL; + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + + timeleft = wait_for_completion_timeout(&row->signaled, + msecs_to_jiffies(timeout_ms)); + + if (!timeleft) { + CAM_ERR(CAM_SYNC, + "Error: timed out for sync obj = %d", sync_obj); + rc = -ETIMEDOUT; + } else { + switch (row->state) { + case CAM_SYNC_STATE_INVALID: + case CAM_SYNC_STATE_ACTIVE: + case CAM_SYNC_STATE_SIGNALED_ERROR: + CAM_ERR(CAM_SYNC, + "Error: Wait on invalid state = %d, obj = %d", + row->state, sync_obj); + rc = -EINVAL; + break; + case CAM_SYNC_STATE_SIGNALED_SUCCESS: + rc = 0; + break; + default: + rc = -EINVAL; + break; + } + } + + return rc; +} + +static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_info sync_create; + int result; + + if (k_ioctl->size != sizeof(struct cam_sync_info)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_create, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + result = cam_sync_create(&sync_create.sync_obj, + sync_create.name); + + if (!result) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->ioctl_ptr), + &sync_create, + k_ioctl->size)) + return -EFAULT; + + return result; +} + +static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl) +{ + int rc = 0; + struct cam_sync_signal sync_signal; + + if (k_ioctl->size != sizeof(struct cam_sync_signal)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_signal, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + /* need to get ref for UMD signaled fences */ + rc = cam_sync_get_obj_ref(sync_signal.sync_obj); + if (rc) { + CAM_DBG(CAM_SYNC, + "Error: cannot signal an uninitialized sync obj = %d", + sync_signal.sync_obj); + return rc; + } + + return cam_sync_signal(sync_signal.sync_obj, + sync_signal.sync_state); +} + +static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_merge sync_merge; + uint32_t *sync_objs; + uint32_t num_objs; + uint32_t size; + int result; + + if (k_ioctl->size != sizeof(struct cam_sync_merge)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_merge, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + if (sync_merge.num_objs >= CAM_SYNC_MAX_OBJS) + return -EINVAL; + + size = sizeof(uint32_t) * sync_merge.num_objs; + sync_objs = kzalloc(size, GFP_ATOMIC); + + if (!sync_objs) + return -ENOMEM; + + if (copy_from_user(sync_objs, + u64_to_user_ptr(sync_merge.sync_objs), + sizeof(uint32_t) * sync_merge.num_objs)) { + kfree(sync_objs); + return -EFAULT; + } + + num_objs = sync_merge.num_objs; + + result = cam_sync_merge(sync_objs, + num_objs, + &sync_merge.merged); + + if (!result) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->ioctl_ptr), + &sync_merge, + k_ioctl->size)) { + kfree(sync_objs); + return -EFAULT; + } + + kfree(sync_objs); + + return result; +} + +static int cam_sync_handle_wait(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_wait sync_wait; + + if (k_ioctl->size != sizeof(struct cam_sync_wait)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_wait, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + k_ioctl->result = cam_sync_wait(sync_wait.sync_obj, + sync_wait.timeout_ms); + + return 0; +} + +static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_info sync_create; + + if (k_ioctl->size != sizeof(struct cam_sync_info)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_create, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + return cam_sync_destroy(sync_create.sync_obj); +} + +static int cam_sync_handle_register_user_payload( + struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_userpayload_info userpayload_info; + struct sync_user_payload *user_payload_kernel; + struct sync_user_payload *user_payload_iter; + struct sync_user_payload *temp_upayload_kernel; + uint32_t sync_obj; + struct sync_table_row *row = NULL; + + if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&userpayload_info, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + sync_obj = userpayload_info.sync_obj; + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + user_payload_kernel = kzalloc(sizeof(*user_payload_kernel), GFP_KERNEL); + if (!user_payload_kernel) + return -ENOMEM; + + memcpy(user_payload_kernel->payload_data, + userpayload_info.payload, + CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + kfree(user_payload_kernel); + return -EINVAL; + } + + if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS || + row->state == CAM_SYNC_STATE_SIGNALED_ERROR) { + + cam_sync_util_send_v4l2_event(CAM_SYNC_V4L_EVENT_ID_CB_TRIG, + sync_obj, + row->state, + user_payload_kernel->payload_data, + CAM_SYNC_USER_PAYLOAD_SIZE * sizeof(__u64)); + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + kfree(user_payload_kernel); + return 0; + } + + list_for_each_entry_safe(user_payload_iter, + temp_upayload_kernel, + &row->user_payload_list, + list) { + if (user_payload_iter->payload_data[0] == + user_payload_kernel->payload_data[0] && + user_payload_iter->payload_data[1] == + user_payload_kernel->payload_data[1]) { + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + kfree(user_payload_kernel); + return -EALREADY; + } + } + + list_add_tail(&user_payload_kernel->list, &row->user_payload_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return 0; +} + +static int cam_sync_handle_deregister_user_payload( + struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_userpayload_info userpayload_info; + struct sync_user_payload *user_payload_kernel, *temp; + uint32_t sync_obj; + struct sync_table_row *row = NULL; + + if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info)) { + CAM_ERR(CAM_SYNC, "Incorrect ioctl size"); + return -EINVAL; + } + + if (!k_ioctl->ioctl_ptr) { + CAM_ERR(CAM_SYNC, "Invalid embedded ioctl ptr"); + return -EINVAL; + } + + if (copy_from_user(&userpayload_info, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + sync_obj = userpayload_info.sync_obj; + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -EINVAL; + } + + list_for_each_entry_safe(user_payload_kernel, temp, + &row->user_payload_list, list) { + if (user_payload_kernel->payload_data[0] == + userpayload_info.payload[0] && + user_payload_kernel->payload_data[1] == + userpayload_info.payload[1]) { + list_del_init(&user_payload_kernel->list); + kfree(user_payload_kernel); + } + } + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return 0; +} + +static long cam_sync_dev_ioctl(struct file *filep, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + int32_t rc; + struct sync_device *sync_dev = video_drvdata(filep); + struct cam_private_ioctl_arg k_ioctl; + + if (!sync_dev) { + CAM_ERR(CAM_SYNC, "sync_dev NULL"); + return -EINVAL; + } + + if (!arg) + return -EINVAL; + + if (cmd != CAM_PRIVATE_IOCTL_CMD) + return -ENOIOCTLCMD; + + k_ioctl = *(struct cam_private_ioctl_arg *)arg; + + switch (k_ioctl.id) { + case CAM_SYNC_CREATE: + rc = cam_sync_handle_create(&k_ioctl); + break; + case CAM_SYNC_DESTROY: + rc = cam_sync_handle_destroy(&k_ioctl); + break; + case CAM_SYNC_REGISTER_PAYLOAD: + rc = cam_sync_handle_register_user_payload( + &k_ioctl); + break; + case CAM_SYNC_DEREGISTER_PAYLOAD: + rc = cam_sync_handle_deregister_user_payload( + &k_ioctl); + break; + case CAM_SYNC_SIGNAL: + rc = cam_sync_handle_signal(&k_ioctl); + break; + case CAM_SYNC_MERGE: + rc = cam_sync_handle_merge(&k_ioctl); + break; + case CAM_SYNC_WAIT: + rc = cam_sync_handle_wait(&k_ioctl); + ((struct cam_private_ioctl_arg *)arg)->result = + k_ioctl.result; + break; + default: + rc = -ENOIOCTLCMD; + } + + return rc; +} + +static unsigned int cam_sync_poll(struct file *f, + struct poll_table_struct *pll_table) +{ + int rc = 0; + struct v4l2_fh *eventq = f->private_data; + + if (!eventq) + return -EINVAL; + + poll_wait(f, &eventq->wait, pll_table); + + if (v4l2_event_pending(eventq)) + rc = POLLPRI; + + return rc; +} + +static int cam_sync_open(struct file *filep) +{ + int rc; + struct sync_device *sync_dev = video_drvdata(filep); + + if (!sync_dev) { + CAM_ERR(CAM_SYNC, "Sync device NULL"); + return -ENODEV; + } + + mutex_lock(&sync_dev->table_lock); + if (sync_dev->open_cnt >= 1) { + mutex_unlock(&sync_dev->table_lock); + return -EALREADY; + } + + rc = v4l2_fh_open(filep); + if (!rc) { + sync_dev->open_cnt++; + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + sync_dev->cam_sync_eventq = filep->private_data; + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + } else { + CAM_ERR(CAM_SYNC, "v4l2_fh_open failed : %d", rc); + } + mutex_unlock(&sync_dev->table_lock); + + return rc; +} + +static int cam_sync_close(struct file *filep) +{ + int rc = 0; + int i; + struct sync_device *sync_dev = video_drvdata(filep); + + if (!sync_dev) { + CAM_ERR(CAM_SYNC, "Sync device NULL"); + rc = -ENODEV; + return rc; + } + mutex_lock(&sync_dev->table_lock); + sync_dev->open_cnt--; + if (!sync_dev->open_cnt) { + for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) { + struct sync_table_row *row = + sync_dev->sync_table + i; + + /* + * Signal all ACTIVE objects as ERR, but we don't + * care about the return status here apart from logging + * it. + */ + if (row->state == CAM_SYNC_STATE_ACTIVE) { + rc = cam_sync_signal(i, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc < 0) + CAM_ERR(CAM_SYNC, + "Cleanup signal fail idx:%d\n", + i); + } + } + + /* + * Flush the work queue to wait for pending signal callbacks to + * finish + */ + flush_workqueue(sync_dev->work_queue); + + /* + * Now that all callbacks worker threads have finished, + * destroy the sync objects + */ + for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) { + struct sync_table_row *row = + sync_dev->sync_table + i; + + if (row->state != CAM_SYNC_STATE_INVALID) { + rc = cam_sync_destroy(i); + if (rc < 0) + CAM_ERR(CAM_SYNC, + "Cleanup destroy fail:idx:%d\n", + i); + } + } + } + mutex_unlock(&sync_dev->table_lock); + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + sync_dev->cam_sync_eventq = NULL; + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + v4l2_fh_release(filep); + + return rc; +} + +int cam_sync_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, CAM_SYNC_MAX_V4L2_EVENTS, NULL); +} + +int cam_sync_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static const struct v4l2_ioctl_ops g_cam_sync_ioctl_ops = { + .vidioc_subscribe_event = cam_sync_subscribe_event, + .vidioc_unsubscribe_event = cam_sync_unsubscribe_event, + .vidioc_default = cam_sync_dev_ioctl, +}; + +static struct v4l2_file_operations cam_sync_v4l2_fops = { + .owner = THIS_MODULE, + .open = cam_sync_open, + .release = cam_sync_close, + .poll = cam_sync_poll, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif +}; + +#if defined(CONFIG_MEDIA_CONTROLLER) +static int cam_sync_media_controller_init(struct sync_device *sync_dev, + struct platform_device *pdev) +{ + int rc; + + sync_dev->v4l2_dev.mdev = kzalloc(sizeof(struct media_device), + GFP_KERNEL); + if (!sync_dev->v4l2_dev.mdev) + return -ENOMEM; + + media_device_init(sync_dev->v4l2_dev.mdev); + strlcpy(sync_dev->v4l2_dev.mdev->model, CAM_SYNC_DEVICE_NAME, + sizeof(sync_dev->v4l2_dev.mdev->model)); + sync_dev->v4l2_dev.mdev->dev = &(pdev->dev); + + rc = media_device_register(sync_dev->v4l2_dev.mdev); + if (rc < 0) + goto register_fail; + + rc = media_entity_pads_init(&sync_dev->vdev->entity, 0, NULL); + if (rc < 0) + goto entity_fail; + + return 0; + +entity_fail: + media_device_unregister(sync_dev->v4l2_dev.mdev); +register_fail: + media_device_cleanup(sync_dev->v4l2_dev.mdev); + return rc; +} + +static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev) +{ + media_entity_cleanup(&sync_dev->vdev->entity); + media_device_unregister(sync_dev->v4l2_dev.mdev); + media_device_cleanup(sync_dev->v4l2_dev.mdev); + kfree(sync_dev->v4l2_dev.mdev); +} + +static void cam_sync_init_entity(struct sync_device *sync_dev) +{ + sync_dev->vdev->entity.function = CAM_SYNC_DEVICE_TYPE; + sync_dev->vdev->entity.name = + video_device_node_name(sync_dev->vdev); +} +#else +static int cam_sync_media_controller_init(struct sync_device *sync_dev, + struct platform_device *pdev) +{ + return 0; +} + +static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev) +{ +} + +static void cam_sync_init_entity(struct sync_device *sync_dev) +{ +} +#endif + +static int cam_sync_create_debugfs(void) +{ + sync_dev->dentry = debugfs_create_dir("camera_sync", NULL); + + if (!sync_dev->dentry) { + CAM_ERR(CAM_SYNC, "Failed to create sync dir"); + return -ENOMEM; + } + + if (!debugfs_create_bool("trigger_cb_without_switch", + 0644, sync_dev->dentry, + &trigger_cb_without_switch)) { + CAM_ERR(CAM_SYNC, + "failed to create trigger_cb_without_switch entry"); + return -ENOMEM; + } + + return 0; +} + +static int cam_sync_probe(struct platform_device *pdev) +{ + int rc; + int idx; + + sync_dev = kzalloc(sizeof(*sync_dev), GFP_KERNEL); + if (!sync_dev) + return -ENOMEM; + + mutex_init(&sync_dev->table_lock); + spin_lock_init(&sync_dev->cam_sync_eventq_lock); + + for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++) + spin_lock_init(&sync_dev->row_spinlocks[idx]); + + sync_dev->vdev = video_device_alloc(); + if (!sync_dev->vdev) { + rc = -ENOMEM; + goto vdev_fail; + } + + rc = cam_sync_media_controller_init(sync_dev, pdev); + if (rc < 0) + goto mcinit_fail; + + sync_dev->vdev->v4l2_dev = &sync_dev->v4l2_dev; + + rc = v4l2_device_register(&(pdev->dev), sync_dev->vdev->v4l2_dev); + if (rc < 0) + goto register_fail; + + strlcpy(sync_dev->vdev->name, CAM_SYNC_NAME, + sizeof(sync_dev->vdev->name)); + sync_dev->vdev->release = video_device_release; + sync_dev->vdev->fops = &cam_sync_v4l2_fops; + sync_dev->vdev->ioctl_ops = &g_cam_sync_ioctl_ops; + sync_dev->vdev->minor = -1; + sync_dev->vdev->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(sync_dev->vdev, + VFL_TYPE_GRABBER, -1); + if (rc < 0) + goto v4l2_fail; + + cam_sync_init_entity(sync_dev); + video_set_drvdata(sync_dev->vdev, sync_dev); + memset(&sync_dev->sync_table, 0, sizeof(sync_dev->sync_table)); + memset(&sync_dev->bitmap, 0, sizeof(sync_dev->bitmap)); + bitmap_zero(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + + /* + * We treat zero as invalid handle, so we will keep the 0th bit set + * always + */ + set_bit(0, sync_dev->bitmap); + + sync_dev->work_queue = alloc_workqueue(CAM_SYNC_WORKQUEUE_NAME, + WQ_HIGHPRI | WQ_UNBOUND, 1); + + if (!sync_dev->work_queue) { + CAM_ERR(CAM_SYNC, + "Error: high priority work queue creation failed"); + rc = -ENOMEM; + goto v4l2_fail; + } + + trigger_cb_without_switch = false; + cam_sync_create_debugfs(); + + return rc; + +v4l2_fail: + v4l2_device_unregister(sync_dev->vdev->v4l2_dev); +register_fail: + cam_sync_media_controller_cleanup(sync_dev); +mcinit_fail: + video_device_release(sync_dev->vdev); +vdev_fail: + mutex_destroy(&sync_dev->table_lock); + kfree(sync_dev); + return rc; +} + +static int cam_sync_remove(struct platform_device *pdev) +{ + v4l2_device_unregister(sync_dev->vdev->v4l2_dev); + cam_sync_media_controller_cleanup(sync_dev); + video_device_release(sync_dev->vdev); + debugfs_remove_recursive(sync_dev->dentry); + sync_dev->dentry = NULL; + kfree(sync_dev); + sync_dev = NULL; + + return 0; +} + +static struct platform_device cam_sync_device = { + .name = "cam_sync", + .id = -1, +}; + +static struct platform_driver cam_sync_driver = { + .probe = cam_sync_probe, + .remove = cam_sync_remove, + .driver = { + .name = "cam_sync", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_sync_init(void) +{ + int rc; + + rc = platform_device_register(&cam_sync_device); + if (rc) + return -ENODEV; + + return platform_driver_register(&cam_sync_driver); +} + +static void __exit cam_sync_exit(void) +{ + int idx; + + for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++) + spin_lock_init(&sync_dev->row_spinlocks[idx]); + platform_driver_unregister(&cam_sync_driver); + platform_device_unregister(&cam_sync_device); + kfree(sync_dev); +} + +module_init(cam_sync_init); +module_exit(cam_sync_exit); +MODULE_DESCRIPTION("Camera sync driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sync/cam_sync_api.h b/drivers/cam_sync/cam_sync_api.h new file mode 100644 index 000000000000..3d99bc15eb18 --- /dev/null +++ b/drivers/cam_sync/cam_sync_api.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_SYNC_API_H__ +#define __CAM_SYNC_API_H__ + +#include +#include +#include +#include +#include + +#define SYNC_DEBUG_NAME_LEN 63 +typedef void (*sync_callback)(int32_t sync_obj, int status, void *data); + +/* Kernel APIs */ + +/** + * @brief: Creates a sync object + * + * The newly created sync obj is assigned to sync_obj. + * sync object. + * + * @param sync_obj : Pointer to int referencing the sync object. + * @param name : Optional parameter associating a name with the sync object for + * debug purposes. Only first SYNC_DEBUG_NAME_LEN bytes are accepted, + * rest will be ignored. + * + * @return Status of operation. Zero in case of success. + * -EINVAL will be returned if sync_obj is an invalid pointer. + * -ENOMEM will be returned if the kernel can't allocate space for + * sync object. + */ +int cam_sync_create(int32_t *sync_obj, const char *name); + +/** + * @brief: Registers a callback with a sync object + * + * @param cb_func: Pointer to callback to be registered + * @param userdata: Opaque pointer which will be passed back with callback. + * @param sync_obj: int referencing the sync object. + * + * @return Status of operation. Zero in case of success. + * -EINVAL will be returned if userdata is invalid. + * -ENOMEM will be returned if cb_func is invalid. + * + */ +int cam_sync_register_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj); + +/** + * @brief: De-registers a callback with a sync object + * + * @param cb_func: Pointer to callback to be de-registered + * @param userdata: Opaque pointer which will be passed back with callback. + * @param sync_obj: int referencing the sync object. + * + * @return Status of operation. Zero in case of success. + * -EINVAL will be returned if userdata is invalid. + * -ENOMEM will be returned if cb_func is invalid. + */ +int cam_sync_deregister_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj); + +/** + * @brief: Signals a sync object with the status argument. + * + * This function will signal the sync object referenced by the sync_obj + * parameter and when doing so, will trigger callbacks in both user space and + * kernel. Callbacks will triggered asynchronously and their order of execution + * is not guaranteed. The status parameter will indicate whether the entity + * performing the signaling wants to convey an error case or a success case. + * + * @param sync_obj: int referencing the sync object. + * @param status: Status of the signaling. Can be either SYNC_SIGNAL_ERROR or + * SYNC_SIGNAL_SUCCESS. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_signal(int32_t sync_obj, uint32_t status); + +/** + * @brief: Merges multiple sync objects + * + * This function will merge multiple sync objects into a sync group. + * + * @param sync_obj: pointer to a block of ints to be merged + * @param num_objs: Number of ints in the block + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj); + +/** + * @brief: get ref count of sync obj + * + * This function will increment ref count for the sync object, and the ref + * count will be decremented when this sync object is signaled. + * + * @param sync_obj: sync object + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_get_obj_ref(int32_t sync_obj); + +/** + * @brief: put ref count of sync obj + * + * This function will decrement ref count for the sync object. + * + * @param sync_obj: sync object + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_put_obj_ref(int32_t sync_obj); + +/** + * @brief: Destroys a sync object + * + * @param sync_obj: int referencing the sync object to be destroyed + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_destroy(int32_t sync_obj); + +/** + * @brief: Waits for a sync object synchronously + * + * Does a wait on the sync object identified by sync_obj for a maximum + * of timeout_ms milliseconds. Must not be called from interrupt context as + * this API can sleep. Should be called from process context only. + * + * @param sync_obj: int referencing the sync object to be waited upon + * @timeout_ms sync_obj: Timeout in ms. + * + * @return 0 upon success, -EINVAL if sync object is in bad state or arguments + * are invalid, -ETIMEDOUT if wait times out. + */ +int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms); + + +#endif /* __CAM_SYNC_API_H__ */ diff --git a/drivers/cam_sync/cam_sync_private.h b/drivers/cam_sync/cam_sync_private.h new file mode 100644 index 000000000000..68a9804adf45 --- /dev/null +++ b/drivers/cam_sync/cam_sync_private.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_SYNC_PRIVATE_H__ +#define __CAM_SYNC_PRIVATE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_CAM_SYNC_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define CAM_SYNC_OBJ_NAME_LEN 64 +#define CAM_SYNC_MAX_OBJS 1024 +#define CAM_SYNC_MAX_V4L2_EVENTS 50 +#define CAM_SYNC_DEBUG_FILENAME "cam_debug" +#define CAM_SYNC_DEBUG_BASEDIR "cam" +#define CAM_SYNC_DEBUG_BUF_SIZE 32 +#define CAM_SYNC_PAYLOAD_WORDS 2 +#define CAM_SYNC_NAME "cam_sync" +#define CAM_SYNC_WORKQUEUE_NAME "HIPRIO_SYNC_WORK_QUEUE" + +#define CAM_SYNC_TYPE_INDV 0 +#define CAM_SYNC_TYPE_GROUP 1 + +/** + * enum sync_type - Enum to indicate the type of sync object, + * i.e. individual or group. + * + * @SYNC_TYPE_INDV : Object is an individual sync object + * @SYNC_TYPE_GROUP : Object is a group sync object + */ +enum sync_type { + SYNC_TYPE_INDV, + SYNC_TYPE_GROUP +}; + +/** + * enum sync_list_clean_type - Enum to indicate the type of list clean action + * to be peformed, i.e. specific sync ID or all list sync ids. + * + * @SYNC_CLEAN_ONE : Specific object to be cleaned in the list + * @SYNC_CLEAN_ALL : Clean all objects in the list + */ +enum sync_list_clean_type { + SYNC_LIST_CLEAN_ONE, + SYNC_LIST_CLEAN_ALL +}; + +/** + * struct sync_parent_info - Single node of information about a parent + * of a sync object, usually part of the parents linked list + * + * @sync_id : Sync object id of parent + * @list : List member used to append this node to a linked list + */ +struct sync_parent_info { + int32_t sync_id; + struct list_head list; +}; + +/** + * struct sync_parent_info - Single node of information about a child + * of a sync object, usually part of the children linked list + * + * @sync_id : Sync object id of child + * @list : List member used to append this node to a linked list + */ +struct sync_child_info { + int32_t sync_id; + struct list_head list; +}; + + +/** + * struct sync_callback_info - Single node of information about a kernel + * callback registered on a sync object + * + * @callback_func : Callback function, registered by client driver + * @cb_data : Callback data, registered by client driver + * @status........ : Status with which callback will be invoked in client + * @sync_obj : Sync id of the object for which callback is registered + * @cb_dispatch_work : Work representing the call dispatch + * @list : List member used to append this node to a linked list + */ +struct sync_callback_info { + sync_callback callback_func; + void *cb_data; + int status; + int32_t sync_obj; + struct work_struct cb_dispatch_work; + struct list_head list; +}; + +/** + * struct sync_user_payload - Single node of information about a user space + * payload registered from user space + * + * @payload_data : Payload data, opaque to kernel + * @list : List member used to append this node to a linked list + */ +struct sync_user_payload { + uint64_t payload_data[CAM_SYNC_PAYLOAD_WORDS]; + struct list_head list; +}; + +/** + * struct sync_table_row - Single row of information about a sync object, used + * for internal book keeping in the sync driver + * + * @name : Optional string representation of the sync object + * @type : Type of the sync object (individual or group) + * @sync_id : Integer id representing this sync object + * @parents_list : Linked list of parents of this sync object + * @children_list : Linked list of children of this sync object + * @state : State (INVALID, ACTIVE, SIGNALED_SUCCESS or + * SIGNALED_ERROR) + * @remaining : Count of remaining children that not been signaled + * @signaled : Completion variable on which block calls will wait + * @callback_list : Linked list of kernel callbacks registered + * @user_payload_list : LInked list of user space payloads registered + * @ref_cnt : ref count of the number of usage of the fence. + */ +struct sync_table_row { + char name[CAM_SYNC_OBJ_NAME_LEN]; + enum sync_type type; + int32_t sync_id; + /* List of parents, which are merged objects */ + struct list_head parents_list; + /* List of children, which constitute the merged object */ + struct list_head children_list; + uint32_t state; + uint32_t remaining; + struct completion signaled; + struct list_head callback_list; + struct list_head user_payload_list; + atomic_t ref_cnt; +}; + +/** + * struct cam_signalable_info - Information for a single sync object that is + * ready to be signaled + * + * @sync_obj : Sync object id of signalable object + * @status : Status with which to signal + * @list : List member used to append this node to a linked list + */ +struct cam_signalable_info { + int32_t sync_obj; + uint32_t status; + struct list_head list; +}; + +/** + * struct sync_device - Internal struct to book keep sync driver details + * + * @vdev : Video device + * @v4l2_dev : V4L2 device + * @sync_table : Table of all sync objects + * @row_spinlocks : Spinlock array, one for each row in the table + * @table_lock : Mutex used to lock the table + * @open_cnt : Count of file open calls made on the sync driver + * @dentry : Debugfs entry + * @work_queue : Work queue used for dispatching kernel callbacks + * @cam_sync_eventq : Event queue used to dispatch user payloads to user space + * @bitmap : Bitmap representation of all sync objects + */ +struct sync_device { + struct video_device *vdev; + struct v4l2_device v4l2_dev; + struct sync_table_row sync_table[CAM_SYNC_MAX_OBJS]; + spinlock_t row_spinlocks[CAM_SYNC_MAX_OBJS]; + struct mutex table_lock; + int open_cnt; + struct dentry *dentry; + struct workqueue_struct *work_queue; + struct v4l2_fh *cam_sync_eventq; + spinlock_t cam_sync_eventq_lock; + DECLARE_BITMAP(bitmap, CAM_SYNC_MAX_OBJS); +}; + + +#endif /* __CAM_SYNC_PRIVATE_H__ */ diff --git a/drivers/cam_sync/cam_sync_util.c b/drivers/cam_sync/cam_sync_util.c new file mode 100644 index 000000000000..d7e0f4125290 --- /dev/null +++ b/drivers/cam_sync/cam_sync_util.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sync_util.h" + +int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, + long *idx) +{ + int rc = 0; + + mutex_lock(&sync_dev->table_lock); + + *idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + + if (*idx < CAM_SYNC_MAX_OBJS) + set_bit(*idx, sync_dev->bitmap); + else + rc = -1; + + mutex_unlock(&sync_dev->table_lock); + + return rc; +} + +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type) +{ + struct sync_table_row *row = table + idx; + + if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) + return -EINVAL; + + memset(row, 0, sizeof(*row)); + + if (name) + strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN); + INIT_LIST_HEAD(&row->parents_list); + INIT_LIST_HEAD(&row->children_list); + row->type = type; + row->sync_id = idx; + row->state = CAM_SYNC_STATE_ACTIVE; + row->remaining = 0; + atomic_set(&row->ref_cnt, 0); + init_completion(&row->signaled); + INIT_LIST_HEAD(&row->callback_list); + INIT_LIST_HEAD(&row->user_payload_list); + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u ", + row->name, row->sync_id, idx, row->state); + + return 0; +} + +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, + uint32_t *sync_objs, + uint32_t num_objs) +{ + int i, rc = 0; + struct sync_child_info *child_info; + struct sync_parent_info *parent_info; + struct sync_table_row *row = table + idx; + struct sync_table_row *child_row = NULL; + + cam_sync_init_row(table, idx, "merged_fence", CAM_SYNC_TYPE_GROUP); + + /* + * While traversing for children, parent's row list is updated with + * child info and each child's row is updated with parent info. + * If any child state is ERROR or SUCCESS, it will not be added to list. + */ + for (i = 0; i < num_objs; i++) { + child_row = table + sync_objs[i]; + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + + /* validate child */ + if ((child_row->type == CAM_SYNC_TYPE_GROUP) || + (child_row->state == CAM_SYNC_STATE_INVALID)) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + CAM_ERR(CAM_SYNC, + "Invalid child fence:%i state:%u type:%u", + child_row->sync_id, child_row->state, + child_row->type); + rc = -EINVAL; + goto clean_children_info; + } + + /* check for child's state */ + if (child_row->state == CAM_SYNC_STATE_SIGNALED_ERROR) { + row->state = CAM_SYNC_STATE_SIGNALED_ERROR; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } + if (child_row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } + + row->remaining++; + + /* Add child info */ + child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC); + if (!child_info) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + rc = -ENOMEM; + goto clean_children_info; + } + child_info->sync_id = sync_objs[i]; + list_add_tail(&child_info->list, &row->children_list); + + /* Add parent info */ + parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC); + if (!parent_info) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + rc = -ENOMEM; + goto clean_children_info; + } + parent_info->sync_id = idx; + list_add_tail(&parent_info->list, &child_row->parents_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + } + + if (!row->remaining) { + if (row->state != CAM_SYNC_STATE_SIGNALED_ERROR) + row->state = CAM_SYNC_STATE_SIGNALED_SUCCESS; + complete_all(&row->signaled); + } + + return 0; + +clean_children_info: + row->state = CAM_SYNC_STATE_INVALID; + for (i = i-1; i >= 0; i--) { + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + child_row = table + sync_objs[i]; + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + } + + cam_sync_util_cleanup_children_list(row, SYNC_LIST_CLEAN_ALL, 0); + return rc; +} + +int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) +{ + struct sync_table_row *row = table + idx; + struct sync_child_info *child_info, *temp_child; + struct sync_callback_info *sync_cb, *temp_cb; + struct sync_parent_info *parent_info, *temp_parent; + struct sync_user_payload *upayload_info, *temp_upayload; + struct sync_table_row *child_row = NULL, *parent_row = NULL; + struct list_head temp_child_list, temp_parent_list; + + if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) + return -EINVAL; + + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u", + row->name, row->sync_id, idx, row->state); + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj: idx = %d", + idx); + return -EINVAL; + } + + if (row->state == CAM_SYNC_STATE_ACTIVE) + CAM_DBG(CAM_SYNC, + "Destroying an active sync object name:%s id:%i", + row->name, row->sync_id); + + row->state = CAM_SYNC_STATE_INVALID; + + /* Object's child and parent objects will be added into this list */ + INIT_LIST_HEAD(&temp_child_list); + INIT_LIST_HEAD(&temp_parent_list); + + list_for_each_entry_safe(child_info, temp_child, &row->children_list, + list) { + if (child_info->sync_id <= 0) + continue; + + list_del_init(&child_info->list); + list_add_tail(&child_info->list, &temp_child_list); + } + + list_for_each_entry_safe(parent_info, temp_parent, &row->parents_list, + list) { + if (parent_info->sync_id <= 0) + continue; + + list_del_init(&parent_info->list); + list_add_tail(&parent_info->list, &temp_parent_list); + } + + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + /* Cleanup the child to parent link from child list */ + while (!list_empty(&temp_child_list)) { + child_info = list_first_entry(&temp_child_list, + struct sync_child_info, list); + child_row = sync_dev->sync_table + child_info->sync_id; + + spin_lock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); + + if (child_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&child_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[ + child_info->sync_id]); + kfree(child_info); + continue; + } + + if (child_row->state == CAM_SYNC_STATE_ACTIVE) + CAM_DBG(CAM_SYNC, + "Warning: destroying active child sync obj = %d", + child_info->sync_id); + + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + + list_del_init(&child_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); + kfree(child_info); + } + + /* Cleanup the parent to child link */ + while (!list_empty(&temp_parent_list)) { + parent_info = list_first_entry(&temp_parent_list, + struct sync_parent_info, list); + parent_row = sync_dev->sync_table + parent_info->sync_id; + + spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + + if (parent_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&parent_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[ + parent_info->sync_id]); + kfree(parent_info); + continue; + } + + if (parent_row->state == CAM_SYNC_STATE_ACTIVE) + CAM_DBG(CAM_SYNC, + "Warning: destroying active parent sync obj = %d", + parent_info->sync_id); + + cam_sync_util_cleanup_children_list(parent_row, + SYNC_LIST_CLEAN_ONE, idx); + + list_del_init(&parent_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + kfree(parent_info); + } + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + list_for_each_entry_safe(upayload_info, temp_upayload, + &row->user_payload_list, list) { + list_del_init(&upayload_info->list); + kfree(upayload_info); + } + + list_for_each_entry_safe(sync_cb, temp_cb, + &row->callback_list, list) { + list_del_init(&sync_cb->list); + kfree(sync_cb); + } + + memset(row, 0, sizeof(*row)); + clear_bit(idx, sync_dev->bitmap); + INIT_LIST_HEAD(&row->callback_list); + INIT_LIST_HEAD(&row->parents_list); + INIT_LIST_HEAD(&row->children_list); + INIT_LIST_HEAD(&row->user_payload_list); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + CAM_DBG(CAM_SYNC, "Destroying sync obj:%d successful", idx); + return 0; +} + +void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work) +{ + struct sync_callback_info *cb_info = container_of(cb_dispatch_work, + struct sync_callback_info, + cb_dispatch_work); + + cb_info->callback_func(cb_info->sync_obj, + cb_info->status, + cb_info->cb_data); + + kfree(cb_info); +} + +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status) +{ + struct sync_callback_info *sync_cb; + struct sync_user_payload *payload_info; + struct sync_callback_info *temp_sync_cb; + struct sync_table_row *signalable_row; + struct sync_user_payload *temp_payload_info; + + signalable_row = sync_dev->sync_table + sync_obj; + if (signalable_row->state == CAM_SYNC_STATE_INVALID) { + CAM_DBG(CAM_SYNC, + "Accessing invalid sync object:%i", sync_obj); + return; + } + + /* Dispatch kernel callbacks if any were registered earlier */ + list_for_each_entry_safe(sync_cb, + temp_sync_cb, &signalable_row->callback_list, list) { + sync_cb->status = status; + list_del_init(&sync_cb->list); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + } + + /* Dispatch user payloads if any were registered earlier */ + list_for_each_entry_safe(payload_info, temp_payload_info, + &signalable_row->user_payload_list, list) { + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + if (!sync_dev->cam_sync_eventq) { + spin_unlock_bh( + &sync_dev->cam_sync_eventq_lock); + break; + } + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + cam_sync_util_send_v4l2_event( + CAM_SYNC_V4L_EVENT_ID_CB_TRIG, + sync_obj, + status, + payload_info->payload_data, + CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); + + list_del_init(&payload_info->list); + /* + * We can free the list node here because + * sending V4L event will make a deep copy + * anyway + */ + kfree(payload_info); + } + + /* + * This needs to be done because we want to unblock anyone + * who might be blocked and waiting on this sync object + */ + complete_all(&signalable_row->signaled); +} + +void cam_sync_util_send_v4l2_event(uint32_t id, + uint32_t sync_obj, + int status, + void *payload, + int len) +{ + struct v4l2_event event; + __u64 *payload_data = NULL; + struct cam_sync_ev_header *ev_header = NULL; + + event.id = id; + event.type = CAM_SYNC_V4L_EVENT; + + ev_header = CAM_SYNC_GET_HEADER_PTR(event); + ev_header->sync_obj = sync_obj; + ev_header->status = status; + + payload_data = CAM_SYNC_GET_PAYLOAD_PTR(event, __u64); + memcpy(payload_data, payload, len); + + v4l2_event_queue(sync_dev->vdev, &event); + CAM_DBG(CAM_SYNC, "send v4l2 event for sync_obj :%d", + sync_obj); +} + +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, + int new_state) +{ + int rc = 0; + + switch (parent_row->state) { + case CAM_SYNC_STATE_ACTIVE: + case CAM_SYNC_STATE_SIGNALED_SUCCESS: + parent_row->state = new_state; + break; + + case CAM_SYNC_STATE_SIGNALED_ERROR: + break; + + case CAM_SYNC_STATE_INVALID: + default: + rc = -EINVAL; + break; + } + + return rc; +} + +void cam_sync_util_cleanup_children_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj) +{ + struct sync_child_info *child_info = NULL; + struct sync_child_info *temp_child_info = NULL; + uint32_t curr_sync_obj; + + list_for_each_entry_safe(child_info, + temp_child_info, &row->children_list, list) { + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (child_info->sync_id != sync_obj)) + continue; + + curr_sync_obj = child_info->sync_id; + list_del_init(&child_info->list); + kfree(child_info); + + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (curr_sync_obj == sync_obj)) + break; + } +} + +void cam_sync_util_cleanup_parents_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj) +{ + struct sync_parent_info *parent_info = NULL; + struct sync_parent_info *temp_parent_info = NULL; + uint32_t curr_sync_obj; + + list_for_each_entry_safe(parent_info, + temp_parent_info, &row->parents_list, list) { + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (parent_info->sync_id != sync_obj)) + continue; + + curr_sync_obj = parent_info->sync_id; + list_del_init(&parent_info->list); + kfree(parent_info); + + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (curr_sync_obj == sync_obj)) + break; + } +} diff --git a/drivers/cam_sync/cam_sync_util.h b/drivers/cam_sync/cam_sync_util.h new file mode 100644 index 000000000000..e114c33c655a --- /dev/null +++ b/drivers/cam_sync/cam_sync_util.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_SYNC_UTIL_H__ +#define __CAM_SYNC_UTIL_H__ + + +#include +#include "cam_sync_private.h" +#include "cam_debug_util.h" + +extern struct sync_device *sync_dev; + +/** + * @brief: Finds an empty row in the sync table and sets its corresponding bit + * in the bit array + * + * @param sync_dev : Pointer to the sync device instance + * @param idx : Pointer to an long containing the index found in the bit + * array + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, + long *idx); + +/** + * @brief: Function to initialize an empty row in the sync table. This should be + * called only for individual sync objects. + * + * @param table : Pointer to the sync objects table + * @param idx : Index of row to initialize + * @param name : Optional string representation of the sync object. Should be + * 63 characters or less + * @param type : type of row to be initialized + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type); + +/** + * @brief: Function to uninitialize a row in the sync table + * + * @param table : Pointer to the sync objects table + * @param idx : Index of row to initialize + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx); + +/** + * @brief: Function to initialize a row in the sync table when the object is a + * group object, also known as a merged sync object + * + * @param table : Pointer to the sync objects table + * @param idx : Index of row to initialize + * @param sync_objs : Array of sync objects which will merged + * or grouped together + * @param num_objs : Number of sync objects in the array + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, + uint32_t *sync_objs, + uint32_t num_objs); + +int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx); + +/** + * @brief: Function to dispatch a kernel callback for a sync callback + * + * @param cb_dispatch_work : Pointer to the work_struct that needs to be + * dispatched + * + * @return None + */ +void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work); + +/** + * @brief: Function to dispatch callbacks for a signaled sync object + * + * @sync_obj : Sync object that is signaled + * @status : Status of the signaled object + * + * @return None + */ +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status); + +/** + * @brief: Function to send V4L event to user space + * @param id : V4L event id to send + * @param sync_obj : Sync obj for which event needs to be sent + * @param status : Status of the event + * @payload : Payload that needs to be sent to user space + * @len : Length of the payload + * + * @return None + */ +void cam_sync_util_send_v4l2_event(uint32_t id, + uint32_t sync_obj, + int status, + void *payload, + int len); + +/** + * @brief: Function which gets the next state of the sync object based on the + * current state and the new state + * + * @param current_state : Current state of the sync object + * @param new_state : New state of the sync object + * + * @return Next state of the sync object + */ +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, + int new_state); + +/** + * @brief: Function to clean up the children of a sync object + * @row : Row whose child list to clean + * @list_clean_type : Clean specific object or clean all objects + * @sync_obj : Sync object to be clean if list clean type is + * SYNC_LIST_CLEAN_ONE + * + * @return None + */ +void cam_sync_util_cleanup_children_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj); + +/** + * @brief: Function to clean up the parents of a sync object + * @row : Row whose parent list to clean + * @list_clean_type : Clean specific object or clean all objects + * @sync_obj : Sync object to be clean if list clean type is + * SYNC_LIST_CLEAN_ONE + * + * @return None + */ +void cam_sync_util_cleanup_parents_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj); + +#endif /* __CAM_SYNC_UTIL_H__ */ diff --git a/drivers/cam_utils/Makefile b/drivers/cam_utils/Makefile new file mode 100644 index 000000000000..fb8c48eeeb04 --- /dev/null +++ b/drivers/cam_utils/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_soc_util.o cam_io_util.o cam_packet_util.o cam_debug_util.o cam_trace.o cam_common_util.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cx_ipeak.o diff --git a/drivers/cam_utils/cam_common_util.c b/drivers/cam_utils/cam_common_util.c new file mode 100644 index 000000000000..dbcb31d7bf0e --- /dev/null +++ b/drivers/cam_utils/cam_common_util.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include + +#include "cam_common_util.h" +#include "cam_debug_util.h" + +int cam_common_util_get_string_index(const char **strings, + uint32_t num_strings, const char *matching_string, uint32_t *index) +{ + int i; + + for (i = 0; i < num_strings; i++) { + if (strnstr(strings[i], matching_string, strlen(strings[i]))) { + CAM_DBG(CAM_UTIL, "matched %s : %d\n", + matching_string, i); + *index = i; + return 0; + } + } + + return -EINVAL; +} + +uint32_t cam_common_util_remove_duplicate_arr(int32_t *arr, uint32_t num) +{ + int i, j; + uint32_t wr_idx = 1; + + if (!arr) { + CAM_ERR(CAM_UTIL, "Null input array"); + return 0; + } + + for (i = 1; i < num; i++) { + for (j = 0; j < wr_idx ; j++) { + if (arr[i] == arr[j]) + break; + } + if (j == wr_idx) + arr[wr_idx++] = arr[i]; + } + + return wr_idx; +} diff --git a/drivers/cam_utils/cam_common_util.h b/drivers/cam_utils/cam_common_util.h new file mode 100644 index 000000000000..e202bae5b761 --- /dev/null +++ b/drivers/cam_utils/cam_common_util.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_COMMON_UTIL_H_ +#define _CAM_COMMON_UTIL_H_ + +#include +#include + +#define CAM_BITS_MASK_SHIFT(x, mask, shift) (((x) & (mask)) >> shift) + +#define PTR_TO_U64(ptr) ((uint64_t)(uintptr_t)ptr) +#define U64_TO_PTR(ptr) ((void *)(uintptr_t)ptr) + +/** + * cam_common_util_get_string_index() + * + * @brief Match the string from list of strings to return + * matching index + * + * @strings: Pointer to list of strings + * @num_strings: Number of strings in 'strings' + * @matching_string: String to match + * @index: Pointer to index to return matching index + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_common_util_get_string_index(const char **strings, + uint32_t num_strings, const char *matching_string, uint32_t *index); + +/** + * cam_common_util_remove_duplicate_arr() + * + * @brief Move all the unique integers to the start of + * the array and return the number of unique integers + * + * @array: Pointer to the first integer of array + * @num: Number of elements in array + * + * @return: Number of unique integers in array + */ +uint32_t cam_common_util_remove_duplicate_arr(int32_t *array, + uint32_t num); + +#endif /* _CAM_COMMON_UTIL_H_ */ diff --git a/drivers/cam_utils/cam_cx_ipeak.c b/drivers/cam_utils/cam_cx_ipeak.c new file mode 100644 index 000000000000..b0f93ba045e0 --- /dev/null +++ b/drivers/cam_utils/cam_cx_ipeak.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static struct cx_ipeak_client *cam_cx_ipeak; +static int cx_ipeak_level = CAM_NOMINAL_VOTE; +static int cx_default_ipeak_mask; +static int cx_current_ipeak_mask; +static int cam_cx_client_cnt; + +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + soc_info->cam_cx_ipeak_enable = true; + soc_info->cam_cx_ipeak_bit = 1 << cam_cx_client_cnt++; + cx_default_ipeak_mask |= soc_info->cam_cx_ipeak_bit; + + if (cam_cx_ipeak) + goto exit; + + cam_cx_ipeak = cx_ipeak_register(soc_info->dev->of_node, + "qcom,cam-cx-ipeak"); + + if (cam_cx_ipeak) { + goto exit; + } else { + rc = -EINVAL; + goto exit; + } + +exit: + CAM_DBG(CAM_UTIL, "cam_cx_ipeak is enabled for %s\n" + "mask = %x cx_default_ipeak_mask = %x", + soc_info->dev_name, soc_info->cam_cx_ipeak_bit, + cx_default_ipeak_mask); + return rc; +} + +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + int ret = 0; + + CAM_DBG(CAM_UTIL, "E: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + + if (apply_level < cx_ipeak_level && + (cx_current_ipeak_mask & soc_cx_ipeak_bit)) { + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, false); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s UNVOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s DISABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + goto exit; + } else if (apply_level < cx_ipeak_level) { + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x NO AI", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + goto exit; + } + + cx_current_ipeak_mask |= soc_cx_ipeak_bit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s ENABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, true); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s VOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + +exit: + return ret; +} + +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + + CAM_DBG(CAM_UTIL, "E:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + if (cam_cx_ipeak) + cx_ipeak_update(cam_cx_ipeak, false); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x UNVOTE", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + + return 0; +} diff --git a/drivers/cam_utils/cam_cx_ipeak.h b/drivers/cam_utils/cam_cx_ipeak.h new file mode 100644 index 000000000000..ab06952b86a8 --- /dev/null +++ b/drivers/cam_utils/cam_cx_ipeak.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CX_IPEAK_H_ +#define _CAM_CX_IPEAK_H_ + +#include "cam_soc_util.h" + +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info); + +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level); +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_CX_IPEAK_H_ */ diff --git a/drivers/cam_utils/cam_debug_util.c b/drivers/cam_utils/cam_debug_util.c new file mode 100644 index 000000000000..3c178f1e77ac --- /dev/null +++ b/drivers/cam_utils/cam_debug_util.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundataion. All rights reserved. + */ + +#include +#include + +#include "cam_debug_util.h" + +static uint debug_mdl; +module_param(debug_mdl, uint, 0644); + +const char *cam_get_module_name(unsigned int module_id) +{ + const char *name = NULL; + + switch (module_id) { + case CAM_CDM: + name = "CAM-CDM"; + break; + case CAM_CORE: + name = "CAM-CORE"; + break; + case CAM_CRM: + name = "CAM-CRM"; + break; + case CAM_CPAS: + name = "CAM-CPAS"; + break; + case CAM_ISP: + name = "CAM-ISP"; + break; + case CAM_SENSOR: + name = "CAM-SENSOR"; + break; + case CAM_SMMU: + name = "CAM-SMMU"; + break; + case CAM_SYNC: + name = "CAM-SYNC"; + break; + case CAM_ICP: + name = "CAM-ICP"; + break; + case CAM_JPEG: + name = "CAM-JPEG"; + break; + case CAM_FD: + name = "CAM-FD"; + break; + case CAM_LRME: + name = "CAM-LRME"; + break; + case CAM_FLASH: + name = "CAM-FLASH"; + break; + case CAM_ACTUATOR: + name = "CAM-ACTUATOR"; + break; + case CAM_CCI: + name = "CAM-CCI"; + break; + case CAM_CSIPHY: + name = "CAM-CSIPHY"; + break; + case CAM_EEPROM: + name = "CAM-EEPROM"; + break; + case CAM_UTIL: + name = "CAM-UTIL"; + break; + case CAM_CTXT: + name = "CAM-CTXT"; + break; + case CAM_HFI: + name = "CAM-HFI"; + break; + case CAM_OIS: + name = "CAM-OIS"; + break; + case CAM_IRQ_CTRL: + name = "CAM-IRQ-CTRL"; + break; + case CAM_MEM: + name = "CAM-MEM"; + break; + case CAM_PERF: + name = "CAM-PERF"; + break; + case CAM_REQ: + name = "CAM-REQ"; + break; + default: + name = "CAM"; + break; + } + + return name; +} + +void cam_debug_log(unsigned int module_id, const char *func, const int line, + const char *fmt, ...) +{ + char str_buffer[STR_BUFFER_MAX_LENGTH]; + va_list args; + + va_start(args, fmt); + + if (debug_mdl & module_id) { + vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args); + pr_info("CAM_DBG: %s: %s: %d: %s\n", + cam_get_module_name(module_id), + func, line, str_buffer); + va_end(args); + } +} diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h new file mode 100644 index 000000000000..7380312dcde0 --- /dev/null +++ b/drivers/cam_utils/cam_debug_util.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_DEBUG_UTIL_H_ +#define _CAM_DEBUG_UTIL_H_ + +#define CAM_CDM (1 << 0) +#define CAM_CORE (1 << 1) +#define CAM_CPAS (1 << 2) +#define CAM_ISP (1 << 3) +#define CAM_CRM (1 << 4) +#define CAM_SENSOR (1 << 5) +#define CAM_SMMU (1 << 6) +#define CAM_SYNC (1 << 7) +#define CAM_ICP (1 << 8) +#define CAM_JPEG (1 << 9) +#define CAM_FD (1 << 10) +#define CAM_LRME (1 << 11) +#define CAM_FLASH (1 << 12) +#define CAM_ACTUATOR (1 << 13) +#define CAM_CCI (1 << 14) +#define CAM_CSIPHY (1 << 15) +#define CAM_EEPROM (1 << 16) +#define CAM_UTIL (1 << 17) +#define CAM_HFI (1 << 18) +#define CAM_CTXT (1 << 19) +#define CAM_OIS (1 << 20) +#define CAM_RES (1 << 21) +#define CAM_MEM (1 << 22) + +/* CAM_IRQ_CTRL: For events in irq controller */ +#define CAM_IRQ_CTRL (1 << 23) + +/* CAM_REQ: Tracks a request submitted to KMD */ +#define CAM_REQ (1 << 24) + +/* CAM_PERF: Used for performance (clock, BW etc) logs */ +#define CAM_PERF (1 << 25) + +#define STR_BUFFER_MAX_LENGTH 1024 + +/* + * cam_debug_log() + * + * @brief : Get the Module name from module ID and print + * respective debug logs + * + * @module_id : Respective Module ID which is calling this function + * @func : Function which is calling to print logs + * @line : Line number associated with the function which is calling + * to print log + * @fmt : Formatted string which needs to be print in the log + * + */ +void cam_debug_log(unsigned int module_id, const char *func, const int line, + const char *fmt, ...); + +/* + * cam_get_module_name() + * + * @brief : Get the module name from module ID + * + * @module_id : Module ID which is using this function + */ +const char *cam_get_module_name(unsigned int module_id); + +/* + * CAM_ERR + * @brief : This Macro will print error logs + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_ERR(__module, fmt, args...) \ + pr_err("CAM_ERR: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) +/* + * CAM_WARN + * @brief : This Macro will print warning logs + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_WARN(__module, fmt, args...) \ + pr_warn("CAM_WARN: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) +/* + * CAM_INFO + * @brief : This Macro will print Information logs + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_INFO(__module, fmt, args...) \ + pr_info("CAM_INFO: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +/* + * CAM_INFO_RATE_LIMIT + * @brief : This Macro will print info logs with ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_INFO_RATE_LIMIT(__module, fmt, args...) \ + pr_err_ratelimited("CAM_INFO: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +/* + * CAM_DBG + * @brief : This Macro will print debug logs when enabled using GROUP + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_DBG(__module, fmt, args...) \ + cam_debug_log(__module, __func__, __LINE__, fmt, ##args) + +/* + * CAM_ERR_RATE_LIMIT + * @brief : This Macro will print error print logs with ratelimit + */ +#define CAM_ERR_RATE_LIMIT(__module, fmt, args...) \ + pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +#endif /* _CAM_DEBUG_UTIL_H_ */ diff --git a/drivers/cam_utils/cam_io_util.c b/drivers/cam_utils/cam_io_util.c new file mode 100644 index 000000000000..d35320e7e487 --- /dev/null +++ b/drivers/cam_utils/cam_io_util.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2011-2014, 2017-2018, The Linux Foundation. + * All rights reserved. + */ + +#include +#include +#include +#include "cam_io_util.h" +#include "cam_debug_util.h" + +int cam_io_w(uint32_t data, void __iomem *addr) +{ + if (!addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + writel_relaxed_no_log(data, addr); + + return 0; +} + +int cam_io_w_mb(uint32_t data, void __iomem *addr) +{ + if (!addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + /* Ensure previous writes are done */ + wmb(); + writel_relaxed_no_log(data, addr); + /* Ensure previous writes are done */ + wmb(); + + return 0; +} + +uint32_t cam_io_r(void __iomem *addr) +{ + uint32_t data; + + if (!addr) { + CAM_ERR(CAM_UTIL, "Invalid args"); + return 0; + } + + data = readl_relaxed(addr); + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + + return data; +} + +uint32_t cam_io_r_mb(void __iomem *addr) +{ + uint32_t data; + + if (!addr) { + CAM_ERR(CAM_UTIL, "Invalid args"); + return 0; + } + + /* Ensure previous read is done */ + rmb(); + data = readl_relaxed(addr); + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + /* Ensure previous read is done */ + rmb(); + + return data; +} + +int cam_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len) +{ + int i; + uint32_t *d = (uint32_t *) dest_addr; + uint32_t *s = (uint32_t *) src_addr; + + if (!dest_addr || !src_addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "%pK %pK %d", dest_addr, src_addr, len); + + for (i = 0; i < len/4; i++) { + CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s); + writel_relaxed(*s++, d++); + } + + return 0; +} + +int cam_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len) +{ + int i; + uint32_t *d = (uint32_t *) dest_addr; + uint32_t *s = (uint32_t *) src_addr; + + if (!dest_addr || !src_addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "%pK %pK %d", dest_addr, src_addr, len); + + /* + * Do not use cam_io_w_mb to avoid double wmb() after a write + * and before the next write. + */ + wmb(); + for (i = 0; i < (len / 4); i++) { + CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s); + writel_relaxed(*s++, d++); + } + /* Ensure previous writes are done */ + wmb(); + + return 0; +} + +int cam_io_poll_value(void __iomem *addr, uint32_t wait_data, uint32_t retry, + unsigned long min_usecs, unsigned long max_usecs) +{ + uint32_t tmp, cnt = 0; + int rc = 0; + + if (!addr) + return -EINVAL; + + tmp = readl_relaxed(addr); + while ((tmp != wait_data) && (cnt++ < retry)) { + if (min_usecs > 0 && max_usecs > 0) + usleep_range(min_usecs, max_usecs); + tmp = readl_relaxed(addr); + } + + if (cnt > retry) { + CAM_DBG(CAM_UTIL, "Poll failed by value"); + rc = -EINVAL; + } + + return rc; +} + +int cam_io_poll_value_wmask(void __iomem *addr, uint32_t wait_data, + uint32_t bmask, uint32_t retry, unsigned long min_usecs, + unsigned long max_usecs) +{ + uint32_t tmp, cnt = 0; + int rc = 0; + + if (!addr) + return -EINVAL; + + tmp = readl_relaxed(addr); + while (((tmp & bmask) != wait_data) && (cnt++ < retry)) { + if (min_usecs > 0 && max_usecs > 0) + usleep_range(min_usecs, max_usecs); + tmp = readl_relaxed(addr); + } + + if (cnt > retry) { + CAM_DBG(CAM_UTIL, "Poll failed with mask"); + rc = -EINVAL; + } + + return rc; +} + +int cam_io_w_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len) +{ + int i; + + if (!data || !len || !addr) + return -EINVAL; + + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr =%pK", + i, len, data[i], addr); + writel_relaxed(data[i], addr); + } + + return 0; +} + +int cam_io_w_mb_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len) +{ + int i; + + if (!data || !len || !addr) + return -EINVAL; + + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr =%pK", + i, len, data[i], addr); + /* Ensure previous writes are done */ + wmb(); + writel_relaxed(data[i], addr); + } + + return 0; +} + +#define __OFFSET(__i) (data[__i][0]) +#define __VAL(__i) (data[__i][1]) +int cam_io_w_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len) +{ + int i; + + if (!data || !len || !addr_base) + return -EINVAL; + + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr_base =%pK reg=%x", + i, len, __VAL(i), addr_base, __OFFSET(i)); + writel_relaxed(__VAL(i), addr_base + __OFFSET(i)); + } + + return 0; +} + +int cam_io_w_mb_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len) +{ + int i; + + if (!data || !len || !addr_base) + return -EINVAL; + + /* Ensure write is done */ + wmb(); + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr_base =%pK reg=%x", + i, len, __VAL(i), addr_base, __OFFSET(i)); + writel_relaxed(__VAL(i), addr_base + __OFFSET(i)); + } + + return 0; +} + +#define BYTES_PER_REGISTER 4 +#define NUM_REGISTER_PER_LINE 4 +#define REG_OFFSET(__start, __i) (__start + (__i * BYTES_PER_REGISTER)) +int cam_io_dump(void __iomem *base_addr, uint32_t start_offset, int size) +{ + char line_str[128]; + char *p_str; + int i; + uint32_t data; + + CAM_DBG(CAM_UTIL, "addr=%pK offset=0x%x size=%d", + base_addr, start_offset, size); + + if (!base_addr || (size <= 0)) + return -EINVAL; + + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size; i++) { + if (i % NUM_REGISTER_PER_LINE == 0) { + snprintf(p_str, 12, "0x%08x: ", + REG_OFFSET(start_offset, i)); + p_str += 11; + } + data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i)); + snprintf(p_str, 9, "%08x ", data); + p_str += 8; + if ((i + 1) % NUM_REGISTER_PER_LINE == 0) { + CAM_ERR(CAM_UTIL, "%s", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CAM_ERR(CAM_UTIL, "%s", line_str); + + return 0; +} diff --git a/drivers/cam_utils/cam_io_util.h b/drivers/cam_utils/cam_io_util.h new file mode 100644 index 000000000000..66aaeaa45d55 --- /dev/null +++ b/drivers/cam_utils/cam_io_util.h @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2011-2014, 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IO_UTIL_H_ +#define _CAM_IO_UTIL_H_ + +#include + +/** + * cam_io_w() + * + * @brief: Camera IO util for register write + * + * @data: Value to be written + * @addr: Address used to write the value + * + * @return: Success or Failure + */ +int cam_io_w(uint32_t data, void __iomem *addr); + +/** + * cam_io_w_mb() + * + * @brief: Camera IO util for register write with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @data: Value to be written + * @addr: Address used to write the value + * + * @return: Success or Failure + */ +int cam_io_w_mb(uint32_t data, void __iomem *addr); + +/** + * cam_io_r() + * + * @brief: Camera IO util for register read + * + * @addr: Address of register to be read + * + * @return: Value read from the register address + */ +uint32_t cam_io_r(void __iomem *addr); + +/** + * cam_io_r_mb() + * + * @brief: Camera IO util for register read with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call rmb() independently in the caller. + * + * @addr: Address of register to be read + * + * @return: Value read from the register address + */ +uint32_t cam_io_r_mb(void __iomem *addr); + +/** + * cam_io_memcpy() + * + * @brief: Camera IO util for memory to register copy + * + * @dest_addr: Destination register address + * @src_addr: Source regiser address + * @len: Range to be copied + * + * @return: Success or Failure + */ +int cam_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len); + +/** + * cam_io_memcpy_mb() + * + * @brief: Camera IO util for memory to register copy + * with barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @dest_addr: Destination register address + * @src_addr: Source regiser address + * @len: Range to be copied + * + * @return: Success or Failure + */ +int cam_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len); + +/** + * cam_io_poll_value_wmask() + * + * @brief: Poll register value with bitmask. + * + * @addr: Register address to be polled + * @wait_data: Wait until @bmask read from @addr matches this data + * @bmask: Bit mask + * @retry: Number of retry + * @min_usecs: Minimum time to wait for retry + * @max_usecs: Maximum time to wait for retry + * + * @return: Success or Failure + * + * This function can sleep so it should not be called from interrupt + * handler, spin_lock etc. + */ +int cam_io_poll_value_wmask(void __iomem *addr, uint32_t wait_data, + uint32_t bmask, uint32_t retry, unsigned long min_usecs, + unsigned long max_usecs); + +/** + * cam_io_poll_value() + * + * @brief: Poll register value + * + * @addr: Register address to be polled + * @wait_data: Wait until value read from @addr matches this data + * @retry: Number of retry + * @min_usecs: Minimum time to wait for retry + * @max_usecs: Maximum time to wait for retry + * + * @return: Success or Failure + * + * This function can sleep so it should not be called from interrupt + * handler, spin_lock etc. + */ +int cam_io_poll_value(void __iomem *addr, uint32_t wait_data, uint32_t retry, + unsigned long min_usecs, unsigned long max_usecs); + +/** + * cam_io_w_same_offset_block() + * + * @brief: Write a block of data to same address + * + * @data: Block data to be written + * @addr: Register offset to be written. + * @len: Number of the data to be written + * + * @return: Success or Failure + */ +int cam_io_w_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len); + +/** + * cam_io_w_mb_same_offset_block() + * + * @brief: Write a block of data to same address with barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @data: Block data to be written + * @addr: Register offset to be written. + * @len: Number of the data to be written + * + * @return: Success or Failure + */ +int cam_io_w_mb_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len); + +/** + * cam_io_w_offset_val_block() + * + * @brief: This API is to write a block of registers + * represented by a 2 dimensional array table with + * register offset and value pair + * + * offset0, value0, + * offset1, value1, + * offset2, value2, + * and so on... + * + * @data: Pointer to 2-dimensional offset-value array + * @addr_base: Base address to which offset will be added to + * get the register address + * @len: Length of offset-value pair array to be written in + * number of uin32_t + * + * @return: Success or Failure + * + */ +int32_t cam_io_w_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len); + +/** + * cam_io_w_mb_offset_val_block() + * + * @brief: This API is to write a block of registers + * represented by a 2 dimensional array table with + * register offset and value pair with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * The OFFSETS NEED to be different because of the way + * barrier is used here. + * + * offset0, value0, + * offset1, value1, + * offset2, value2, + * and so on... + * + * @data: Pointer to 2-dimensional offset-value array + * @addr_base: Base address to which offset will be added to + * get the register address + * @len: Length of offset-value pair array to be written in + * number of uin32_t + * + * @return: Success or Failure + * + */ +int32_t cam_io_w_mb_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len); + +/** + * cam_io_dump() + * + * @brief: Camera IO util for dumping a range of register + * + * @base_addr: Start register address for the dumping + * @start_offset: Start register offset for the dump + * @size: Size specifying the range for dumping + * + * @return: Success or Failure + */ +int cam_io_dump(void __iomem *base_addr, uint32_t start_offset, int size); + +#endif /* _CAM_IO_UTIL_H_ */ diff --git a/drivers/cam_utils/cam_packet_util.c b/drivers/cam_utils/cam_packet_util.c new file mode 100644 index 000000000000..4eadee666219 --- /dev/null +++ b/drivers/cam_utils/cam_packet_util.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include + +#include "cam_mem_mgr.h" +#include "cam_packet_util.h" +#include "cam_debug_util.h" + +int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, + size_t *len) +{ + int rc = 0; + uintptr_t kmd_buf_addr = 0; + + rc = cam_mem_get_cpu_buf(handle, &kmd_buf_addr, len); + if (rc) { + CAM_ERR(CAM_UTIL, "Unable to get the virtual address %d", rc); + } else { + if (kmd_buf_addr && *len) { + *buf_addr = (uint32_t *)kmd_buf_addr; + } else { + CAM_ERR(CAM_UTIL, "Invalid addr and length :%zd", *len); + rc = -ENOMEM; + } + } + return rc; +} + +int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc) +{ + if ((cmd_desc->length > cmd_desc->size) || + (cmd_desc->mem_handle <= 0)) { + CAM_ERR(CAM_UTIL, "invalid cmd arg %d %d %d %d", + cmd_desc->offset, cmd_desc->length, + cmd_desc->mem_handle, cmd_desc->size); + return -EINVAL; + } + + return 0; +} + +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len) +{ + size_t sum_cmd_desc = 0; + size_t sum_io_cfgs = 0; + size_t sum_patch_desc = 0; + size_t pkt_wo_payload = 0; + + if (!packet) + return -EINVAL; + + if ((size_t)packet->header.size > remain_len) { + CAM_ERR(CAM_UTIL, + "Invalid packet size: %zu, CPU buf length: %zu", + (size_t)packet->header.size, remain_len); + return -EINVAL; + } + + + CAM_DBG(CAM_UTIL, "num cmd buf:%d num of io config:%d kmd buf index:%d", + packet->num_cmd_buf, packet->num_io_configs, + packet->kmd_cmd_buf_index); + + sum_cmd_desc = packet->num_cmd_buf * sizeof(struct cam_cmd_buf_desc); + sum_io_cfgs = packet->num_io_configs * sizeof(struct cam_buf_io_cfg); + sum_patch_desc = packet->num_patches * sizeof(struct cam_patch_desc); + pkt_wo_payload = offsetof(struct cam_packet, payload); + + if ((!packet->header.size) || + ((pkt_wo_payload + (size_t)packet->cmd_buf_offset + + sum_cmd_desc) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->io_configs_offset + + sum_io_cfgs) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->patch_offset + + sum_patch_desc) > (size_t)packet->header.size)) { + CAM_ERR(CAM_UTIL, "params not within mem len:%zu %zu %zu %zu", + (size_t)packet->header.size, sum_cmd_desc, + sum_io_cfgs, sum_patch_desc); + return -EINVAL; + } + + return 0; +} + +int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, + struct cam_kmd_buf_info *kmd_buf) +{ + int rc = 0; + size_t len = 0; + size_t remain_len = 0; + struct cam_cmd_buf_desc *cmd_desc; + uint32_t *cpu_addr; + + if (!packet || !kmd_buf) { + CAM_ERR(CAM_UTIL, "Invalid arg %pK %pK", packet, kmd_buf); + return -EINVAL; + } + + if ((packet->kmd_cmd_buf_index < 0) || + (packet->kmd_cmd_buf_index >= packet->num_cmd_buf)) { + CAM_ERR(CAM_UTIL, "Invalid kmd buf index: %d", + packet->kmd_cmd_buf_index); + return -EINVAL; + } + + /* Take first command descriptor and add offset to it for kmd*/ + cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *) + &packet->payload + packet->cmd_buf_offset); + cmd_desc += packet->kmd_cmd_buf_index; + + rc = cam_packet_util_validate_cmd_desc(cmd_desc); + if (rc) + return rc; + + rc = cam_packet_util_get_cmd_mem_addr(cmd_desc->mem_handle, &cpu_addr, + &len); + if (rc) + return rc; + + remain_len = len; + if (((size_t)cmd_desc->offset >= len) || + ((size_t)cmd_desc->size > (len - (size_t)cmd_desc->offset))) { + CAM_ERR(CAM_UTIL, "invalid memory len:%zd and cmd desc size:%d", + len, cmd_desc->size); + return -EINVAL; + } + + remain_len -= (size_t)cmd_desc->offset; + if ((size_t)packet->kmd_cmd_buf_offset >= remain_len) { + CAM_ERR(CAM_UTIL, "Invalid kmd cmd buf offset: %zu", + (size_t)packet->kmd_cmd_buf_offset); + return -EINVAL; + } + + cpu_addr += (cmd_desc->offset / 4) + (packet->kmd_cmd_buf_offset / 4); + CAM_DBG(CAM_UTIL, "total size %d, cmd size: %d, KMD buffer size: %d", + cmd_desc->size, cmd_desc->length, + cmd_desc->size - cmd_desc->length); + CAM_DBG(CAM_UTIL, "hdl 0x%x, cmd offset %d, kmd offset %d, addr 0x%pK", + cmd_desc->mem_handle, cmd_desc->offset, + packet->kmd_cmd_buf_offset, cpu_addr); + + kmd_buf->cpu_addr = cpu_addr; + kmd_buf->handle = cmd_desc->mem_handle; + kmd_buf->offset = cmd_desc->offset + packet->kmd_cmd_buf_offset; + kmd_buf->size = cmd_desc->size - cmd_desc->length; + kmd_buf->used_bytes = 0; + + return rc; +} + +int cam_packet_util_process_patches(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl) +{ + struct cam_patch_desc *patch_desc = NULL; + dma_addr_t iova_addr; + uintptr_t cpu_addr = 0; + uint32_t temp; + uint32_t *dst_cpu_addr; + uint32_t *src_buf_iova_addr; + size_t dst_buf_len; + size_t src_buf_size; + int i; + int rc = 0; + int32_t hdl; + + /* process patch descriptor */ + patch_desc = (struct cam_patch_desc *) + ((uint32_t *) &packet->payload + + packet->patch_offset/4); + CAM_DBG(CAM_UTIL, "packet = %pK patch_desc = %pK size = %lu", + (void *)packet, (void *)patch_desc, + sizeof(struct cam_patch_desc)); + + for (i = 0; i < packet->num_patches; i++) { + hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ? + sec_mmu_hdl : iommu_hdl; + rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, + hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, "unable to get src buf address"); + return rc; + } + src_buf_iova_addr = (uint32_t *)iova_addr; + temp = iova_addr; + + rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, + &cpu_addr, &dst_buf_len); + if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { + CAM_ERR(CAM_UTIL, "unable to get dst buf address"); + return rc; + } + dst_cpu_addr = (uint32_t *)cpu_addr; + + CAM_DBG(CAM_UTIL, "i = %d patch info = %x %x %x %x", i, + patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset, + patch_desc[i].src_buf_hdl, patch_desc[i].src_offset); + + if ((size_t)patch_desc[i].src_offset >= src_buf_size) { + CAM_ERR(CAM_UTIL, + "Invalid src buf patch offset"); + return -EINVAL; + } + + if ((dst_buf_len < sizeof(void *)) || + ((dst_buf_len - sizeof(void *)) < + (size_t)patch_desc[i].dst_offset)) { + CAM_ERR(CAM_UTIL, + "Invalid dst buf patch offset"); + return -EINVAL; + } + + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + + patch_desc[i].dst_offset); + temp += patch_desc[i].src_offset; + + *dst_cpu_addr = temp; + + CAM_DBG(CAM_UTIL, + "patch is done for dst %pK with src %pK value %llx", + dst_cpu_addr, src_buf_iova_addr, + *((uint64_t *)dst_cpu_addr)); + } + + return rc; +} + +int cam_packet_util_process_generic_cmd_buffer( + struct cam_cmd_buf_desc *cmd_buf, + cam_packet_generic_blob_handler blob_handler_cb, void *user_data) +{ + int rc = 0; + uintptr_t cpu_addr = 0; + size_t buf_size; + size_t remain_len = 0; + uint32_t *blob_ptr; + uint32_t blob_type, blob_size, blob_block_size, len_read; + + if (!cmd_buf || !blob_handler_cb) { + CAM_ERR(CAM_UTIL, "Invalid args %pK %pK", + cmd_buf, blob_handler_cb); + return -EINVAL; + } + + if (!cmd_buf->length || !cmd_buf->size) { + CAM_ERR(CAM_UTIL, "Invalid cmd buf size %d %d", + cmd_buf->length, cmd_buf->size); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(cmd_buf->mem_handle, &cpu_addr, &buf_size); + if (rc || !cpu_addr || (buf_size == 0)) { + CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK", + rc, (void *)cpu_addr); + return rc; + } + + remain_len = buf_size; + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_buf->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_buf->offset); + return -EINVAL; + } + remain_len -= (size_t)cmd_buf->offset; + + if (remain_len < (size_t)cmd_buf->length) { + CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", + (size_t)cmd_buf->length); + return -EINVAL; + } + + blob_ptr = (uint32_t *)(((uint8_t *)cpu_addr) + + cmd_buf->offset); + + CAM_DBG(CAM_UTIL, + "GenericCmdBuffer cpuaddr=%pK, blobptr=%pK, len=%d", + (void *)cpu_addr, (void *)blob_ptr, cmd_buf->length); + + len_read = 0; + while (len_read < cmd_buf->length) { + blob_type = + ((*blob_ptr) & CAM_GENERIC_BLOB_CMDBUFFER_TYPE_MASK) >> + CAM_GENERIC_BLOB_CMDBUFFER_TYPE_SHIFT; + blob_size = + ((*blob_ptr) & CAM_GENERIC_BLOB_CMDBUFFER_SIZE_MASK) >> + CAM_GENERIC_BLOB_CMDBUFFER_SIZE_SHIFT; + + blob_block_size = sizeof(uint32_t) + + (((blob_size + sizeof(uint32_t) - 1) / + sizeof(uint32_t)) * sizeof(uint32_t)); + + CAM_DBG(CAM_UTIL, + "Blob type=%d size=%d block_size=%d len_read=%d total=%d", + blob_type, blob_size, blob_block_size, len_read, + cmd_buf->length); + + if (len_read + blob_block_size > cmd_buf->length) { + CAM_ERR(CAM_UTIL, "Invalid Blob %d %d %d %d", + blob_type, blob_size, len_read, + cmd_buf->length); + rc = -EINVAL; + goto end; + } + + len_read += blob_block_size; + + rc = blob_handler_cb(user_data, blob_type, blob_size, + (uint8_t *)(blob_ptr + 1)); + if (rc) { + CAM_ERR(CAM_UTIL, "Error in handling blob type %d %d", + blob_type, blob_size); + goto end; + } + + blob_ptr += (blob_block_size / sizeof(uint32_t)); + } + +end: + return rc; +} diff --git a/drivers/cam_utils/cam_packet_util.h b/drivers/cam_utils/cam_packet_util.h new file mode 100644 index 000000000000..d5fc8f70ec07 --- /dev/null +++ b/drivers/cam_utils/cam_packet_util.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_PACKET_UTIL_H_ +#define _CAM_PACKET_UTIL_H_ + +#include + +/** + * @brief KMD scratch buffer information + * + * @handle: Memory handle + * @cpu_addr: Cpu address + * @offset: Offset from the start of the buffer + * @size: Size of the buffer + * @used_bytes: Used memory in bytes + * + */ +struct cam_kmd_buf_info { + int handle; + uint32_t *cpu_addr; + uint32_t offset; + uint32_t size; + uint32_t used_bytes; +}; + +/* Generic Cmd Buffer blob callback function type */ +typedef int (*cam_packet_generic_blob_handler)(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data); + +/** + * cam_packet_util_get_cmd_mem_addr() + * + * @brief Get command buffer address + * + * @handle: Command buffer memory handle + * @buf_addr: Command buffer cpu mapped address + * @len: Command buffer length + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, + size_t *len); + +/** + * cam_packet_util_validate_packet() + * + * @brief Validate the packet + * + * @packet: Packet to be validated + * + * @remain_len: CPU buff length after config offset + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len); + +/** + * cam_packet_util_validate_cmd_desc() + * + * @brief Validate the packet + * + * @cmd_desc: Command descriptor to be validated + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc); + +/** + * cam_packet_util_get_kmd_buffer() + * + * @brief Get the kmd buffer from the packet command descriptor + * + * @packet: Packet data + * @kmd_buf: Extracted the KMD buffer information + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, + struct cam_kmd_buf_info *kmd_buf_info); + +/** + * cam_packet_util_process_patches() + * + * @brief: Replace the handle in Packet to Address using the + * information from patches. + * + * @packet: Input packet containing Command Buffers and Patches + * @iommu_hdl: IOMMU handle of the HW Device that received the packet + * @sec_iommu_hdl: Secure IOMMU handle of the HW Device that + * received the packet + * + * @return: 0: Success + * Negative: Failure + */ +int cam_packet_util_process_patches(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl); + +/** + * cam_packet_util_process_generic_cmd_buffer() + * + * @brief: Process Generic Blob command buffer. This utility + * function process the command buffer and calls the + * blob_handle_cb callback for each blob that exists + * in the command buffer. + * + * @cmd_buf: Generic Blob Cmd Buffer handle + * @blob_handler_cb: Callback pointer to call for each blob exists in the + * command buffer + * @user_data: User data to be passed while callback + * + * @return: 0: Success + * Negative: Failure + */ +int cam_packet_util_process_generic_cmd_buffer( + struct cam_cmd_buf_desc *cmd_buf, + cam_packet_generic_blob_handler blob_handler_cb, void *user_data); + +#endif /* _CAM_PACKET_UTIL_H_ */ diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c new file mode 100644 index 000000000000..4f031ee720b0 --- /dev/null +++ b/drivers/cam_utils/cam_soc_util.c @@ -0,0 +1,1752 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_cx_ipeak.h" + +static char supported_clk_info[256]; +static char debugfs_dir_name[64]; + +static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, + int32_t src_clk_idx, int32_t clk_rate) +{ + int i; + long clk_rate_round; + + clk_rate_round = clk_round_rate(soc_info->clk[src_clk_idx], clk_rate); + if (clk_rate_round < 0) { + CAM_ERR(CAM_UTIL, "round failed rc = %ld", + clk_rate_round); + return -EINVAL; + } + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_rate[i][src_clk_idx] >= clk_rate_round) { + CAM_DBG(CAM_UTIL, + "soc = %d round rate = %ld actual = %d", + soc_info->clk_rate[i][src_clk_idx], + clk_rate_round, clk_rate); + return i; + } + } + + CAM_WARN(CAM_UTIL, "Invalid clock rate %ld", clk_rate_round); + return -EINVAL; +} + +/** + * cam_soc_util_get_string_from_level() + * + * @brief: Returns the string for a given clk level + * + * @level: Clock level + * + * @return: String corresponding to the clk level + */ +static const char *cam_soc_util_get_string_from_level( + enum cam_vote_level level) +{ + switch (level) { + case CAM_SUSPEND_VOTE: + return ""; + case CAM_MINSVS_VOTE: + return "MINSVS[1]"; + case CAM_LOWSVS_VOTE: + return "LOWSVS[2]"; + case CAM_SVS_VOTE: + return "SVS[3]"; + case CAM_SVSL1_VOTE: + return "SVSL1[4]"; + case CAM_NOMINAL_VOTE: + return "NOM[5]"; + case CAM_NOMINALL1_VOTE: + return "NOML1[6]"; + case CAM_TURBO_VOTE: + return "TURBO[7]"; + default: + return ""; + } +} + +/** + * cam_soc_util_get_supported_clk_levels() + * + * @brief: Returns the string of all the supported clk levels for + * the given device + * + * @soc_info: Device soc information + * + * @return: String containing all supported clk levels + */ +static const char *cam_soc_util_get_supported_clk_levels( + struct cam_hw_soc_info *soc_info) +{ + int i = 0; + + memset(supported_clk_info, 0, sizeof(supported_clk_info)); + strlcat(supported_clk_info, "Supported levels: ", + sizeof(supported_clk_info)); + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_level_valid[i] == true) { + strlcat(supported_clk_info, + cam_soc_util_get_string_from_level(i), + sizeof(supported_clk_info)); + strlcat(supported_clk_info, " ", + sizeof(supported_clk_info)); + } + } + + strlcat(supported_clk_info, "\n", sizeof(supported_clk_info)); + return supported_clk_info; +} + +static int cam_soc_util_clk_lvl_options_open(struct inode *inode, + struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t cam_soc_util_clk_lvl_options_read(struct file *file, + char __user *clk_info, size_t size_t, loff_t *loff_t) +{ + struct cam_hw_soc_info *soc_info = + (struct cam_hw_soc_info *)file->private_data; + const char *display_string = + cam_soc_util_get_supported_clk_levels(soc_info); + + return simple_read_from_buffer(clk_info, size_t, loff_t, display_string, + strlen(display_string)); +} + +static const struct file_operations cam_soc_util_clk_lvl_options = { + .open = cam_soc_util_clk_lvl_options_open, + .read = cam_soc_util_clk_lvl_options_read, +}; + +static int cam_soc_util_set_clk_lvl(void *data, u64 val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + if (val <= CAM_SUSPEND_VOTE || val >= CAM_MAX_VOTE) + return 0; + + if (soc_info->clk_level_valid[val] == true) + soc_info->clk_level_override = val; + else + soc_info->clk_level_override = 0; + + return 0; +} + +static int cam_soc_util_get_clk_lvl(void *data, u64 *val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + *val = soc_info->clk_level_override; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_soc_util_clk_lvl_control, + cam_soc_util_get_clk_lvl, cam_soc_util_set_clk_lvl, "%08llu"); + +/** + * cam_soc_util_create_clk_lvl_debugfs() + * + * @brief: Creates debugfs files to view/control device clk rates + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +static int cam_soc_util_create_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + struct dentry *dentry = NULL; + + if (!soc_info) { + CAM_ERR(CAM_UTIL, "soc info is NULL"); + return -EINVAL; + } + + if (soc_info->dentry) + return 0; + + memset(debugfs_dir_name, 0, sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, "clk_dir_", sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, soc_info->dev_name, sizeof(debugfs_dir_name)); + + dentry = soc_info->dentry; + dentry = debugfs_create_dir(debugfs_dir_name, NULL); + if (!dentry) { + CAM_ERR(CAM_UTIL, "failed to create debug directory"); + return -ENOMEM; + } + + if (!debugfs_create_file("clk_lvl_options", 0444, + dentry, soc_info, &cam_soc_util_clk_lvl_options)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_options"); + goto err; + } + + if (!debugfs_create_file("clk_lvl_control", 0644, + dentry, soc_info, &cam_soc_util_clk_lvl_control)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_control"); + goto err; + } + + CAM_DBG(CAM_UTIL, "clk lvl debugfs for %s successfully created", + soc_info->dev_name); + + return 0; + +err: + debugfs_remove_recursive(dentry); + dentry = NULL; + return -ENOMEM; +} + +/** + * cam_soc_util_remove_clk_lvl_debugfs() + * + * @brief: Removes the debugfs files used to view/control + * device clk rates + * + * @soc_info: Device soc information + * + */ +static void cam_soc_util_remove_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + debugfs_remove_recursive(soc_info->dentry); + soc_info->dentry = NULL; +} + +int cam_soc_util_get_level_from_string(const char *string, + enum cam_vote_level *level) +{ + if (!level) + return -EINVAL; + + if (!strcmp(string, "suspend")) { + *level = CAM_SUSPEND_VOTE; + } else if (!strcmp(string, "minsvs")) { + *level = CAM_MINSVS_VOTE; + } else if (!strcmp(string, "lowsvs")) { + *level = CAM_LOWSVS_VOTE; + } else if (!strcmp(string, "svs")) { + *level = CAM_SVS_VOTE; + } else if (!strcmp(string, "svs_l1")) { + *level = CAM_SVSL1_VOTE; + } else if (!strcmp(string, "nominal")) { + *level = CAM_NOMINAL_VOTE; + } else if (!strcmp(string, "nominal_l1")) { + *level = CAM_NOMINALL1_VOTE; + } else if (!strcmp(string, "turbo")) { + *level = CAM_TURBO_VOTE; + } else { + CAM_ERR(CAM_UTIL, "Invalid string %s", string); + return -EINVAL; + } + + return 0; +} + +/** + * cam_soc_util_get_clk_level_to_apply() + * + * @brief: Get the clock level to apply. If the requested level + * is not valid, bump the level to next available valid + * level. If no higher level found, return failure. + * + * @soc_info: Device soc struct to be populated + * @req_level: Requested level + * @apply_level Level to apply + * + * @return: success or failure + */ +static int cam_soc_util_get_clk_level_to_apply( + struct cam_hw_soc_info *soc_info, enum cam_vote_level req_level, + enum cam_vote_level *apply_level) +{ + if (req_level >= CAM_MAX_VOTE) { + CAM_ERR(CAM_UTIL, "Invalid clock level parameter %d", + req_level); + return -EINVAL; + } + + if (soc_info->clk_level_valid[req_level] == true) { + *apply_level = req_level; + } else { + int i; + + for (i = (req_level + 1); i < CAM_MAX_VOTE; i++) + if (soc_info->clk_level_valid[i] == true) { + *apply_level = i; + break; + } + + if (i == CAM_MAX_VOTE) { + CAM_ERR(CAM_UTIL, + "No valid clock level found to apply, req=%d", + req_level); + return -EINVAL; + } + } + + CAM_DBG(CAM_UTIL, "Req level %d, Applying %d", + req_level, *apply_level); + + return 0; +} + +int cam_soc_util_irq_enable(struct cam_hw_soc_info *soc_info) +{ + if (!soc_info) { + CAM_ERR(CAM_UTIL, "Invalid arguments"); + return -EINVAL; + } + + if (!soc_info->irq_line) { + CAM_ERR(CAM_UTIL, "No IRQ line available"); + return -ENODEV; + } + + enable_irq(soc_info->irq_line->start); + + return 0; +} + +int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info) +{ + if (!soc_info) { + CAM_ERR(CAM_UTIL, "Invalid arguments"); + return -EINVAL; + } + + if (!soc_info->irq_line) { + CAM_ERR(CAM_UTIL, "No IRQ line available"); + return -ENODEV; + } + + disable_irq(soc_info->irq_line->start); + + return 0; +} + +long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long clk_rate) +{ + if (!soc_info || (clk_index >= soc_info->num_clk) || (clk_rate == 0)) { + CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d %lu", + soc_info, clk_index, clk_rate); + return clk_rate; + } + + return clk_round_rate(soc_info->clk[clk_index], clk_rate); +} + +int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long flags) +{ + if (!soc_info || (clk_index >= soc_info->num_clk)) { + CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d", + soc_info, clk_index); + return -EINVAL; + } + + return clk_set_flags(soc_info->clk[clk_index], flags); +} + +/** + * cam_soc_util_set_clk_rate() + * + * @brief: Sets the given rate for the clk requested for + * + * @clk: Clock structure information for which rate is to be set + * @clk_name: Name of the clock for which rate is being set + * @clk_rate Clock rate to be set + * + * @return: Success or failure + */ +static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, + int32_t clk_rate) +{ + int rc = 0; + long clk_rate_round; + + if (!clk || !clk_name) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "set %s, rate %d", clk_name, clk_rate); + if (clk_rate > 0) { + clk_rate_round = clk_round_rate(clk, clk_rate); + CAM_DBG(CAM_UTIL, "new_rate %ld", clk_rate_round); + if (clk_rate_round < 0) { + CAM_ERR(CAM_UTIL, "round failed for clock %s rc = %ld", + clk_name, clk_rate_round); + return clk_rate_round; + } + rc = clk_set_rate(clk, clk_rate_round); + if (rc) { + CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name); + return rc; + } + } else if (clk_rate == INIT_RATE) { + clk_rate_round = clk_get_rate(clk); + CAM_DBG(CAM_UTIL, "init new_rate %ld", clk_rate_round); + if (clk_rate_round == 0) { + clk_rate_round = clk_round_rate(clk, 0); + if (clk_rate_round <= 0) { + CAM_ERR(CAM_UTIL, "round rate failed on %s", + clk_name); + return clk_rate_round; + } + } + rc = clk_set_rate(clk, clk_rate_round); + if (rc) { + CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name); + return rc; + } + } + + return rc; +} + +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_rate) +{ + int32_t src_clk_idx; + struct clk *clk = NULL; + int32_t apply_level; + uint32_t clk_level_override = 0; + + if (!soc_info || (soc_info->src_clk_idx < 0)) + return -EINVAL; + + src_clk_idx = soc_info->src_clk_idx; + clk_level_override = soc_info->clk_level_override; + if (clk_level_override && clk_rate) + clk_rate = + soc_info->clk_rate[clk_level_override][src_clk_idx]; + + clk = soc_info->clk[src_clk_idx]; + + if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { + apply_level = cam_soc_util_get_clk_level(soc_info, src_clk_idx, + clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s\n" + "apply level = %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, apply_level); + if (apply_level >= 0) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, + apply_level); + } + return cam_soc_util_set_clk_rate(clk, + soc_info->clk_name[src_clk_idx], clk_rate); + +} + +int cam_soc_util_clk_put(struct clk **clk) +{ + if (!(*clk)) { + CAM_ERR(CAM_UTIL, "Invalid params clk"); + return -EINVAL; + } + + clk_put(*clk); + *clk = NULL; + + return 0; +} + +static struct clk *cam_soc_util_option_clk_get(struct device_node *np, + int index) +{ + struct of_phandle_args clkspec; + struct clk *clk; + int rc; + + if (index < 0) + return ERR_PTR(-EINVAL); + + rc = of_parse_phandle_with_args(np, "clocks-option", "#clock-cells", + index, &clkspec); + if (rc) + return ERR_PTR(rc); + + clk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); + + return clk; +} + +int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info, + const char *clk_name, struct clk **clk, int32_t *clk_index, + int32_t *clk_rate) +{ + int index = 0; + int rc = 0; + struct device_node *of_node = NULL; + + if (!soc_info || !clk_name || !clk) { + CAM_ERR(CAM_UTIL, + "Invalid params soc_info %pK clk_name %s clk %pK", + soc_info, clk_name, clk); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + + index = of_property_match_string(of_node, "clock-names-option", + clk_name); + + if (index < 0) { + CAM_INFO(CAM_UTIL, "No clk data for %s", clk_name); + *clk_index = -1; + *clk = ERR_PTR(-EINVAL); + return -EINVAL; + } + + *clk = cam_soc_util_option_clk_get(of_node, index); + if (IS_ERR(*clk)) { + CAM_ERR(CAM_UTIL, "No clk named %s found. Dev %s", clk_name, + soc_info->dev_name); + *clk_index = -1; + return -EFAULT; + } + *clk_index = index; + + rc = of_property_read_u32_index(of_node, "clock-rates-option", + index, clk_rate); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading clock-rates clk_name %s index %d", + clk_name, index); + cam_soc_util_clk_put(clk); + *clk_rate = 0; + return rc; + } + + /* + * Option clocks are assumed to be available to single Device here. + * Hence use INIT_RATE instead of NO_SET_RATE. + */ + *clk_rate = (*clk_rate == 0) ? (int32_t)INIT_RATE : *clk_rate; + + CAM_DBG(CAM_UTIL, "clk_name %s index %d clk_rate %d", + clk_name, *clk_index, *clk_rate); + + return 0; +} + +int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name, + int32_t clk_rate) +{ + int rc = 0; + + if (!clk || !clk_name) + return -EINVAL; + + rc = cam_soc_util_set_clk_rate(clk, clk_name, clk_rate); + if (rc) + return rc; + + rc = clk_prepare_enable(clk); + if (rc) { + CAM_ERR(CAM_UTIL, "enable failed for %s: rc(%d)", clk_name, rc); + return rc; + } + + return rc; +} + +int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name) +{ + if (!clk || !clk_name) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "disable %s", clk_name); + clk_disable_unprepare(clk); + + return 0; +} + +/** + * cam_soc_util_clk_enable_default() + * + * @brief: This function enables the default clocks present + * in soc_info + * + * @soc_info: Device soc struct to be populated + * @clk_level: Clk level to apply while enabling + * + * @return: success or failure + */ +int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level) +{ + int i, rc = 0; + enum cam_vote_level apply_level; + + if ((soc_info->num_clk == 0) || + (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid number of clock %d", + soc_info->num_clk); + return -EINVAL; + } + + rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level, + &apply_level); + if (rc) + return rc; + + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + + for (i = 0; i < soc_info->num_clk; i++) { + rc = cam_soc_util_clk_enable(soc_info->clk[i], + soc_info->clk_name[i], + soc_info->clk_rate[apply_level][i]); + if (rc) + goto clk_disable; + if (soc_info->cam_cx_ipeak_enable) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk name = %s idx = %d\n" + "apply_level = %d clc idx = %d", + soc_info->dev_name, soc_info->clk_name[i], i, + apply_level, i); + } + + } + + return rc; + +clk_disable: + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); + for (i--; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + + return rc; +} + +/** + * cam_soc_util_clk_disable_default() + * + * @brief: This function disables the default clocks present + * in soc_info + * + * @soc_info: device soc struct to be populated + * + * @return: success or failure + */ +void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info) +{ + int i; + + if (soc_info->num_clk == 0) + return; + + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_unvote_cx_ipeak(soc_info); + for (i = soc_info->num_clk - 1; i >= 0; i--) + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); +} + +/** + * cam_soc_util_get_dt_clk_info() + * + * @brief: Parse the DT and populate the Clock properties + * + * @soc_info: device soc struct to be populated + * @src_clk_str name of src clock that has rate control + * + * @return: success or failure + */ +static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) +{ + struct device_node *of_node = NULL; + int count; + int num_clk_rates, num_clk_levels; + int i, j, rc; + int32_t num_clk_level_strings; + const char *src_clk_str = NULL; + const char *clk_control_debugfs = NULL; + const char *clk_cntl_lvl_string = NULL; + enum cam_vote_level level; + + if (!soc_info || !soc_info->dev) + return -EINVAL; + + of_node = soc_info->dev->of_node; + + if (!of_property_read_bool(of_node, "use-shared-clk")) { + CAM_DBG(CAM_UTIL, "No shared clk parameter defined"); + soc_info->use_shared_clk = false; + } else { + soc_info->use_shared_clk = true; + } + + count = of_property_count_strings(of_node, "clock-names"); + + CAM_DBG(CAM_UTIL, "E: dev_name = %s count = %d", + soc_info->dev_name, count); + if (count > CAM_SOC_MAX_CLK) { + CAM_ERR(CAM_UTIL, "invalid count of clocks, count=%d", count); + rc = -EINVAL; + return rc; + } + if (count <= 0) { + CAM_DBG(CAM_UTIL, "No clock-names found"); + count = 0; + soc_info->num_clk = count; + return 0; + } + soc_info->num_clk = count; + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(soc_info->clk_name[i])); + CAM_DBG(CAM_UTIL, "clock-names[%d] = %s", + i, soc_info->clk_name[i]); + if (rc) { + CAM_ERR(CAM_UTIL, + "i= %d count= %d reading clock-names failed", + i, count); + return rc; + } + } + + num_clk_rates = of_property_count_u32_elems(of_node, "clock-rates"); + if (num_clk_rates <= 0) { + CAM_ERR(CAM_UTIL, "reading clock-rates count failed"); + return -EINVAL; + } + + if ((num_clk_rates % soc_info->num_clk) != 0) { + CAM_ERR(CAM_UTIL, + "mismatch clk/rates, No of clocks=%d, No of rates=%d", + soc_info->num_clk, num_clk_rates); + return -EINVAL; + } + + num_clk_levels = (num_clk_rates / soc_info->num_clk); + + num_clk_level_strings = of_property_count_strings(of_node, + "clock-cntl-level"); + if (num_clk_level_strings != num_clk_levels) { + CAM_ERR(CAM_UTIL, + "Mismatch No of levels=%d, No of level string=%d", + num_clk_levels, num_clk_level_strings); + return -EINVAL; + } + + for (i = 0; i < num_clk_levels; i++) { + rc = of_property_read_string_index(of_node, + "clock-cntl-level", i, &clk_cntl_lvl_string); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading clock-cntl-level, rc=%d", rc); + return rc; + } + + rc = cam_soc_util_get_level_from_string(clk_cntl_lvl_string, + &level); + if (rc) + return rc; + + CAM_DBG(CAM_UTIL, + "[%d] : %s %d", i, clk_cntl_lvl_string, level); + soc_info->clk_level_valid[level] = true; + for (j = 0; j < soc_info->num_clk; j++) { + rc = of_property_read_u32_index(of_node, "clock-rates", + ((i * soc_info->num_clk) + j), + &soc_info->clk_rate[level][j]); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading clock-rates, rc=%d", + rc); + return rc; + } + + soc_info->clk_rate[level][j] = + (soc_info->clk_rate[level][j] == 0) ? + (int32_t)NO_SET_RATE : + soc_info->clk_rate[level][j]; + + CAM_DBG(CAM_UTIL, "soc_info->clk_rate[%d][%d] = %d", + level, j, + soc_info->clk_rate[level][j]); + } + } + + soc_info->src_clk_idx = -1; + rc = of_property_read_string_index(of_node, "src-clock-name", 0, + &src_clk_str); + if (rc || !src_clk_str) { + CAM_DBG(CAM_UTIL, "No src_clk_str found"); + rc = 0; + goto end; + } + + for (i = 0; i < soc_info->num_clk; i++) { + if (strcmp(soc_info->clk_name[i], src_clk_str) == 0) { + soc_info->src_clk_idx = i; + CAM_DBG(CAM_UTIL, "src clock = %s, index = %d", + src_clk_str, i); + break; + } + } + + rc = of_property_read_string_index(of_node, + "clock-control-debugfs", 0, &clk_control_debugfs); + if (rc || !clk_control_debugfs) { + CAM_DBG(CAM_UTIL, "No clock_control_debugfs property found"); + rc = 0; + goto end; + } + + if (strcmp("true", clk_control_debugfs) == 0) + soc_info->clk_control_enable = true; + + CAM_DBG(CAM_UTIL, "X: dev_name = %s count = %d", + soc_info->dev_name, count); +end: + return rc; +} + +int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level) +{ + int i, rc = 0; + enum cam_vote_level apply_level; + + if ((soc_info->num_clk == 0) || + (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid number of clock %d", + soc_info->num_clk); + return -EINVAL; + } + + rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level, + &apply_level); + if (rc) + return rc; + + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + + for (i = 0; i < soc_info->num_clk; i++) { + rc = cam_soc_util_set_clk_rate(soc_info->clk[i], + soc_info->clk_name[i], + soc_info->clk_rate[apply_level][i]); + if (rc < 0) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk_name = %s idx = %d\n" + "apply_level = %d", + soc_info->dev_name, soc_info->clk_name[i], + i, apply_level); + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); + break; + } + } + + return rc; +}; + +static int cam_soc_util_get_dt_gpio_req_tbl(struct device_node *of_node, + struct cam_soc_gpio_data *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int32_t rc = 0, i = 0; + uint32_t count = 0; + uint32_t *val_array = NULL; + + if (!of_get_property(of_node, "gpio-req-tbl-num", &count)) + return 0; + + count /= sizeof(uint32_t); + if (!count) { + CAM_ERR(CAM_UTIL, "gpio-req-tbl-num 0"); + return 0; + } + + val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); + if (!val_array) + return -ENOMEM; + + gconf->cam_gpio_req_tbl = kcalloc(count, sizeof(struct gpio), + GFP_KERNEL); + if (!gconf->cam_gpio_req_tbl) { + rc = -ENOMEM; + goto free_val_array; + } + gconf->cam_gpio_req_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "gpio-req-tbl-num", + val_array, count); + if (rc) { + CAM_ERR(CAM_UTIL, "failed in reading gpio-req-tbl-num, rc = %d", + rc); + goto free_gpio_req_tbl; + } + + for (i = 0; i < count; i++) { + if (val_array[i] >= gpio_array_size) { + CAM_ERR(CAM_UTIL, "gpio req tbl index %d invalid", + val_array[i]); + goto free_gpio_req_tbl; + } + gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]]; + CAM_DBG(CAM_UTIL, "cam_gpio_req_tbl[%d].gpio = %d", i, + gconf->cam_gpio_req_tbl[i].gpio); + } + + rc = of_property_read_u32_array(of_node, "gpio-req-tbl-flags", + val_array, count); + if (rc) { + CAM_ERR(CAM_UTIL, "Failed in gpio-req-tbl-flags, rc %d", rc); + goto free_gpio_req_tbl; + } + + for (i = 0; i < count; i++) { + gconf->cam_gpio_req_tbl[i].flags = val_array[i]; + CAM_DBG(CAM_UTIL, "cam_gpio_req_tbl[%d].flags = %ld", i, + gconf->cam_gpio_req_tbl[i].flags); + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "gpio-req-tbl-label", i, + &gconf->cam_gpio_req_tbl[i].label); + if (rc) { + CAM_ERR(CAM_UTIL, "Failed rc %d", rc); + goto free_gpio_req_tbl; + } + CAM_DBG(CAM_UTIL, "cam_gpio_req_tbl[%d].label = %s", i, + gconf->cam_gpio_req_tbl[i].label); + } + + kfree(val_array); + + return rc; + +free_gpio_req_tbl: + kfree(gconf->cam_gpio_req_tbl); +free_val_array: + kfree(val_array); + gconf->cam_gpio_req_tbl_size = 0; + + return rc; +} + +static int cam_soc_util_get_gpio_info(struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0, i = 0; + uint16_t *gpio_array = NULL; + int16_t gpio_array_size = 0; + struct cam_soc_gpio_data *gconf = NULL; + struct device_node *of_node = NULL; + + if (!soc_info || !soc_info->dev) + return -EINVAL; + + of_node = soc_info->dev->of_node; + + /* Validate input parameters */ + if (!of_node) { + CAM_ERR(CAM_UTIL, "Invalid param of_node"); + return -EINVAL; + } + + gpio_array_size = of_gpio_count(of_node); + + if (gpio_array_size <= 0) + return 0; + + CAM_DBG(CAM_UTIL, "gpio count %d", gpio_array_size); + + gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL); + if (!gpio_array) + goto free_gpio_conf; + + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CAM_DBG(CAM_UTIL, "gpio_array[%d] = %d", i, gpio_array[i]); + } + + gconf = kzalloc(sizeof(*gconf), GFP_KERNEL); + if (!gconf) + return -ENOMEM; + + rc = cam_soc_util_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc) { + CAM_ERR(CAM_UTIL, "failed in msm_camera_get_dt_gpio_req_tbl"); + goto free_gpio_array; + } + + gconf->cam_gpio_common_tbl = kcalloc(gpio_array_size, + sizeof(struct gpio), GFP_KERNEL); + if (!gconf->cam_gpio_common_tbl) { + rc = -ENOMEM; + goto free_gpio_array; + } + + for (i = 0; i < gpio_array_size; i++) + gconf->cam_gpio_common_tbl[i].gpio = gpio_array[i]; + + gconf->cam_gpio_common_tbl_size = gpio_array_size; + soc_info->gpio_data = gconf; + kfree(gpio_array); + + return rc; + +free_gpio_array: + kfree(gpio_array); +free_gpio_conf: + kfree(gconf); + soc_info->gpio_data = NULL; + + return rc; +} + +static int cam_soc_util_request_gpio_table( + struct cam_hw_soc_info *soc_info, bool gpio_en) +{ + int rc = 0, i = 0; + uint8_t size = 0; + struct cam_soc_gpio_data *gpio_conf = + soc_info->gpio_data; + struct gpio *gpio_tbl = NULL; + + + if (!gpio_conf) { + CAM_DBG(CAM_UTIL, "No GPIO entry"); + return 0; + } + if (gpio_conf->cam_gpio_common_tbl_size <= 0) { + CAM_ERR(CAM_UTIL, "GPIO table size is invalid"); + return -EINVAL; + } + size = gpio_conf->cam_gpio_req_tbl_size; + gpio_tbl = gpio_conf->cam_gpio_req_tbl; + + if (!gpio_tbl || !size) { + CAM_ERR(CAM_UTIL, "Invalid gpio_tbl %pK / size %d", + gpio_tbl, size); + return -EINVAL; + } + for (i = 0; i < size; i++) { + CAM_DBG(CAM_UTIL, "i=%d, gpio=%d dir=%ld", i, + gpio_tbl[i].gpio, gpio_tbl[i].flags); + } + if (gpio_en) { + for (i = 0; i < size; i++) { + rc = gpio_request_one(gpio_tbl[i].gpio, + gpio_tbl[i].flags, gpio_tbl[i].label); + if (rc) { + /* + * After GPIO request fails, contine to + * apply new gpios, outout a error message + * for driver bringup debug + */ + CAM_ERR(CAM_UTIL, "gpio %d:%s request fails", + gpio_tbl[i].gpio, gpio_tbl[i].label); + } + } + } else { + gpio_free_array(gpio_tbl, size); + } + + return rc; +} + +static int cam_soc_util_get_dt_regulator_info + (struct cam_hw_soc_info *soc_info) +{ + int rc = 0, count = 0, i = 0; + struct device_node *of_node = NULL; + + if (!soc_info || !soc_info->dev) { + CAM_ERR(CAM_UTIL, "Invalid parameters"); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + + soc_info->num_rgltr = 0; + count = of_property_count_strings(of_node, "regulator-names"); + if (count != -EINVAL) { + if (count <= 0) { + CAM_ERR(CAM_UTIL, "no regulators found"); + count = 0; + return -EINVAL; + } + + soc_info->num_rgltr = count; + + } else { + CAM_DBG(CAM_UTIL, "No regulators node found"); + return 0; + } + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = of_property_read_string_index(of_node, + "regulator-names", i, &soc_info->rgltr_name[i]); + CAM_DBG(CAM_UTIL, "rgltr_name[%d] = %s", + i, soc_info->rgltr_name[i]); + if (rc) { + CAM_ERR(CAM_UTIL, "no regulator resource at cnt=%d", i); + return -ENODEV; + } + } + + if (!of_property_read_bool(of_node, "rgltr-cntrl-support")) { + CAM_DBG(CAM_UTIL, "No regulator control parameter defined"); + soc_info->rgltr_ctrl_support = false; + return 0; + } + + soc_info->rgltr_ctrl_support = true; + + rc = of_property_read_u32_array(of_node, "rgltr-min-voltage", + soc_info->rgltr_min_volt, soc_info->num_rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "No minimum volatage value found, rc=%d", rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, "rgltr-max-voltage", + soc_info->rgltr_max_volt, soc_info->num_rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "No maximum volatage value found, rc=%d", rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, "rgltr-load-current", + soc_info->rgltr_op_mode, soc_info->num_rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "No Load curent found rc=%d", rc); + return -EINVAL; + } + + return rc; +} + +int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + struct device_node *of_node = NULL; + int count = 0, i = 0, rc = 0; + + if (!soc_info || !soc_info->dev) + return -EINVAL; + + of_node = soc_info->dev->of_node; + + rc = of_property_read_u32(of_node, "cell-index", &soc_info->index); + if (rc) { + CAM_ERR(CAM_UTIL, "device %s failed to read cell-index", + soc_info->dev_name); + return rc; + } + + count = of_property_count_strings(of_node, "reg-names"); + if (count <= 0) { + CAM_DBG(CAM_UTIL, "no reg-names found for: %s", + soc_info->dev_name); + count = 0; + } + soc_info->num_mem_block = count; + + for (i = 0; i < soc_info->num_mem_block; i++) { + rc = of_property_read_string_index(of_node, "reg-names", i, + &soc_info->mem_block_name[i]); + if (rc) { + CAM_ERR(CAM_UTIL, "failed to read reg-names at %d", i); + return rc; + } + soc_info->mem_block[i] = + platform_get_resource_byname(soc_info->pdev, + IORESOURCE_MEM, soc_info->mem_block_name[i]); + + if (!soc_info->mem_block[i]) { + CAM_ERR(CAM_UTIL, "no mem resource by name %s", + soc_info->mem_block_name[i]); + rc = -ENODEV; + return rc; + } + } + + if (soc_info->num_mem_block > 0) { + rc = of_property_read_u32_array(of_node, "reg-cam-base", + soc_info->mem_block_cam_base, soc_info->num_mem_block); + if (rc) { + CAM_ERR(CAM_UTIL, "Error reading register offsets"); + return rc; + } + } + + rc = of_property_read_string_index(of_node, "interrupt-names", 0, + &soc_info->irq_name); + if (rc) { + CAM_DBG(CAM_UTIL, "No interrupt line preset for: %s", + soc_info->dev_name); + rc = 0; + } else { + soc_info->irq_line = + platform_get_resource_byname(soc_info->pdev, + IORESOURCE_IRQ, soc_info->irq_name); + if (!soc_info->irq_line) { + CAM_ERR(CAM_UTIL, "no irq resource"); + rc = -ENODEV; + return rc; + } + } + + rc = of_property_read_string_index(of_node, "compatible", 0, + (const char **)&soc_info->compatible); + if (rc) { + CAM_DBG(CAM_UTIL, "No compatible string present for: %s", + soc_info->dev_name); + rc = 0; + } + + rc = cam_soc_util_get_dt_regulator_info(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_get_dt_clk_info(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_get_gpio_info(soc_info); + if (rc) + return rc; + + if (of_find_property(of_node, "qcom,cam-cx-ipeak", NULL)) + rc = cam_cx_ipeak_register_cx_ipeak(soc_info); + + return rc; +} + +/** + * cam_soc_util_get_regulator() + * + * @brief: Get regulator resource named vdd + * + * @dev: Device associated with regulator + * @reg: Return pointer to be filled with regulator on success + * @rgltr_name: Name of regulator to get + * + * @return: 0 for Success, negative value for failure + */ +static int cam_soc_util_get_regulator(struct device *dev, + struct regulator **reg, const char *rgltr_name) +{ + int rc = 0; + *reg = regulator_get(dev, rgltr_name); + if (IS_ERR_OR_NULL(*reg)) { + rc = PTR_ERR(*reg); + rc = rc ? rc : -EINVAL; + CAM_ERR(CAM_UTIL, "Regulator %s get failed %d", rgltr_name, rc); + *reg = NULL; + } + return rc; +} + +int cam_soc_util_regulator_disable(struct regulator *rgltr, + const char *rgltr_name, uint32_t rgltr_min_volt, + uint32_t rgltr_max_volt, uint32_t rgltr_op_mode, + uint32_t rgltr_delay_ms) +{ + int32_t rc = 0; + + if (!rgltr) { + CAM_ERR(CAM_UTIL, "Invalid NULL parameter"); + return -EINVAL; + } + + rc = regulator_disable(rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "%s regulator disable failed", rgltr_name); + return rc; + } + + if (rgltr_delay_ms > 20) + msleep(rgltr_delay_ms); + else if (rgltr_delay_ms) + usleep_range(rgltr_delay_ms * 1000, + (rgltr_delay_ms * 1000) + 1000); + + if (regulator_count_voltages(rgltr) > 0) { + regulator_set_load(rgltr, 0); + regulator_set_voltage(rgltr, 0, rgltr_max_volt); + } + + return rc; +} + + +int cam_soc_util_regulator_enable(struct regulator *rgltr, + const char *rgltr_name, + uint32_t rgltr_min_volt, uint32_t rgltr_max_volt, + uint32_t rgltr_op_mode, uint32_t rgltr_delay) +{ + int32_t rc = 0; + + if (!rgltr) { + CAM_ERR(CAM_UTIL, "Invalid NULL parameter"); + return -EINVAL; + } + + if (regulator_count_voltages(rgltr) > 0) { + CAM_DBG(CAM_UTIL, "voltage min=%d, max=%d", + rgltr_min_volt, rgltr_max_volt); + + rc = regulator_set_voltage( + rgltr, rgltr_min_volt, rgltr_max_volt); + if (rc) { + CAM_ERR(CAM_UTIL, "%s set voltage failed", rgltr_name); + return rc; + } + + rc = regulator_set_load(rgltr, rgltr_op_mode); + if (rc) { + CAM_ERR(CAM_UTIL, "%s set optimum mode failed", + rgltr_name); + return rc; + } + } + + rc = regulator_enable(rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "%s regulator_enable failed", rgltr_name); + return rc; + } + + if (rgltr_delay > 20) + msleep(rgltr_delay); + else if (rgltr_delay) + usleep_range(rgltr_delay * 1000, + (rgltr_delay * 1000) + 1000); + + return rc; +} + +static int cam_soc_util_request_pinctrl( + struct cam_hw_soc_info *soc_info) +{ + + struct cam_soc_pinctrl_info *device_pctrl = &soc_info->pinctrl_info; + struct device *dev = soc_info->dev; + + device_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(device_pctrl->pinctrl)) { + CAM_DBG(CAM_UTIL, "Pinctrl not available"); + device_pctrl->pinctrl = NULL; + return 0; + } + device_pctrl->gpio_state_active = + pinctrl_lookup_state(device_pctrl->pinctrl, + CAM_SOC_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_active)) { + CAM_ERR(CAM_UTIL, + "Failed to get the active state pinctrl handle"); + device_pctrl->gpio_state_active = NULL; + return -EINVAL; + } + device_pctrl->gpio_state_suspend + = pinctrl_lookup_state(device_pctrl->pinctrl, + CAM_SOC_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_suspend)) { + CAM_ERR(CAM_UTIL, + "Failed to get the suspend state pinctrl handle"); + device_pctrl->gpio_state_suspend = NULL; + return -EINVAL; + } + return 0; +} + +static void cam_soc_util_regulator_disable_default( + struct cam_hw_soc_info *soc_info) +{ + int j = 0; + uint32_t num_rgltr = soc_info->num_rgltr; + + for (j = num_rgltr-1; j >= 0; j--) { + if (soc_info->rgltr_ctrl_support == true) { + cam_soc_util_regulator_disable(soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + } else { + if (soc_info->rgltr[j]) + regulator_disable(soc_info->rgltr[j]); + } + } +} + +static int cam_soc_util_regulator_enable_default( + struct cam_hw_soc_info *soc_info) +{ + int j = 0, rc = 0; + uint32_t num_rgltr = soc_info->num_rgltr; + + for (j = 0; j < num_rgltr; j++) { + if (soc_info->rgltr_ctrl_support == true) { + rc = cam_soc_util_regulator_enable(soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + } else { + if (soc_info->rgltr[j]) + rc = regulator_enable(soc_info->rgltr[j]); + } + + if (rc) { + CAM_ERR(CAM_UTIL, "%s enable failed", + soc_info->rgltr_name[j]); + goto disable_rgltr; + } + } + + return rc; +disable_rgltr: + + for (j--; j >= 0; j--) { + if (soc_info->rgltr_ctrl_support == true) { + cam_soc_util_regulator_disable(soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + } else { + if (soc_info->rgltr[j]) + regulator_disable(soc_info->rgltr[j]); + } + } + + return rc; +} + +int cam_soc_util_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t handler, void *irq_data) +{ + int i = 0, rc = 0; + + if (!soc_info || !soc_info->dev) { + CAM_ERR(CAM_UTIL, "Invalid parameters"); + return -EINVAL; + } + + for (i = 0; i < soc_info->num_mem_block; i++) { + if (soc_info->reserve_mem) { + if (!request_mem_region(soc_info->mem_block[i]->start, + resource_size(soc_info->mem_block[i]), + soc_info->mem_block_name[i])){ + CAM_ERR(CAM_UTIL, + "Error Mem region request Failed:%s", + soc_info->mem_block_name[i]); + rc = -ENOMEM; + goto unmap_base; + } + } + soc_info->reg_map[i].mem_base = ioremap( + soc_info->mem_block[i]->start, + resource_size(soc_info->mem_block[i])); + if (!soc_info->reg_map[i].mem_base) { + CAM_ERR(CAM_UTIL, "i= %d base NULL", i); + rc = -ENOMEM; + goto unmap_base; + } + soc_info->reg_map[i].mem_cam_base = + soc_info->mem_block_cam_base[i]; + soc_info->reg_map[i].size = + resource_size(soc_info->mem_block[i]); + soc_info->num_reg_map++; + } + + for (i = 0; i < soc_info->num_rgltr; i++) { + if (soc_info->rgltr_name[i] == NULL) { + CAM_ERR(CAM_UTIL, "can't find regulator name"); + goto put_regulator; + } + + rc = cam_soc_util_get_regulator(soc_info->dev, + &soc_info->rgltr[i], + soc_info->rgltr_name[i]); + if (rc) + goto put_regulator; + } + + if (soc_info->irq_line) { + rc = devm_request_irq(soc_info->dev, soc_info->irq_line->start, + handler, IRQF_TRIGGER_RISING, + soc_info->irq_name, irq_data); + if (rc) { + CAM_ERR(CAM_UTIL, "irq request fail"); + rc = -EBUSY; + goto put_regulator; + } + disable_irq(soc_info->irq_line->start); + soc_info->irq_data = irq_data; + } + + /* Get Clock */ + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_UTIL, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + goto put_clk; + } + } + + rc = cam_soc_util_request_pinctrl(soc_info); + if (rc) + CAM_DBG(CAM_UTIL, "Failed in request pinctrl, rc=%d", rc); + + rc = cam_soc_util_request_gpio_table(soc_info, true); + if (rc) { + CAM_ERR(CAM_UTIL, "Failed in request gpio table, rc=%d", rc); + goto put_clk; + } + + if (soc_info->clk_control_enable) + cam_soc_util_create_clk_lvl_debugfs(soc_info); + + return rc; + +put_clk: + if (i == -1) + i = soc_info->num_clk; + for (i = i - 1; i >= 0; i--) { + if (soc_info->clk[i]) { + clk_put(soc_info->clk[i]); + soc_info->clk[i] = NULL; + } + } + + if (soc_info->irq_line) { + disable_irq(soc_info->irq_line->start); + devm_free_irq(soc_info->dev, + soc_info->irq_line->start, irq_data); + } + +put_regulator: + if (i == -1) + i = soc_info->num_rgltr; + for (i = i - 1; i >= 0; i--) { + if (soc_info->rgltr[i]) { + regulator_disable(soc_info->rgltr[i]); + regulator_put(soc_info->rgltr[i]); + soc_info->rgltr[i] = NULL; + } + } + +unmap_base: + if (i == -1) + i = soc_info->num_reg_map; + for (i = i - 1; i >= 0; i--) { + if (soc_info->reserve_mem) + release_mem_region(soc_info->mem_block[i]->start, + resource_size(soc_info->mem_block[i])); + iounmap(soc_info->reg_map[i].mem_base); + soc_info->reg_map[i].mem_base = NULL; + soc_info->reg_map[i].size = 0; + } + + return rc; +} + +int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info) +{ + int i; + + if (!soc_info || !soc_info->dev) { + CAM_ERR(CAM_UTIL, "Invalid parameter"); + return -EINVAL; + } + + for (i = soc_info->num_clk - 1; i >= 0; i--) { + clk_put(soc_info->clk[i]); + soc_info->clk[i] = NULL; + } + + for (i = soc_info->num_rgltr - 1; i >= 0; i--) { + if (soc_info->rgltr[i]) { + regulator_put(soc_info->rgltr[i]); + soc_info->rgltr[i] = NULL; + } + } + + for (i = soc_info->num_reg_map - 1; i >= 0; i--) { + iounmap(soc_info->reg_map[i].mem_base); + soc_info->reg_map[i].mem_base = NULL; + soc_info->reg_map[i].size = 0; + } + + if (soc_info->irq_line) { + disable_irq(soc_info->irq_line->start); + devm_free_irq(soc_info->dev, + soc_info->irq_line->start, soc_info->irq_data); + } + + if (soc_info->pinctrl_info.pinctrl) + devm_pinctrl_put(soc_info->pinctrl_info.pinctrl); + + + /* release for gpio */ + cam_soc_util_request_gpio_table(soc_info, false); + + if (soc_info->clk_control_enable) + cam_soc_util_remove_clk_lvl_debugfs(soc_info); + + return 0; +} + +int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, + bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq) +{ + int rc = 0; + + if (!soc_info) + return -EINVAL; + + rc = cam_soc_util_regulator_enable_default(soc_info); + if (rc) { + CAM_ERR(CAM_UTIL, "Regulators enable failed"); + return rc; + } + + if (enable_clocks) { + rc = cam_soc_util_clk_enable_default(soc_info, clk_level); + if (rc) + goto disable_regulator; + } + + if (enable_irq) { + rc = cam_soc_util_irq_enable(soc_info); + if (rc) + goto disable_clk; + } + + if (soc_info->pinctrl_info.pinctrl && + soc_info->pinctrl_info.gpio_state_active) { + rc = pinctrl_select_state(soc_info->pinctrl_info.pinctrl, + soc_info->pinctrl_info.gpio_state_active); + + if (rc) + goto disable_irq; + } + + return rc; + +disable_irq: + if (enable_irq) + cam_soc_util_irq_disable(soc_info); + +disable_clk: + if (enable_clocks) + cam_soc_util_clk_disable_default(soc_info); + +disable_regulator: + cam_soc_util_regulator_disable_default(soc_info); + + + return rc; +} + +int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq) +{ + int rc = 0; + + if (!soc_info) + return -EINVAL; + + if (disable_irq) + rc |= cam_soc_util_irq_disable(soc_info); + + if (disable_clocks) + cam_soc_util_clk_disable_default(soc_info); + + cam_soc_util_regulator_disable_default(soc_info); + + if (soc_info->pinctrl_info.pinctrl && + soc_info->pinctrl_info.gpio_state_suspend) + rc = pinctrl_select_state(soc_info->pinctrl_info.pinctrl, + soc_info->pinctrl_info.gpio_state_suspend); + + return rc; +} + +int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, int size) +{ + void __iomem *base_addr = NULL; + + CAM_DBG(CAM_UTIL, "base_idx %u size=%d", base_index, size); + + if (!soc_info || base_index >= soc_info->num_reg_map || + size <= 0 || (offset + size) >= + CAM_SOC_GET_REG_MAP_SIZE(soc_info, base_index)) + return -EINVAL; + + base_addr = CAM_SOC_GET_REG_MAP_START(soc_info, base_index); + + /* + * All error checking already done above, + * hence ignoring the return value below. + */ + cam_io_dump(base_addr, offset, size); + + return 0; +} + +uint32_t cam_soc_util_get_vote_level(struct cam_hw_soc_info *soc_info, + uint64_t clock_rate) +{ + int i = 0; + + if (!clock_rate) + return CAM_SVS_VOTE; + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_level_valid[i] && + soc_info->clk_rate[i][soc_info->src_clk_idx] >= + clock_rate) { + CAM_DBG(CAM_UTIL, + "Clock rate %lld, selected clock level %d", + clock_rate, i); + return i; + } + } + + return CAM_TURBO_VOTE; +} diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h new file mode 100644 index 000000000000..bfa6183bf739 --- /dev/null +++ b/drivers/cam_utils/cam_soc_util.h @@ -0,0 +1,638 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SOC_UTIL_H_ +#define _CAM_SOC_UTIL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_io_util.h" + +#define NO_SET_RATE -1 +#define INIT_RATE -2 + +/* maximum number of device block */ +#define CAM_SOC_MAX_BLOCK 7 + +/* maximum number of device base */ +#define CAM_SOC_MAX_BASE CAM_SOC_MAX_BLOCK + +/* maximum number of device regulator */ +#define CAM_SOC_MAX_REGULATOR 5 + +/* maximum number of device clock */ +#define CAM_SOC_MAX_CLK 32 + +/* DDR device types */ +#define DDR_TYPE_LPDDR4 6 +#define DDR_TYPE_LPDDR4X 7 +#define DDR_TYPE_LPDDR5 8 +#define DDR_TYPE_LPDDR5X 9 + +/** + * enum cam_vote_level - Enum for voting level + * + * @CAM_SUSPEND_VOTE : Suspend vote + * @CAM_MINSVS_VOTE : Min SVS vote + * @CAM_LOWSVS_VOTE : Low SVS vote + * @CAM_SVS_VOTE : SVS vote + * @CAM_SVSL1_VOTE : SVS Plus vote + * @CAM_NOMINAL_VOTE : Nominal vote + * @CAM_NOMINALL1_VOTE: Nominal plus vote + * @CAM_TURBO_VOTE : Turbo vote + * @CAM_MAX_VOTE : Max voting level, This is invalid level. + */ +enum cam_vote_level { + CAM_SUSPEND_VOTE, + CAM_MINSVS_VOTE, + CAM_LOWSVS_VOTE, + CAM_SVS_VOTE, + CAM_SVSL1_VOTE, + CAM_NOMINAL_VOTE, + CAM_NOMINALL1_VOTE, + CAM_TURBO_VOTE, + CAM_MAX_VOTE, +}; + +/* pinctrl states */ +#define CAM_SOC_PINCTRL_STATE_SLEEP "cam_suspend" +#define CAM_SOC_PINCTRL_STATE_DEFAULT "cam_default" + +/** + * struct cam_soc_reg_map: Information about the mapped register space + * + * @mem_base: Starting location of MAPPED register space + * @mem_cam_base: Starting offset of this register space compared + * to ENTIRE Camera register space + * @size: Size of register space + **/ +struct cam_soc_reg_map { + void __iomem *mem_base; + uint32_t mem_cam_base; + resource_size_t size; +}; + +/** + * struct cam_soc_pinctrl_info: Information about pinctrl data + * + * @pinctrl: pintrl object + * @gpio_state_active: default pinctrl state + * @gpio_state_suspend suspend state of pinctrl + **/ +struct cam_soc_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; +}; + +/** + * struct cam_soc_gpio_data: Information about the gpio pins + * + * @cam_gpio_common_tbl: It is list of al the gpios present in gpios node + * @cam_gpio_common_tbl_size: It is equal to number of gpios prsent in + * gpios node in DTSI + * @cam_gpio_req_tbl It is list of al the requesetd gpios + * @cam_gpio_req_tbl_size: It is size of requested gpios + **/ +struct cam_soc_gpio_data { + struct gpio *cam_gpio_common_tbl; + uint8_t cam_gpio_common_tbl_size; + struct gpio *cam_gpio_req_tbl; + uint8_t cam_gpio_req_tbl_size; +}; + +/** + * struct cam_hw_soc_info: Soc information pertaining to specific instance of + * Camera hardware driver module + * + * @pdev: Platform device pointer + * @device: Device pointer + * @hw_version: Camera device version + * @index: Instance id for the camera device + * @dev_name: Device Name + * @irq_name: Name of the irq associated with the device + * @irq_line: Irq resource + * @irq_data: Private data that is passed when IRQ is requested + * @compatible: Compatible string associated with the device + * @num_mem_block: Number of entry in the "reg-names" + * @mem_block_name: Array of the reg block name + * @mem_block_cam_base: Array of offset of this register space compared + * to ENTIRE Camera register space + * @mem_block: Associated resource structs + * @reg_map: Array of Mapped register info for the "reg-names" + * @num_reg_map: Number of mapped register space associated + * with mem_block. num_reg_map = num_mem_block in + * most cases + * @reserve_mem: Whether to reserve memory for Mem blocks + * @num_rgltr: Number of regulators + * @rgltr_name: Array of regulator names + * @rgltr_ctrl_support: Whether regulator control is supported + * @rgltr_min_volt: Array of minimum regulator voltage + * @rgltr_max_volt: Array of maximum regulator voltage + * @rgltr_op_mode: Array of regulator operation mode + * @rgltr_type: Array of regulator names + * @rgltr: Array of associated regulator resources + * @rgltr_delay: Array of regulator delay values + * @num_clk: Number of clocks + * @clk_name: Array of clock names + * @clk: Array of associated clock resources + * @clk_rate: 2D array of clock rates representing clock rate + * values at different vote levels + * @prev_clk_level Last vote level + * @src_clk_idx: Source clock index that is rate-controllable + * @clk_level_valid: Indicates whether corresponding level is valid + * @gpio_data: Pointer to gpio info + * @pinctrl_info: Pointer to pinctrl info + * @dentry: Debugfs entry + * @clk_level_override: Clk level set from debugfs + * @clk_control: Enable/disable clk rate control through debugfs + * @cam_cx_ipeak_enable cx-ipeak enable/disable flag + * @cam_cx_ipeak_bit cx-ipeak mask for driver + * @soc_private: Soc private data + */ +struct cam_hw_soc_info { + struct platform_device *pdev; + struct device *dev; + uint32_t hw_version; + uint32_t index; + const char *dev_name; + const char *irq_name; + struct resource *irq_line; + void *irq_data; + const char *compatible; + + uint32_t num_mem_block; + const char *mem_block_name[CAM_SOC_MAX_BLOCK]; + uint32_t mem_block_cam_base[CAM_SOC_MAX_BLOCK]; + struct resource *mem_block[CAM_SOC_MAX_BLOCK]; + struct cam_soc_reg_map reg_map[CAM_SOC_MAX_BASE]; + uint32_t num_reg_map; + uint32_t reserve_mem; + + uint32_t num_rgltr; + const char *rgltr_name[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_ctrl_support; + uint32_t rgltr_min_volt[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_max_volt[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_op_mode[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_type[CAM_SOC_MAX_REGULATOR]; + struct regulator *rgltr[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_delay[CAM_SOC_MAX_REGULATOR]; + + uint32_t use_shared_clk; + uint32_t num_clk; + const char *clk_name[CAM_SOC_MAX_CLK]; + struct clk *clk[CAM_SOC_MAX_CLK]; + int32_t clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK]; + int32_t prev_clk_level; + int32_t src_clk_idx; + bool clk_level_valid[CAM_MAX_VOTE]; + + struct cam_soc_gpio_data *gpio_data; + struct cam_soc_pinctrl_info pinctrl_info; + + struct dentry *dentry; + uint32_t clk_level_override; + bool clk_control_enable; + bool cam_cx_ipeak_enable; + int32_t cam_cx_ipeak_bit; + + void *soc_private; +}; + +/* + * CAM_SOC_GET_REG_MAP_START + * + * @brief: This MACRO will get the mapped starting address + * where the register space can be accessed + * + * @__soc_info: Device soc information + * @__base_index: Index of register space in the HW block + * + * @return: Returns a pointer to the mapped register memory + */ +#define CAM_SOC_GET_REG_MAP_START(__soc_info, __base_index) \ + ((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \ + NULL : __soc_info->reg_map[__base_index].mem_base) + +/* + * CAM_SOC_GET_REG_MAP_CAM_BASE + * + * @brief: This MACRO will get the cam_base of the + * register space + * + * @__soc_info: Device soc information + * @__base_index: Index of register space in the HW block + * + * @return: Returns an int32_t value. + * Failure: -1 + * Success: Starting offset of register space compared + * to entire Camera Register Map + */ +#define CAM_SOC_GET_REG_MAP_CAM_BASE(__soc_info, __base_index) \ + ((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \ + -1 : __soc_info->reg_map[__base_index].mem_cam_base) + +/* + * CAM_SOC_GET_REG_MAP_SIZE + * + * @brief: This MACRO will get the size of the mapped + * register space + * + * @__soc_info: Device soc information + * @__base_index: Index of register space in the HW block + * + * @return: Returns a uint32_t value. + * Failure: 0 + * Success: Non-zero size of mapped register space + */ +#define CAM_SOC_GET_REG_MAP_SIZE(__soc_info, __base_index) \ + ((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \ + 0 : __soc_info->reg_map[__base_index].size) + +/** + * cam_soc_util_get_level_from_string() + * + * @brief: Get the associated vote level for the input string + * + * @string: Input string to compare with. + * @level: Vote level corresponds to input string. + * + * @return: Success or failure + */ +int cam_soc_util_get_level_from_string(const char *string, + enum cam_vote_level *level); + +/** + * cam_soc_util_get_dt_properties() + * + * @brief: Parse the DT and populate the common properties that + * are part of the soc_info structure - register map, + * clocks, regulators, irq, etc. + * + * @soc_info: Device soc struct to be populated + * + * @return: Success or failure + */ +int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_request_platform_resource() + * + * @brief: Request regulator, irq, and clock resources + * + * @soc_info: Device soc information + * @handler: Irq handler function pointer + * @irq_data: Irq handler function CB data + * + * @return: Success or failure + */ +int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info, + irq_handler_t handler, void *irq_data); + +/** + * cam_soc_util_release_platform_resource() + * + * @brief: Release regulator, irq, and clock resources + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_enable_platform_resource() + * + * @brief: Enable regulator, irq resources + * + * @soc_info: Device soc information + * @enable_clocks: Boolean flag: + * TRUE: Enable all clocks in soc_info Now. + * False: Don't enable clocks Now. Driver will + * enable independently. + * @clk_level: Clock level to be applied. + * Applicable only if enable_clocks is true + * Valid range : 0 to (CAM_MAX_VOTE - 1) + * @enable_irq: Boolean flag: + * TRUE: Enable IRQ in soc_info Now. + * False: Don't enable IRQ Now. Driver will + * enable independently. + * + * @return: Success or failure + */ +int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, + bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq); + +/** + * cam_soc_util_disable_platform_resource() + * + * @brief: Disable regulator, irq resources + * + * @soc_info: Device soc information + * @disable_irq: Boolean flag: + * TRUE: Disable IRQ in soc_info Now. + * False: Don't disable IRQ Now. Driver will + * disable independently. + * + * @return: Success or failure + */ +int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq); + +/** + * cam_soc_util_get_clk_round_rate() + * + * @brief: Get the rounded clock rate for the given clock's + * clock rate value + * + * @soc_info: Device soc information + * @clk_index: Clock index in soc_info for which round rate is needed + * @clk_rate: Input clock rate for which rounded rate is needed + * + * @return: Rounded clock rate + */ +long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long clk_rate); + +/** + * cam_soc_util_set_clk_flags() + * + * @brief: Camera SOC util to set the flags for a specified clock + * + * @soc_info: Device soc information + * @clk_index: Clock index in soc_info for which flags are to be set + * @flags: Flags to set + * + * @return: Success or Failure + */ +int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long flags); + +/** + * cam_soc_util_set_src_clk_rate() + * + * @brief: Set the rate on the source clock. + * + * @soc_info: Device soc information + * @clk_rate: Clock rate associated with the src clk + * + * @return: success or failure + */ +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_rate); + +/** + * cam_soc_util_get_option_clk_by_name() + * + * @brief: Get reference to optional clk using name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to find reference for + * @clk: Clock reference pointer to be filled if Success + * @clk_index: Clk index in the option clk array to be returned + * @clk_rate: Clk rate in the option clk array + * + * @return: 0: Success + * Negative: Failure + */ +int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info, + const char *clk_name, struct clk **clk, int32_t *clk_index, + int32_t *clk_rate); + +/** + * cam_soc_util_clk_put() + * + * @brief: Put clock specified in params + * + * @clk: Reference to the Clock that needs to be put + * + * @return: Success or failure + */ +int cam_soc_util_clk_put(struct clk **clk); + +/** + * cam_soc_util_clk_enable() + * + * @brief: Enable clock specified in params + * + * @clk: Clock that needs to be turned ON + * @clk_name: Clocks name associated with clk + * @clk_rate: Clocks rate associated with clk + * + * @return: Success or failure + */ +int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name, + int32_t clk_rate); + +/** + * cam_soc_util_set_clk_rate_level() + * + * @brief: Apply clock rates for the requested level. + * This applies the new requested level for all + * the clocks listed in DT based on their values. + * + * @soc_info: Device soc information + * @clk_level: Clock level number to set + * + * @return: Success or failure + */ +int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level); + +/** + * cam_soc_util_clk_disable() + * + * @brief: Disable clock specified in params + * + * @clk: Clock that needs to be turned OFF + * @clk_name: Clocks name associated with clk + * + * @return: Success or failure + */ +int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name); + +/** + * cam_soc_util_irq_enable() + * + * @brief: Enable IRQ in SOC + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +int cam_soc_util_irq_enable(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_irq_disable() + * + * @brief: Disable IRQ in SOC + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_regulator_enable() + * + * @brief: Enable single regulator + * + * @rgltr Regulator that needs to be turned ON + * @rgltr_name Associated Regulator name + * @rgltr_min_volt: Requested minimum volatage + * @rgltr_max_volt: Requested maximum volatage + * @rgltr_op_mode: Requested Load + * @rgltr_delay: Requested delay needed aaftre enabling regulator + * + * @return: Success or failure + */ +int cam_soc_util_regulator_enable(struct regulator *rgltr, + const char *rgltr_name, + uint32_t rgltr_min_volt, uint32_t rgltr_max_volt, + uint32_t rgltr_op_mode, uint32_t rgltr_delay); + +/** + * cam_soc_util_regulator_enable() + * + * @brief: Disable single regulator + * + * @rgltr Regulator that needs to be turned ON + * @rgltr_name Associated Regulator name + * @rgltr_min_volt: Requested minimum volatage + * @rgltr_max_volt: Requested maximum volatage + * @rgltr_op_mode: Requested Load + * @rgltr_delay: Requested delay needed aaftre enabling regulator + * + * @return: Success or failure + */ +int cam_soc_util_regulator_disable(struct regulator *rgltr, + const char *rgltr_name, + uint32_t rgltr_min_volt, uint32_t rgltr_max_volt, + uint32_t rgltr_op_mode, uint32_t rgltr_delay); + + +/** + * cam_soc_util_w() + * + * @brief: Camera SOC util for register write + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * @data: Value to be written + * + * @return: Success or Failure + */ +static inline int cam_soc_util_w(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, uint32_t data) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return -EINVAL; + return cam_io_w(data, + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_w_mb() + * + * @brief: Camera SOC util for register write with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * @data: Value to be written + * + * @return: Success or Failure + */ +static inline int cam_soc_util_w_mb(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, uint32_t data) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return -EINVAL; + return cam_io_w_mb(data, + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_r() + * + * @brief: Camera SOC util for register read + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * + * @return: Value read from the register address + */ +static inline uint32_t cam_soc_util_r(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return 0; + return cam_io_r( + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_r_mb() + * + * @brief: Camera SOC util for register read with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call rmb() independently in the caller. + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * + * @return: Value read from the register address + */ +static inline uint32_t cam_soc_util_r_mb(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return 0; + return cam_io_r_mb( + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_reg_dump() + * + * @brief: Camera SOC util for dumping a range of register + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Start register offset for the dump + * @size: Size specifying the range for dump + * + * @return: Success or Failure + */ +int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, int size); + +void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info); + +int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level); + +uint32_t cam_soc_util_get_vote_level(struct cam_hw_soc_info *soc_info, + uint64_t clock_rate); + +#endif /* _CAM_SOC_UTIL_H_ */ diff --git a/drivers/cam_utils/cam_trace.c b/drivers/cam_utils/cam_trace.c new file mode 100644 index 000000000000..d4a6c9279081 --- /dev/null +++ b/drivers/cam_utils/cam_trace.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +/* Instantiate tracepoints */ +#define CREATE_TRACE_POINTS +#include "cam_trace.h" diff --git a/drivers/cam_utils/cam_trace.h b/drivers/cam_utils/cam_trace.h new file mode 100644 index 000000000000..95bc95da9e75 --- /dev/null +++ b/drivers/cam_utils/cam_trace.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#if !defined(_CAM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _CAM_TRACE_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM camera +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE ../../techpack/camera/drivers/cam_utils/cam_trace + +#include +#include +#include "cam_req_mgr_core.h" +#include "cam_req_mgr_interface.h" +#include "cam_context.h" + +TRACE_EVENT(cam_context_state, + TP_PROTO(const char *name, struct cam_context *ctx), + TP_ARGS(name, ctx), + TP_STRUCT__entry( + __field(void*, ctx) + __field(uint32_t, state) + __string(name, name) + ), + TP_fast_assign( + __entry->ctx = ctx; + __entry->state = ctx->state; + __assign_str(name, name); + ), + TP_printk( + "%s: State ctx=%p ctx_state=%u", + __get_str(name), __entry->ctx, __entry->state + ) +); + +TRACE_EVENT(cam_isp_activated_irq, + TP_PROTO(struct cam_context *ctx, unsigned int substate, + unsigned int event, uint64_t timestamp), + TP_ARGS(ctx, substate, event, timestamp), + TP_STRUCT__entry( + __field(void*, ctx) + __field(uint32_t, state) + __field(uint32_t, substate) + __field(uint32_t, event) + __field(uint64_t, ts) + ), + TP_fast_assign( + __entry->ctx = ctx; + __entry->state = ctx->state; + __entry->substate = substate; + __entry->event = event; + __entry->ts = timestamp; + ), + TP_printk( + "ISP: IRQ ctx=%p ctx_state=%u substate=%u event=%u ts=%llu", + __entry->ctx, __entry->state, __entry->substate, + __entry->event, __entry->ts + ) +); + +TRACE_EVENT(cam_icp_fw_dbg, + TP_PROTO(char *dbg_message, uint64_t timestamp), + TP_ARGS(dbg_message, timestamp), + TP_STRUCT__entry( + __string(dbg_message, dbg_message) + __field(uint64_t, timestamp) + ), + TP_fast_assign( + __assign_str(dbg_message, dbg_message); + __entry->timestamp = timestamp; + ), + TP_printk( + "%llu %s: ", + __entry->timestamp, __get_str(dbg_message) + ) +); + +TRACE_EVENT(cam_buf_done, + TP_PROTO(const char *ctx_type, struct cam_context *ctx, + struct cam_ctx_request *req), + TP_ARGS(ctx_type, ctx, req), + TP_STRUCT__entry( + __string(ctx_type, ctx_type) + __field(void*, ctx) + __field(uint64_t, request) + ), + TP_fast_assign( + __assign_str(ctx_type, ctx_type); + __entry->ctx = ctx; + __entry->request = req->request_id; + ), + TP_printk( + "%5s: BufDone ctx=%p request=%llu", + __get_str(ctx_type), __entry->ctx, __entry->request + ) +); + +TRACE_EVENT(cam_apply_req, + TP_PROTO(const char *entity, uint64_t req_id), + TP_ARGS(entity, req_id), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint64_t, req_id) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->req_id = req_id; + ), + TP_printk( + "%8s: ApplyRequest request=%llu", + __get_str(entity), __entry->req_id + ) +); + +TRACE_EVENT(cam_flush_req, + TP_PROTO(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_flush_info *info), + TP_ARGS(link, info), + TP_STRUCT__entry( + __field(uint32_t, type) + __field(int64_t, req_id) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __entry->type = info->flush_type; + __entry->req_id = info->req_id; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "FlushRequest type=%u request=%llu link=%pK session=%pK", + __entry->type, __entry->req_id, __entry->link, + __entry->session + ) +); + +TRACE_EVENT(cam_req_mgr_connect_device, + TP_PROTO(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_device_info *info), + TP_ARGS(link, info), + TP_STRUCT__entry( + __string(name, info->name) + __field(uint32_t, id) + __field(uint32_t, delay) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __assign_str(name, info->name); + __entry->id = info->dev_id; + __entry->delay = info->p_delay; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "ReqMgr Connect name=%s id=%u pd=%d link=%pK session=%pK", + __get_str(name), __entry->id, __entry->delay, + __entry->link, __entry->session + ) +); + +TRACE_EVENT(cam_req_mgr_apply_request, + TP_PROTO(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_apply_request *req, + struct cam_req_mgr_connected_device *dev), + TP_ARGS(link, req, dev), + TP_STRUCT__entry( + __string(name, dev->dev_info.name) + __field(uint32_t, dev_id) + __field(uint64_t, req_id) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __assign_str(name, dev->dev_info.name); + __entry->dev_id = dev->dev_info.dev_id; + __entry->req_id = req->request_id; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "ReqMgr ApplyRequest devname=%s devid=%u request=%lld link=%pK session=%pK", + __get_str(name), __entry->dev_id, __entry->req_id, + __entry->link, __entry->session + ) +); + +TRACE_EVENT(cam_req_mgr_add_req, + TP_PROTO(struct cam_req_mgr_core_link *link, + int idx, struct cam_req_mgr_add_request *add_req, + struct cam_req_mgr_req_tbl *tbl, + struct cam_req_mgr_connected_device *dev), + TP_ARGS(link, idx, add_req, tbl, dev), + TP_STRUCT__entry( + __string(name, dev->dev_info.name) + __field(uint32_t, dev_id) + __field(uint64_t, req_id) + __field(uint32_t, slot_id) + __field(uint32_t, delay) + __field(uint32_t, readymap) + __field(uint32_t, devicemap) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __assign_str(name, dev->dev_info.name); + __entry->dev_id = dev->dev_info.dev_id; + __entry->req_id = add_req->req_id; + __entry->slot_id = idx; + __entry->delay = tbl->pd; + __entry->readymap = tbl->slot[idx].req_ready_map; + __entry->devicemap = tbl->dev_mask; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "ReqMgr AddRequest devname=%s devid=%d request=%lld slot=%d pd=%d readymap=%x devicemap=%d link=%pK session=%pK", + __get_str(name), __entry->dev_id, __entry->req_id, + __entry->slot_id, __entry->delay, __entry->readymap, + __entry->devicemap, __entry->link, __entry->session + ) +); + +TRACE_EVENT(cam_submit_to_hw, + TP_PROTO(const char *entity, uint64_t req_id), + TP_ARGS(entity, req_id), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint64_t, req_id) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->req_id = req_id; + ), + TP_printk( + "%8s: submit request=%llu", + __get_str(entity), __entry->req_id + ) +); + +TRACE_EVENT(cam_irq_activated, + TP_PROTO(const char *entity, uint32_t irq_type), + TP_ARGS(entity, irq_type), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint32_t, irq_type) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->irq_type = irq_type; + ), + TP_printk( + "%8s: got irq type=%d", + __get_str(entity), __entry->irq_type + ) +); + +TRACE_EVENT(cam_irq_handled, + TP_PROTO(const char *entity, uint32_t irq_type), + TP_ARGS(entity, irq_type), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint32_t, irq_type) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->irq_type = irq_type; + ), + TP_printk( + "%8s: handled irq type=%d", + __get_str(entity), __entry->irq_type + ) +); + +TRACE_EVENT(cam_cdm_cb, + TP_PROTO(const char *entity, uint32_t status), + TP_ARGS(entity, status), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint32_t, status) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->status = status; + ), + TP_printk( + "%8s: cdm cb status=%d", + __get_str(entity), __entry->status + ) +); + +#endif /* _CAM_TRACE_H */ + +/* This part must be outside protection */ +#include diff --git a/include/Kbuild b/include/Kbuild new file mode 100644 index 000000000000..bab1145bc7a7 --- /dev/null +++ b/include/Kbuild @@ -0,0 +1,2 @@ +# Top-level Makefile calls into asm-$(ARCH) +# List only non-arch directories below diff --git a/include/uapi/Kbuild b/include/uapi/Kbuild new file mode 100644 index 000000000000..93dffc4bac8d --- /dev/null +++ b/include/uapi/Kbuild @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note + +header-y += media/ diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild new file mode 100644 index 000000000000..e7971dac1051 --- /dev/null +++ b/include/uapi/media/Kbuild @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note + +header-y += cam_cpas.h +header-y += cam_defs.h +header-y += cam_fd.h +header-y += cam_icp.h +header-y += cam_isp.h +header-y += cam_isp_vfe.h +header-y += cam_isp_ife.h +header-y += cam_jpeg.h +header-y += cam_req_mgr.h +header-y += cam_sensor.h +header-y += cam_sync.h +header-y += cam_lrme.h diff --git a/include/uapi/media/cam_cpas.h b/include/uapi/media/cam_cpas.h new file mode 100644 index 000000000000..a3d3ca9d5a71 --- /dev/null +++ b/include/uapi/media/cam_cpas.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_CPAS_H__ +#define __UAPI_CAM_CPAS_H__ + +#include "cam_defs.h" + +#define CAM_FAMILY_CAMERA_SS 1 +#define CAM_FAMILY_CPAS_SS 2 + +/* AXI BW Voting Version */ +#define CAM_AXI_BW_VOTING_V2 2 + +/* AXI BW Voting Transaction Type */ +#define CAM_AXI_TRANSACTION_READ 0 +#define CAM_AXI_TRANSACTION_WRITE 1 + +/* AXI BW Voting Path Data Type */ +#define CAM_AXI_PATH_DATA_IFE_START_OFFSET 0 +#define CAM_AXI_PATH_DATA_IFE_LINEAR (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 0) +#define CAM_AXI_PATH_DATA_IFE_VID (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 1) +#define CAM_AXI_PATH_DATA_IFE_DISP (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 2) +#define CAM_AXI_PATH_DATA_IFE_STATS (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 3) +#define CAM_AXI_PATH_DATA_IFE_RDI0 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 4) +#define CAM_AXI_PATH_DATA_IFE_RDI1 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 5) +#define CAM_AXI_PATH_DATA_IFE_RDI2 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 6) +#define CAM_AXI_PATH_DATA_IFE_RDI3 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 7) +#define CAM_AXI_PATH_DATA_IFE_PDAF (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 8) +#define CAM_AXI_PATH_DATA_IFE_PIXEL_RAW \ + (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 9) +#define CAM_AXI_PATH_DATA_IFE_MAX_OFFSET \ + (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 31) + +#define CAM_AXI_PATH_DATA_IPE_START_OFFSET 32 +#define CAM_AXI_PATH_DATA_IPE_RD_IN (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 0) +#define CAM_AXI_PATH_DATA_IPE_RD_REF (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 1) +#define CAM_AXI_PATH_DATA_IPE_WR_VID (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 2) +#define CAM_AXI_PATH_DATA_IPE_WR_DISP (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 3) +#define CAM_AXI_PATH_DATA_IPE_WR_REF (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 4) +#define CAM_AXI_PATH_DATA_IPE_MAX_OFFSET \ + (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 31) + +#define CAM_AXI_PATH_DATA_ALL 256 + +/** + * struct cam_cpas_query_cap - CPAS query device capability payload + * + * @camera_family : Camera family type + * @reserved : Reserved field for alignment + * @camera_version : Camera platform version + * @cpas_version : Camera CPAS version within camera platform + * + */ +struct cam_cpas_query_cap { + uint32_t camera_family; + uint32_t reserved; + struct cam_hw_version camera_version; + struct cam_hw_version cpas_version; +}; + +/** + * struct cam_axi_per_path_bw_vote - Per path bandwidth vote information + * + * @usage_data client usage data (left/right/rdi) + * @transac_type Transaction type on the path (read/write) + * @path_data_type Path for which vote is given (video, display, rdi) + * @reserved Reserved for alignment + * @camnoc_bw CAMNOC bw for this path + * @mnoc_ab_bw MNOC AB bw for this path + * @mnoc_ib_bw MNOC IB bw for this path + * @ddr_ab_bw DDR AB bw for this path + * @ddr_ib_bw DDR IB bw for this path + */ +struct cam_axi_per_path_bw_vote { + uint32_t usage_data; + uint32_t transac_type; + uint32_t path_data_type; + uint32_t reserved; + uint64_t camnoc_bw; + uint64_t mnoc_ab_bw; + uint64_t mnoc_ib_bw; + uint64_t ddr_ab_bw; + uint64_t ddr_ib_bw; +}; + +#endif /* __UAPI_CAM_CPAS_H__ */ diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h new file mode 100644 index 000000000000..8bc561314027 --- /dev/null +++ b/include/uapi/media/cam_defs.h @@ -0,0 +1,746 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_DEFS_H__ +#define __UAPI_CAM_DEFS_H__ + +#include +#include +#include + + +/* camera op codes */ +#define CAM_COMMON_OPCODE_BASE 0x100 +#define CAM_QUERY_CAP (CAM_COMMON_OPCODE_BASE + 0x1) +#define CAM_ACQUIRE_DEV (CAM_COMMON_OPCODE_BASE + 0x2) +#define CAM_START_DEV (CAM_COMMON_OPCODE_BASE + 0x3) +#define CAM_STOP_DEV (CAM_COMMON_OPCODE_BASE + 0x4) +#define CAM_CONFIG_DEV (CAM_COMMON_OPCODE_BASE + 0x5) +#define CAM_RELEASE_DEV (CAM_COMMON_OPCODE_BASE + 0x6) +#define CAM_SD_SHUTDOWN (CAM_COMMON_OPCODE_BASE + 0x7) +#define CAM_FLUSH_REQ (CAM_COMMON_OPCODE_BASE + 0x8) +#define CAM_COMMON_OPCODE_MAX (CAM_COMMON_OPCODE_BASE + 0x9) + +#define CAM_COMMON_OPCODE_BASE_v2 0x150 +#define CAM_ACQUIRE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x1) +#define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2) + +#define CAM_EXT_OPCODE_BASE 0x200 +#define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) + +/* camera handle type */ +#define CAM_HANDLE_USER_POINTER 1 +#define CAM_HANDLE_MEM_HANDLE 2 + +/* Generic Blob CmdBuffer header properties */ +#define CAM_GENERIC_BLOB_CMDBUFFER_SIZE_MASK 0xFFFFFF00 +#define CAM_GENERIC_BLOB_CMDBUFFER_SIZE_SHIFT 8 +#define CAM_GENERIC_BLOB_CMDBUFFER_TYPE_MASK 0xFF +#define CAM_GENERIC_BLOB_CMDBUFFER_TYPE_SHIFT 0 + +/* Command Buffer Types */ +#define CAM_CMD_BUF_DMI 0x1 +#define CAM_CMD_BUF_DMI16 0x2 +#define CAM_CMD_BUF_DMI32 0x3 +#define CAM_CMD_BUF_DMI64 0x4 +#define CAM_CMD_BUF_DIRECT 0x5 +#define CAM_CMD_BUF_INDIRECT 0x6 +#define CAM_CMD_BUF_I2C 0x7 +#define CAM_CMD_BUF_FW 0x8 +#define CAM_CMD_BUF_GENERIC 0x9 +#define CAM_CMD_BUF_LEGACY 0xA + +/* UBWC API Version */ +#define CAM_UBWC_CFG_VERSION_1 1 +#define CAM_UBWC_CFG_VERSION_2 2 + +#define CAM_MAX_ACQ_RES 5 +#define CAM_MAX_HW_SPLIT 3 + + +/** + * enum flush_type_t - Identifies the various flush types + * + * @CAM_FLUSH_TYPE_REQ: Flush specific request + * @CAM_FLUSH_TYPE_ALL: Flush all requests belonging to a context + * @CAM_FLUSH_TYPE_MAX: Max enum to validate flush type + * + */ +enum flush_type_t { + CAM_FLUSH_TYPE_REQ, + CAM_FLUSH_TYPE_ALL, + CAM_FLUSH_TYPE_MAX +}; + +/** + * struct cam_control - Structure used by ioctl control for camera + * + * @op_code: This is the op code for camera control + * @size: Control command size + * @handle_type: User pointer or shared memory handle + * @reserved: Reserved field for 64 bit alignment + * @handle: Control command payload + */ +struct cam_control { + uint32_t op_code; + uint32_t size; + uint32_t handle_type; + uint32_t reserved; + uint64_t handle; +}; + +/* camera IOCTL */ +#define VIDIOC_CAM_CONTROL \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct cam_control) + +/** + * struct cam_hw_version - Structure for HW version of camera devices + * + * @major : Hardware version major + * @minor : Hardware version minor + * @incr : Hardware version increment + * @reserved : Reserved for 64 bit aligngment + */ +struct cam_hw_version { + uint32_t major; + uint32_t minor; + uint32_t incr; + uint32_t reserved; +}; + +/** + * struct cam_iommu_handle - Structure for IOMMU handles of camera hw devices + * + * @non_secure: Device Non Secure IOMMU handle + * @secure: Device Secure IOMMU handle + * + */ +struct cam_iommu_handle { + int32_t non_secure; + int32_t secure; +}; + +/* camera secure mode */ +#define CAM_SECURE_MODE_NON_SECURE 0 +#define CAM_SECURE_MODE_SECURE 1 + +/* Camera Format Type */ +#define CAM_FORMAT_BASE 0 +#define CAM_FORMAT_MIPI_RAW_6 1 +#define CAM_FORMAT_MIPI_RAW_8 2 +#define CAM_FORMAT_MIPI_RAW_10 3 +#define CAM_FORMAT_MIPI_RAW_12 4 +#define CAM_FORMAT_MIPI_RAW_14 5 +#define CAM_FORMAT_MIPI_RAW_16 6 +#define CAM_FORMAT_MIPI_RAW_20 7 +#define CAM_FORMAT_QTI_RAW_8 8 +#define CAM_FORMAT_QTI_RAW_10 9 +#define CAM_FORMAT_QTI_RAW_12 10 +#define CAM_FORMAT_QTI_RAW_14 11 +#define CAM_FORMAT_PLAIN8 12 +#define CAM_FORMAT_PLAIN16_8 13 +#define CAM_FORMAT_PLAIN16_10 14 +#define CAM_FORMAT_PLAIN16_12 15 +#define CAM_FORMAT_PLAIN16_14 16 +#define CAM_FORMAT_PLAIN16_16 17 +#define CAM_FORMAT_PLAIN32_20 18 +#define CAM_FORMAT_PLAIN64 19 +#define CAM_FORMAT_PLAIN128 20 +#define CAM_FORMAT_ARGB 21 +#define CAM_FORMAT_ARGB_10 22 +#define CAM_FORMAT_ARGB_12 23 +#define CAM_FORMAT_ARGB_14 24 +#define CAM_FORMAT_DPCM_10_6_10 25 +#define CAM_FORMAT_DPCM_10_8_10 26 +#define CAM_FORMAT_DPCM_12_6_12 27 +#define CAM_FORMAT_DPCM_12_8_12 28 +#define CAM_FORMAT_DPCM_14_8_14 29 +#define CAM_FORMAT_DPCM_14_10_14 30 +#define CAM_FORMAT_NV21 31 +#define CAM_FORMAT_NV12 32 +#define CAM_FORMAT_TP10 33 +#define CAM_FORMAT_YUV422 34 +#define CAM_FORMAT_PD8 35 +#define CAM_FORMAT_PD10 36 +#define CAM_FORMAT_UBWC_NV12 37 +#define CAM_FORMAT_UBWC_NV12_4R 38 +#define CAM_FORMAT_UBWC_TP10 39 +#define CAM_FORMAT_UBWC_P010 40 +#define CAM_FORMAT_PLAIN8_SWAP 41 +#define CAM_FORMAT_PLAIN8_10 42 +#define CAM_FORMAT_PLAIN8_10_SWAP 43 +#define CAM_FORMAT_YV12 44 +#define CAM_FORMAT_Y_ONLY 45 +#define CAM_FORMAT_DPCM_12_10_12 46 +#define CAM_FORMAT_PLAIN32 47 +#define CAM_FORMAT_ARGB_16 48 +#define CAM_FORMAT_MAX 49 + +/* camera rotaion */ +#define CAM_ROTATE_CW_0_DEGREE 0 +#define CAM_ROTATE_CW_90_DEGREE 1 +#define CAM_RORATE_CW_180_DEGREE 2 +#define CAM_ROTATE_CW_270_DEGREE 3 + +/* camera Color Space */ +#define CAM_COLOR_SPACE_BASE 0 +#define CAM_COLOR_SPACE_BT601_FULL 1 +#define CAM_COLOR_SPACE_BT601625 2 +#define CAM_COLOR_SPACE_BT601525 3 +#define CAM_COLOR_SPACE_BT709 4 +#define CAM_COLOR_SPACE_DEPTH 5 +#define CAM_COLOR_SPACE_MAX 6 + +/* camera buffer direction */ +#define CAM_BUF_INPUT 1 +#define CAM_BUF_OUTPUT 2 +#define CAM_BUF_IN_OUT 3 + +/* camera packet device Type */ +#define CAM_PACKET_DEV_BASE 0 +#define CAM_PACKET_DEV_IMG_SENSOR 1 +#define CAM_PACKET_DEV_ACTUATOR 2 +#define CAM_PACKET_DEV_COMPANION 3 +#define CAM_PACKET_DEV_EEPOM 4 +#define CAM_PACKET_DEV_CSIPHY 5 +#define CAM_PACKET_DEV_OIS 6 +#define CAM_PACKET_DEV_FLASH 7 +#define CAM_PACKET_DEV_FD 8 +#define CAM_PACKET_DEV_JPEG_ENC 9 +#define CAM_PACKET_DEV_JPEG_DEC 10 +#define CAM_PACKET_DEV_VFE 11 +#define CAM_PACKET_DEV_CPP 12 +#define CAM_PACKET_DEV_CSID 13 +#define CAM_PACKET_DEV_ISPIF 14 +#define CAM_PACKET_DEV_IFE 15 +#define CAM_PACKET_DEV_ICP 16 +#define CAM_PACKET_DEV_LRME 17 +#define CAM_PACKET_DEV_MAX 18 + + +/* constants */ +#define CAM_PACKET_MAX_PLANES 3 + +/** + * struct cam_plane_cfg - Plane configuration info + * + * @width: Plane width in pixels + * @height: Plane height in lines + * @plane_stride: Plane stride in pixel + * @slice_height: Slice height in line (not used by ISP) + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config: UBWC mode config + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * + */ +struct cam_plane_cfg { + uint32_t width; + uint32_t height; + uint32_t plane_stride; + uint32_t slice_height; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; +}; + +/** + * struct cam_ubwc_plane_cfg_v1 - UBWC Plane configuration info + * + * @port_type: Port Type + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config_0: UBWC mode config 0 + * @mode_config_1: UBWC 3 mode config 1 + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * + */ +struct cam_ubwc_plane_cfg_v1 { + uint32_t port_type; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config_0; + uint32_t mode_config_1; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; +}; + +/** + * struct cam_ubwc_plane_cfg_v2 - UBWC Plane configuration info + * + * @port_type: Port Type + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config: UBWC mode config + * @static ctrl: UBWC static ctrl + * @ctrl_2: UBWC ctrl 2 + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * @stats_ctrl_2: UBWC stats control + * @lossy_threshold0 UBWC lossy threshold 0 + * @lossy_threshold1 UBWC lossy threshold 1 + * @lossy_var_offset UBWC offset variance thrshold + * + */ +struct cam_ubwc_plane_cfg_v2 { + uint32_t port_type; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config_0; + uint32_t mode_config_1; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; + uint32_t static_ctrl; + uint32_t ctrl_2; + uint32_t stats_ctrl_2; + uint32_t lossy_threshold_0; + uint32_t lossy_threshold_1; + uint32_t lossy_var_offset; + uint32_t bandwidth_limit; + uint32_t reserved[3]; +}; +/** + * struct cam_cmd_buf_desc - Command buffer descriptor + * + * @mem_handle: Command buffer handle + * @offset: Command start offset + * @size: Size of the command buffer in bytes + * @length: Used memory in command buffer in bytes + * @type: Type of the command buffer + * @meta_data: Data type for private command buffer + * Between UMD and KMD + * + */ +struct cam_cmd_buf_desc { + int32_t mem_handle; + uint32_t offset; + uint32_t size; + uint32_t length; + uint32_t type; + uint32_t meta_data; +}; + +/** + * struct cam_buf_io_cfg - Buffer io configuration for buffers + * + * @mem_handle: Mem_handle array for the buffers. + * @offsets: Offsets for each planes in the buffer + * @planes: Per plane information + * @width: Main plane width in pixel + * @height: Main plane height in lines + * @format: Format of the buffer + * @color_space: Color space for the buffer + * @color_pattern: Color pattern in the buffer + * @bpp: Bit per pixel + * @rotation: Rotation information for the buffer + * @resource_type: Resource type associated with the buffer + * @fence: Fence handle + * @early_fence: Fence handle for early signal + * @aux_cmd_buf: An auxiliary command buffer that may be + * used for programming the IO + * @direction: Direction of the config + * @batch_size: Batch size in HFR mode + * @subsample_pattern: Subsample pattern. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @subsample_period: Subsample period. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @framedrop_pattern: Framedrop pattern + * @framedrop_period: Framedrop period + * @flag: Flags for extra information + * @direction: Buffer direction: input or output + * @padding: Padding for the structure + * + */ +struct cam_buf_io_cfg { + int32_t mem_handle[CAM_PACKET_MAX_PLANES]; + uint32_t offsets[CAM_PACKET_MAX_PLANES]; + struct cam_plane_cfg planes[CAM_PACKET_MAX_PLANES]; + uint32_t format; + uint32_t color_space; + uint32_t color_pattern; + uint32_t bpp; + uint32_t rotation; + uint32_t resource_type; + int32_t fence; + int32_t early_fence; + struct cam_cmd_buf_desc aux_cmd_buf; + uint32_t direction; + uint32_t batch_size; + uint32_t subsample_pattern; + uint32_t subsample_period; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t flag; + uint32_t padding; +}; + +/** + * struct cam_packet_header - Camera packet header + * + * @op_code: Camera packet opcode + * @size: Size of the camera packet in bytes + * @request_id: Request id for this camera packet + * @flags: Flags for the camera packet + * @padding: Padding + * + */ +struct cam_packet_header { + uint32_t op_code; + uint32_t size; + uint64_t request_id; + uint32_t flags; + uint32_t padding; +}; + +/** + * struct cam_patch_desc - Patch structure + * + * @dst_buf_hdl: Memory handle for the dest buffer + * @dst_offset: Offset byte in the dest buffer + * @src_buf_hdl: Memory handle for the source buffer + * @src_offset: Offset byte in the source buffer + * + */ +struct cam_patch_desc { + int32_t dst_buf_hdl; + uint32_t dst_offset; + int32_t src_buf_hdl; + uint32_t src_offset; +}; + +/** + * struct cam_packet - Camera packet structure + * + * @header: Camera packet header + * @cmd_buf_offset: Command buffer start offset + * @num_cmd_buf: Number of the command buffer in the packet + * @io_config_offset: Buffer io configuration start offset + * @num_io_configs: Number of the buffer io configurations + * @patch_offset: Patch offset for the patch structure + * @num_patches: Number of the patch structure + * @kmd_cmd_buf_index: Command buffer index which contains extra + * space for the KMD buffer + * @kmd_cmd_buf_offset: Offset from the beginning of the command + * buffer for KMD usage. + * @payload: Camera packet payload + * + */ +struct cam_packet { + struct cam_packet_header header; + uint32_t cmd_buf_offset; + uint32_t num_cmd_buf; + uint32_t io_configs_offset; + uint32_t num_io_configs; + uint32_t patch_offset; + uint32_t num_patches; + uint32_t kmd_cmd_buf_index; + uint32_t kmd_cmd_buf_offset; + uint64_t payload[1]; + +}; + +/** + * struct cam_release_dev_cmd - Control payload for release devices + * + * @session_handle: Session handle for the release + * @dev_handle: Device handle for the release + */ +struct cam_release_dev_cmd { + int32_t session_handle; + int32_t dev_handle; +}; + +/** + * struct cam_start_stop_dev_cmd - Control payload for start/stop device + * + * @session_handle: Session handle for the start/stop command + * @dev_handle: Device handle for the start/stop command + * + */ +struct cam_start_stop_dev_cmd { + int32_t session_handle; + int32_t dev_handle; +}; + +/** + * struct cam_config_dev_cmd - Command payload for configure device + * + * @session_handle: Session handle for the command + * @dev_handle: Device handle for the command + * @offset: Offset byte in the packet handle. + * @packet_handle: Packet memory handle for the actual packet: + * struct cam_packet. + * + */ +struct cam_config_dev_cmd { + int32_t session_handle; + int32_t dev_handle; + uint64_t offset; + uint64_t packet_handle; +}; + +/** + * struct cam_query_cap_cmd - Payload for query device capability + * + * @size: Handle size + * @handle_type: User pointer or shared memory handle + * @caps_handle: Device specific query command payload + * + */ +struct cam_query_cap_cmd { + uint32_t size; + uint32_t handle_type; + uint64_t caps_handle; +}; + +/** + * struct cam_acquire_dev_cmd - Control payload for acquire devices + * + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @handle_type: Resource handle type: + * 1 = user pointer, 2 = mem handle + * @num_resources: Number of the resources to be acquired + * @resources_hdl: Resource handle that refers to the actual + * resource array. Each item in this + * array is device specific resource structure + * + */ +struct cam_acquire_dev_cmd { + int32_t session_handle; + int32_t dev_handle; + uint32_t handle_type; + uint32_t num_resources; + uint64_t resource_hdl; +}; + +/* + * In old version, while acquiring device the num_resources in + * struct cam_acquire_dev_cmd will be a valid value. During ACQUIRE_DEV + * KMD driver will return dev_handle as well as associate HW to handle. + * If num_resources is set to the constant below, we are using + * the new version and we do not acquire HW in ACQUIRE_DEV IOCTL. + * ACQUIRE_DEV will only return handle and we should receive + * ACQUIRE_HW IOCTL after ACQUIRE_DEV and that is when the HW + * is associated with the dev_handle. + * + * (Data type): uint32_t + */ +#define CAM_API_COMPAT_CONSTANT 0xFEFEFEFE + +#define CAM_ACQUIRE_HW_STRUCT_VERSION_1 1 +#define CAM_ACQUIRE_HW_STRUCT_VERSION_2 2 + +/** + * struct cam_acquire_hw_cmd_v1 - Control payload for acquire HW IOCTL (Ver 1) + * + * @struct_version: = CAM_ACQUIRE_HW_STRUCT_VERSION_1 for this struct + * This value should be the first 32-bits in any structure + * related to this IOCTL. So that if the struct needs to + * change, we can first read the starting 32-bits, get the + * version number and then typecast the data to struct + * accordingly. + * @reserved: Reserved field for 64-bit alignment + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @handle_type: Tells you how to interpret the variable resource_hdl- + * 1 = user pointer, 2 = mem handle + * @data_size: Total size of data contained in memory pointed + * to by resource_hdl + * @resource_hdl: Resource handle that refers to the actual + * resource data. + */ +struct cam_acquire_hw_cmd_v1 { + uint32_t struct_version; + uint32_t reserved; + int32_t session_handle; + int32_t dev_handle; + uint32_t handle_type; + uint32_t data_size; + uint64_t resource_hdl; +}; + +/** + * struct cam_acquired_hw_info - Update the acquired hardware info + * + * @acquired_hw_id: Acquired hardware mask + * @acquired_hw_path: Acquired path mask for an input + * if input splits into multiple paths, + * its updated per hardware + * valid_acquired_hw: Valid num of acquired hardware + */ +struct cam_acquired_hw_info { + uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; + uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; + uint32_t valid_acquired_hw; +}; + +/** + * struct cam_acquire_hw_cmd_v2 - Control payload for acquire HW IOCTL (Ver 2) + * + * @struct_version: = CAM_ACQUIRE_HW_STRUCT_VERSION_2 for this struct + * This value should be the first 32-bits in any structure + * related to this IOCTL. So that if the struct needs to + * change, we can first read the starting 32-bits, get the + * version number and then typecast the data to struct + * accordingly. + * @reserved: Reserved field for 64-bit alignment + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @handle_type: Tells you how to interpret the variable resource_hdl- + * 1 = user pointer, 2 = mem handle + * @data_size: Total size of data contained in memory pointed + * to by resource_hdl + * @resource_hdl: Resource handle that refers to the actual + * resource data. + */ +struct cam_acquire_hw_cmd_v2 { + uint32_t struct_version; + uint32_t reserved; + int32_t session_handle; + int32_t dev_handle; + uint32_t handle_type; + uint32_t data_size; + uint64_t resource_hdl; + struct cam_acquired_hw_info hw_info; +}; + +#define CAM_RELEASE_HW_STRUCT_VERSION_1 1 + +/** + * struct cam_release_hw_cmd_v1 - Control payload for release HW IOCTL (Ver 1) + * + * @struct_version: = CAM_RELEASE_HW_STRUCT_VERSION_1 for this struct + * This value should be the first 32-bits in any structure + * related to this IOCTL. So that if the struct needs to + * change, we can first read the starting 32-bits, get the + * version number and then typecast the data to struct + * accordingly. + * @reserved: Reserved field for 64-bit alignment + * @session_handle: Session handle for the release + * @dev_handle: Device handle for the release + */ +struct cam_release_hw_cmd_v1 { + uint32_t struct_version; + uint32_t reserved; + int32_t session_handle; + int32_t dev_handle; +}; + +/** + * struct cam_flush_dev_cmd - Control payload for flush devices + * + * @version: Version + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @flush_type: Flush type: + * 0 = flush specific request + * 1 = flush all + * @reserved: Reserved for 64 bit aligngment + * @req_id: Request id that needs to cancel + * + */ +struct cam_flush_dev_cmd { + uint64_t version; + int32_t session_handle; + int32_t dev_handle; + uint32_t flush_type; + uint32_t reserved; + int64_t req_id; +}; + +/** + * struct cam_ubwc_config - UBWC Configuration Payload + * + * @api_version: UBWC config api version + * @num_ports: Number of ports to be configured + * @ubwc_plane_config: Array of UBWC configurations per port + * Size [CAM_PACKET_MAX_PLANES - 1] per port + * as UBWC is supported on Y & C planes + * and therefore a max size of 2 planes + * + */ +struct cam_ubwc_config { + uint32_t api_version; + uint32_t num_ports; + struct cam_ubwc_plane_cfg_v1 + ubwc_plane_cfg[1][CAM_PACKET_MAX_PLANES - 1]; +}; + +/** + * struct cam_ubwc_config_v2 - UBWC Configuration Payload + * + * @api_version: UBWC config api version + * @num_ports: Number of ports to be configured + * @ubwc_plane_config: Array of UBWC configurations per port + * Size [CAM_PACKET_MAX_PLANES - 1] per port + * as UBWC is supported on Y & C planes + * and therefore a max size of 2 planes + * + */ +struct cam_ubwc_config_v2 { + uint32_t api_version; + uint32_t num_ports; + struct cam_ubwc_plane_cfg_v2 + ubwc_plane_cfg[1][CAM_PACKET_MAX_PLANES - 1]; +}; + +/** + * struct cam_cmd_mem_region_info - + * Cmd buffer region info + * + * @mem_handle : Memory handle of the region + * @offset : Offset if any + * @size : Size of the region + * @flags : Flags if any + */ +struct cam_cmd_mem_region_info { + int32_t mem_handle; + uint32_t offset; + uint32_t size; + uint32_t flags; +}; + +/** + * struct cam_cmd_mem_regions - + * List of multiple memory descriptors of + * of different regions + * + * @version : Version number + * @num_regions : Number of regions + * @map_info_array : Array of all the regions + */ +struct cam_cmd_mem_regions { + uint32_t version; + uint32_t num_regions; + struct cam_cmd_mem_region_info map_info_array[1]; +}; + + +#endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/include/uapi/media/cam_fd.h b/include/uapi/media/cam_fd.h new file mode 100644 index 000000000000..f456683b3779 --- /dev/null +++ b/include/uapi/media/cam_fd.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_FD_H__ +#define __UAPI_CAM_FD_H__ + +#include "cam_defs.h" + +#define CAM_FD_MAX_FACES 35 +#define CAM_FD_RAW_RESULT_ENTRIES 512 + +/* FD Op Codes */ +#define CAM_PACKET_OPCODES_FD_FRAME_UPDATE 0x0 + +/* FD Command Buffer identifiers */ +#define CAM_FD_CMD_BUFFER_ID_GENERIC 0x0 +#define CAM_FD_CMD_BUFFER_ID_CDM 0x1 +#define CAM_FD_CMD_BUFFER_ID_MAX 0x2 + +/* FD Blob types */ +#define CAM_FD_BLOB_TYPE_SOC_CLOCK_BW_REQUEST 0x0 +#define CAM_FD_BLOB_TYPE_RAW_RESULTS_REQUIRED 0x1 + +/* FD Resource IDs */ +#define CAM_FD_INPUT_PORT_ID_IMAGE 0x0 +#define CAM_FD_INPUT_PORT_ID_MAX 0x1 + +#define CAM_FD_OUTPUT_PORT_ID_RESULTS 0x0 +#define CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS 0x1 +#define CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER 0x2 +#define CAM_FD_OUTPUT_PORT_ID_MAX 0x3 + +/** + * struct cam_fd_soc_clock_bw_request - SOC clock, bandwidth request info + * + * @clock_rate : Clock rate required while processing frame + * @bandwidth : Bandwidth required while processing frame + * @reserved : Reserved for future use + */ +struct cam_fd_soc_clock_bw_request { + uint64_t clock_rate; + uint64_t bandwidth; + uint64_t reserved[4]; +}; + +/** + * struct cam_fd_face - Face properties + * + * @prop1 : Property 1 of face + * @prop2 : Property 2 of face + * @prop3 : Property 3 of face + * @prop4 : Property 4 of face + * + * Do not change this layout, this is inline with how HW writes + * these values directly when the buffer is programmed to HW + */ +struct cam_fd_face { + uint32_t prop1; + uint32_t prop2; + uint32_t prop3; + uint32_t prop4; +}; + +/** + * struct cam_fd_results - FD results layout + * + * @faces : Array of faces with face properties + * @face_count : Number of faces detected + * @reserved : Reserved for alignment + * + * Do not change this layout, this is inline with how HW writes + * these values directly when the buffer is programmed to HW + */ +struct cam_fd_results { + struct cam_fd_face faces[CAM_FD_MAX_FACES]; + uint32_t face_count; + uint32_t reserved[3]; +}; + +/** + * struct cam_fd_hw_caps - Face properties + * + * @core_version : FD core version + * @wrapper_version : FD wrapper version + * @raw_results_available : Whether raw results are available on this HW + * @supported_modes : Modes supported by this HW. + * @reserved : Reserved for future use + */ +struct cam_fd_hw_caps { + struct cam_hw_version core_version; + struct cam_hw_version wrapper_version; + uint32_t raw_results_available; + uint32_t supported_modes; + uint64_t reserved; +}; + +/** + * struct cam_fd_query_cap_cmd - FD Query capabilities information + * + * @device_iommu : FD IOMMU handles + * @cdm_iommu : CDM iommu handles + * @hw_caps : FD HW capabilities + * @reserved : Reserved for alignment + */ +struct cam_fd_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_fd_hw_caps hw_caps; + uint64_t reserved; +}; + +/** + * struct cam_fd_acquire_dev_info - FD acquire device information + * + * @clk_bw_request : SOC clock, bandwidth request + * @priority : Priority for this acquire + * @mode : Mode in which to run FD HW. + * @get_raw_results : Whether this acquire needs face raw results + * while frame processing + * @reserved : Reserved field for 64 bit alignment + */ +struct cam_fd_acquire_dev_info { + struct cam_fd_soc_clock_bw_request clk_bw_request; + uint32_t priority; + uint32_t mode; + uint32_t get_raw_results; + uint32_t reserved[13]; +}; + +#endif /* __UAPI_CAM_FD_H__ */ diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h new file mode 100644 index 000000000000..969de271e054 --- /dev/null +++ b/include/uapi/media/cam_icp.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ICP_H__ +#define __UAPI_CAM_ICP_H__ + +#include "cam_defs.h" +#include "cam_cpas.h" + +/* icp, ipe, bps, cdm(ipe/bps) are used in querycap */ +#define CAM_ICP_DEV_TYPE_A5 1 +#define CAM_ICP_DEV_TYPE_IPE 2 +#define CAM_ICP_DEV_TYPE_BPS 3 +#define CAM_ICP_DEV_TYPE_IPE_CDM 4 +#define CAM_ICP_DEV_TYPE_BPS_CDM 5 +#define CAM_ICP_DEV_TYPE_MAX 5 + +/* definitions needed for icp aquire device */ +#define CAM_ICP_RES_TYPE_BPS 1 +#define CAM_ICP_RES_TYPE_IPE_RT 2 +#define CAM_ICP_RES_TYPE_IPE 3 +#define CAM_ICP_RES_TYPE_MAX 4 + +/* packet opcode types */ +#define CAM_ICP_OPCODE_IPE_UPDATE 0 +#define CAM_ICP_OPCODE_BPS_UPDATE 1 +#define CAM_ICP_OPCODE_IPE_SETTINGS 2 +#define CAM_ICP_OPCODE_BPS_SETTINGS 3 + + +/* IPE input port resource type */ +#define CAM_ICP_IPE_INPUT_IMAGE_FULL 0x0 +#define CAM_ICP_IPE_INPUT_IMAGE_DS4 0x1 +#define CAM_ICP_IPE_INPUT_IMAGE_DS16 0x2 +#define CAM_ICP_IPE_INPUT_IMAGE_DS64 0x3 +#define CAM_ICP_IPE_INPUT_IMAGE_FULL_REF 0x4 +#define CAM_ICP_IPE_INPUT_IMAGE_DS4_REF 0x5 +#define CAM_ICP_IPE_INPUT_IMAGE_DS16_REF 0x6 +#define CAM_ICP_IPE_INPUT_IMAGE_DS64_REF 0x7 + +/* IPE output port resource type */ +#define CAM_ICP_IPE_OUTPUT_IMAGE_DISPLAY 0x8 +#define CAM_ICP_IPE_OUTPUT_IMAGE_VIDEO 0x9 +#define CAM_ICP_IPE_OUTPUT_IMAGE_FULL_REF 0xA +#define CAM_ICP_IPE_OUTPUT_IMAGE_DS4_REF 0xB +#define CAM_ICP_IPE_OUTPUT_IMAGE_DS16_REF 0xC +#define CAM_ICP_IPE_OUTPUT_IMAGE_DS64_REF 0xD + +#define CAM_ICP_IPE_IMAGE_MAX 0xE + +/* BPS input port resource type */ +#define CAM_ICP_BPS_INPUT_IMAGE 0x0 + +/* BPS output port resource type */ +#define CAM_ICP_BPS_OUTPUT_IMAGE_FULL 0x1 +#define CAM_ICP_BPS_OUTPUT_IMAGE_DS4 0x2 +#define CAM_ICP_BPS_OUTPUT_IMAGE_DS16 0x3 +#define CAM_ICP_BPS_OUTPUT_IMAGE_DS64 0x4 +#define CAM_ICP_BPS_OUTPUT_IMAGE_STATS_BG 0x5 +#define CAM_ICP_BPS_OUTPUT_IMAGE_STATS_BHIST 0x6 +#define CAM_ICP_BPS_OUTPUT_IMAGE_REG1 0x7 +#define CAM_ICP_BPS_OUTPUT_IMAGE_REG2 0x8 + +#define CAM_ICP_BPS_IO_IMAGES_MAX 0x9 + +/* Command meta types */ +#define CAM_ICP_CMD_META_GENERIC_BLOB 0x1 + +/* Generic blob types */ +#define CAM_ICP_CMD_GENERIC_BLOB_CLK 0x1 +#define CAM_ICP_CMD_GENERIC_BLOB_CFG_IO 0x2 +#define CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_MAP 0x3 +#define CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_UNMAP 0x4 +#define CAM_ICP_CMD_GENERIC_BLOB_CLK_V2 0x5 + +/** + * struct cam_icp_clk_bw_request_v2 + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @reserved: For memory alignment + * @num_paths: Number of axi paths in bw request + * @axi_path: Per path vote info for IPE/BPS + */ +struct cam_icp_clk_bw_request_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t reserved; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +}; + +/** + * struct cam_icp_clk_bw_request + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @uncompressed_bw: Bandwidth required to process frame + * @compressed_bw: Compressed bandwidth to process frame + */ +struct cam_icp_clk_bw_request { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint64_t uncompressed_bw; + uint64_t compressed_bw; +}; + +/** + * struct cam_icp_dev_ver - Device information for particular hw type + * + * This is used to get device version info of + * ICP, IPE, BPS and CDM related IPE and BPS from firmware + * and use this info in CAM_QUERY_CAP IOCTL + * + * @dev_type: hardware type for the cap info(icp, ipe, bps, cdm(ipe/bps)) + * @reserved: reserved field + * @hw_ver: major, minor and incr values of a device version + */ +struct cam_icp_dev_ver { + uint32_t dev_type; + uint32_t reserved; + struct cam_hw_version hw_ver; +}; + +/** + * struct cam_icp_ver - ICP version info + * + * This strcuture is used for fw and api version + * this is used to get firmware version and api version from firmware + * and use this info in CAM_QUERY_CAP IOCTL + * + * @major: FW version major + * @minor: FW version minor + * @revision: FW version increment + */ +struct cam_icp_ver { + uint32_t major; + uint32_t minor; + uint32_t revision; + uint32_t reserved; +}; + +/** + * struct cam_icp_query_cap_cmd - ICP query device capability payload + * + * @dev_iommu_handle: icp iommu handles for secure/non secure modes + * @cdm_iommu_handle: iommu handles for secure/non secure modes + * @fw_version: firmware version info + * @api_version: api version info + * @num_ipe: number of ipes + * @num_bps: number of bps + * @dev_ver: returned device capability array + */ +struct cam_icp_query_cap_cmd { + struct cam_iommu_handle dev_iommu_handle; + struct cam_iommu_handle cdm_iommu_handle; + struct cam_icp_ver fw_version; + struct cam_icp_ver api_version; + uint32_t num_ipe; + uint32_t num_bps; + struct cam_icp_dev_ver dev_ver[CAM_ICP_DEV_TYPE_MAX]; +}; + +/** + * struct cam_icp_res_info - ICP output resource info + * + * @format: format of the resource + * @width: width in pixels + * @height: height in lines + * @fps: fps + */ +struct cam_icp_res_info { + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t fps; +}; + +/** + * struct cam_icp_acquire_dev_info - An ICP device info + * + * @scratch_mem_size: Output param - size of scratch memory + * @dev_type: device type (IPE_RT/IPE_NON_RT/BPS) + * @io_config_cmd_size: size of IO config command + * @io_config_cmd_handle: IO config command for each acquire + * @secure_mode: camera mode (secure/non secure) + * @chain_info: chaining info of FW device handles + * @in_res: resource info used for clock and bandwidth calculation + * @num_out_res: number of output resources + * @out_res: output resource + */ +struct cam_icp_acquire_dev_info { + uint32_t scratch_mem_size; + uint32_t dev_type; + uint32_t io_config_cmd_size; + int32_t io_config_cmd_handle; + uint32_t secure_mode; + int32_t chain_info; + struct cam_icp_res_info in_res; + uint32_t num_out_res; + struct cam_icp_res_info out_res[1]; +} __attribute__((__packed__)); + +#endif /* __UAPI_CAM_ICP_H__ */ diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h new file mode 100644 index 000000000000..0191d2ced633 --- /dev/null +++ b/include/uapi/media/cam_isp.h @@ -0,0 +1,693 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_H__ +#define __UAPI_CAM_ISP_H__ + +#include "cam_defs.h" +#include "cam_isp_vfe.h" +#include "cam_isp_ife.h" +#include "cam_cpas.h" + +/* ISP driver name */ +#define CAM_ISP_DEV_NAME "cam-isp" + +/* HW type */ +#define CAM_ISP_HW_BASE 0 +#define CAM_ISP_HW_CSID 1 +#define CAM_ISP_HW_VFE 2 +#define CAM_ISP_HW_IFE 3 +#define CAM_ISP_HW_ISPIF 4 +#define CAM_ISP_HW_MAX 5 + +/* Color Pattern */ +#define CAM_ISP_PATTERN_BAYER_RGRGRG 0 +#define CAM_ISP_PATTERN_BAYER_GRGRGR 1 +#define CAM_ISP_PATTERN_BAYER_BGBGBG 2 +#define CAM_ISP_PATTERN_BAYER_GBGBGB 3 +#define CAM_ISP_PATTERN_YUV_YCBYCR 4 +#define CAM_ISP_PATTERN_YUV_YCRYCB 5 +#define CAM_ISP_PATTERN_YUV_CBYCRY 6 +#define CAM_ISP_PATTERN_YUV_CRYCBY 7 +#define CAM_ISP_PATTERN_MAX 8 + +/* Usage Type */ +#define CAM_ISP_RES_USAGE_SINGLE 0 +#define CAM_ISP_RES_USAGE_DUAL 1 +#define CAM_ISP_RES_USAGE_MAX 2 + +/* Resource ID */ +#define CAM_ISP_RES_ID_PORT 0 +#define CAM_ISP_RES_ID_CLK 1 +#define CAM_ISP_RES_ID_MAX 2 + +/* Resource Type - Type of resource for the resource id + * defined in cam_isp_vfe.h, cam_isp_ife.h + */ + +/* Lane Type in input resource for Port */ +#define CAM_ISP_LANE_TYPE_DPHY 0 +#define CAM_ISP_LANE_TYPE_CPHY 1 +#define CAM_ISP_LANE_TYPE_MAX 2 + +/* ISP Resurce Composite Group ID */ +#define CAM_ISP_RES_COMP_GROUP_NONE 0 +#define CAM_ISP_RES_COMP_GROUP_ID_0 1 +#define CAM_ISP_RES_COMP_GROUP_ID_1 2 +#define CAM_ISP_RES_COMP_GROUP_ID_2 3 +#define CAM_ISP_RES_COMP_GROUP_ID_3 4 +#define CAM_ISP_RES_COMP_GROUP_ID_4 5 +#define CAM_ISP_RES_COMP_GROUP_ID_5 6 +#define CAM_ISP_RES_COMP_GROUP_ID_MAX 6 + +/* ISP packet opcode for ISP */ +#define CAM_ISP_PACKET_OP_BASE 0 +#define CAM_ISP_PACKET_INIT_DEV 1 +#define CAM_ISP_PACKET_UPDATE_DEV 2 +#define CAM_ISP_PACKET_OP_MAX 3 + +/* ISP packet meta_data type for command buffer */ +#define CAM_ISP_PACKET_META_BASE 0 +#define CAM_ISP_PACKET_META_LEFT 1 +#define CAM_ISP_PACKET_META_RIGHT 2 +#define CAM_ISP_PACKET_META_COMMON 3 +#define CAM_ISP_PACKET_META_DMI_LEFT 4 +#define CAM_ISP_PACKET_META_DMI_RIGHT 5 +#define CAM_ISP_PACKET_META_DMI_COMMON 6 +#define CAM_ISP_PACKET_META_CLOCK 7 +#define CAM_ISP_PACKET_META_CSID 8 +#define CAM_ISP_PACKET_META_DUAL_CONFIG 9 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_LEFT 10 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_RIGHT 11 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON 12 + +/* DSP mode */ +#define CAM_ISP_DSP_MODE_NONE 0 +#define CAM_ISP_DSP_MODE_ONE_WAY 1 +#define CAM_ISP_DSP_MODE_ROUND 2 + +/* ISP Generic Cmd Buffer Blob types */ +#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 +#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 +#define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 +#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG_V2 6 +#define CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG 7 +#define CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG 8 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 9 + +#define CAM_ISP_VC_DT_CFG 4 + +#define CAM_ISP_IFE0_HW 0x1 +#define CAM_ISP_IFE1_HW 0x2 +#define CAM_ISP_IFE0_LITE_HW 0x4 +#define CAM_ISP_IFE1_LITE_HW 0x8 +#define CAM_ISP_IFE2_LITE_HW 0x10 + +#define CAM_ISP_PXL_PATH 0x1 +#define CAM_ISP_PPP_PATH 0x2 +#define CAM_ISP_LCR_PATH 0x4 +#define CAM_ISP_RDI0_PATH 0x8 +#define CAM_ISP_RDI1_PATH 0x10 +#define CAM_ISP_RDI2_PATH 0x20 +#define CAM_ISP_RDI3_PATH 0x40 + +/* Per Path Usage Data */ +#define CAM_ISP_USAGE_INVALID 0 +#define CAM_ISP_USAGE_LEFT_PX 1 +#define CAM_ISP_USAGE_RIGHT_PX 2 +#define CAM_ISP_USAGE_RDI 3 + +/* Query devices */ +/** + * struct cam_isp_dev_cap_info - A cap info for particular hw type + * + * @hw_type: Hardware type for the cap info + * @reserved: reserved field for alignment + * @hw_version: Hardware version + * + */ +struct cam_isp_dev_cap_info { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_version; +}; + +/** + * struct cam_isp_query_cap_cmd - ISP query device capability payload + * + * @device_iommu: returned iommu handles for device + * @cdm_iommu: returned iommu handles for cdm + * @num_dev: returned number of device capabilities + * @reserved: reserved field for alignment + * @dev_caps: returned device capability array + * + */ +struct cam_isp_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + int32_t num_dev; + uint32_t reserved; + struct cam_isp_dev_cap_info dev_caps[CAM_ISP_HW_MAX]; +}; + +/* Acquire Device */ +/** + * struct cam_isp_out_port_info - An output port resource info + * + * @res_type: output resource type defined in file + * cam_isp_vfe.h or cam_isp_ife.h + * @format: output format of the resource + * @wdith: output width in pixels + * @height: output height in lines + * @comp_grp_id: composite group id for the resource. + * @split_point: split point in pixels for the dual VFE. + * @secure_mode: flag to tell if output should be run in secure + * mode or not. See cam_defs.h for definition + * @reserved: reserved field for alignment + * + */ +struct cam_isp_out_port_info { + uint32_t res_type; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t comp_grp_id; + uint32_t split_point; + uint32_t secure_mode; + uint32_t reserved; +}; + +/** + * struct cam_isp_out_port_info_v2 - An output port resource info + * + * @res_type: output resource type defined in file + * cam_isp_vfe.h or cam_isp_ife.h + * @format: output format of the resource + * @wdith: output width in pixels + * @height: output height in lines + * @comp_grp_id: composite group id for the resource. + * @split_point: split point in pixels for the dual VFE. + * @secure_mode: flag to tell if output should be run in secure + * mode or not. See cam_defs.h for definition + * @wm_mode: WM mode + * @out_port_res1: Output reserved field + * @out_port_res2: Output reserved field + * + */ +struct cam_isp_out_port_info_v2 { + uint32_t res_type; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t comp_grp_id; + uint32_t split_point; + uint32_t secure_mode; + uint32_t wm_mode; + uint32_t out_port_res1; + uint32_t out_port_res2; +}; + +/** + * struct cam_isp_in_port_info - An input port resource info + * + * @res_type: input resource type define in file + * cam_isp_vfe.h or cam_isp_ife.h + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @format: input format + * @test_pattern: test pattern for the testgen + * @usage_type: whether dual vfe is required + * @left_start: left input start offset in pixels + * @left_stop: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * Only for Dual VFE + * @right_stop: right input stop offset in pixels. + * Only for Dual VFE + * @right_width: right input width in pixels. + * Only for dual VFE + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @pixel_clk; sensor output clock + * @batch_size: batch size for HFR mode + * @dsp_mode: DSP stream mode (Defines as CAM_ISP_DSP_MODE_*) + * @hbi_cnt: HBI count for the camif input + * @reserved: Reserved field for alignment + * @num_out_res: number of the output resource associated + * @data: payload that contains the output resources + * + */ +struct cam_isp_in_port_info { + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc; + uint32_t dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t hbi_cnt; + uint32_t reserved; + uint32_t num_out_res; + struct cam_isp_out_port_info data[1]; +}; + +/** + * struct cam_isp_in_port_info_v2 - An input port resource info + * + * @res_type: input resource type define in file + * cam_isp_vfe.h or cam_isp_ife.h + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @num_valid_vc_dt: valid vc and dt in array + * @format: input format + * @test_pattern: test pattern for the testgen + * @usage_type: whether dual vfe is required + * @left_start: left input start offset in pixels + * @left_stop: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * Only for Dual VFE + * @right_stop: right input stop offset in pixels. + * only for Dual VFE + * @right_width: right input width in pixels. + * only for dual VFE + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @pixel_clk; sensor output clock + * @batch_size: batch size for HFR mode + * @dsp_mode: DSP stream mode (Defines as CAM_ISP_DSP_MODE_*) + * @hbi_cnt: HBI count for the camif input + * @cust_node: if any custom HW block is present before IFE + * @num_out_res: number of the output resource associated + * @horizontal_bin: Horizontal Binning info + * @qcfa_bin: Quadra Binning info + * @csid_res_1: payload for future use + * @csid_res_2: payload for future use + * @ife_res_1: payload for future use + * @ife_res_2: payload for future use + * @data: payload that contains the output resources + * + */ +struct cam_isp_in_port_info_v2 { + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc[CAM_ISP_VC_DT_CFG]; + uint32_t dt[CAM_ISP_VC_DT_CFG]; + uint32_t num_valid_vc_dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t hbi_cnt; + uint32_t cust_node; + uint32_t num_out_res; + uint32_t offline_mode; + uint32_t horizontal_bin; + uint32_t qcfa_bin; + uint32_t csid_res_1; + uint32_t csid_res_2; + uint32_t ife_res_1; + uint32_t ife_res_2; + struct cam_isp_out_port_info_v2 data[1]; +}; + +/** + * struct cam_isp_resource - A resource bundle + * + * @resoruce_id: resource id for the resource bundle + * @length: length of the while resource blob + * @handle_type: type of the resource handle + * @reserved: reserved field for alignment + * @res_hdl: resource handle that points to the + * resource array; + * + */ +struct cam_isp_resource { + uint32_t resource_id; + uint32_t length; + uint32_t handle_type; + uint32_t reserved; + uint64_t res_hdl; +}; + +/** + * struct cam_isp_port_hfr_config - HFR configuration for this port + * + * @resource_type: Resource type + * @subsample_pattern: Subsample pattern. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @subsample_period: Subsample period. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @framedrop_pattern: Framedrop pattern + * @framedrop_period: Framedrop period + * @reserved: Reserved for alignment + */ +struct cam_isp_port_hfr_config { + uint32_t resource_type; + uint32_t subsample_pattern; + uint32_t subsample_period; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_isp_resource_hfr_config - Resource HFR configuration + * + * @num_ports: Number of ports + * @reserved: Reserved for alignment + * @port_hfr_config: HFR configuration for each IO port + */ +struct cam_isp_resource_hfr_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_port_hfr_config port_hfr_config[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_dual_split_params - dual isp spilt parameters + * + * @split_point: Split point information x, where (0 < x < width) + * left ISP's input ends at x + righ padding and + * Right ISP's input starts at x - left padding + * @right_padding: Padding added past the split point for left + * ISP's input + * @left_padding: Padding added before split point for right + * ISP's input + * @reserved: Reserved filed for alignment + * + */ +struct cam_isp_dual_split_params { + uint32_t split_point; + uint32_t right_padding; + uint32_t left_padding; + uint32_t reserved; +}; + +/** + * struct cam_isp_dual_stripe_config - stripe config per bus client + * + * @offset: Start horizontal offset relative to + * output buffer + * In UBWC mode, this value indicates the H_INIT + * value in pixel + * @width: Width of the stripe in bytes + * @tileconfig Ubwc meta tile config. Contain the partial + * tile info + * @port_id: port id of ISP output + * + */ +struct cam_isp_dual_stripe_config { + uint32_t offset; + uint32_t width; + uint32_t tileconfig; + uint32_t port_id; +}; + +/** + * struct cam_isp_dual_config - dual isp configuration + * + * @num_ports Number of isp output ports + * @reserved Reserved field for alignment + * @split_params: Inpput split parameters + * @stripes: Stripe information + * + */ +struct cam_isp_dual_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_dual_split_params split_params; + struct cam_isp_dual_stripe_config stripes[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_clock_config - Clock configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_hz: Pixel Clock for Left ISP + * @right_pix_hz: Pixel Clock for Right ISP, valid only if Dual + * @rdi_hz: RDI Clock. ISP clock will be max of RDI and + * PIX clocks. For a particular context which ISP + * HW the RDI is allocated to is not known to UMD. + * Hence pass the clock and let KMD decide. + */ +struct cam_isp_clock_config { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_hz; + uint64_t right_pix_hz; + uint64_t rdi_hz[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_csid_clock_config - CSID clock configuration + * + * @csid_clock CSID clock + */ +struct cam_isp_csid_clock_config { + uint64_t csid_clock; +} __attribute__((packed)); + +/** + * struct cam_isp_bw_vote - Bandwidth vote information + * + * @resource_id: Resource ID + * @reserved: Reserved field for alignment + * @cam_bw_bps: Bandwidth vote for CAMNOC + * @ext_bw_bps: Bandwidth vote for path-to-DDR after CAMNOC + */ +struct cam_isp_bw_vote { + uint32_t resource_id; + uint32_t reserved; + uint64_t cam_bw_bps; + uint64_t ext_bw_bps; +} __attribute__((packed)); + +/** + * struct cam_isp_bw_config - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_vote: Bandwidth vote for left ISP + * @right_pix_vote: Bandwidth vote for right ISP + * @rdi_vote: RDI bandwidth requirements + */ +struct cam_isp_bw_config { + uint32_t usage_type; + uint32_t num_rdi; + struct cam_isp_bw_vote left_pix_vote; + struct cam_isp_bw_vote right_pix_vote; + struct cam_isp_bw_vote rdi_vote[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_bw_config_v2 - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_paths: Number of axi data paths + * @axi_path Per path vote info + */ +struct cam_isp_bw_config_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +} __attribute__((packed)); + +/** + * struct cam_fe_config - Fetch Engine configuration + * + * @version: fetch engine veriosn + * @min_vbi: require min vbi + * @fs_mode: indicates if fs mode enabled + * @fs_line_sync_en: frame level sync or line level + * sync for fetch engine + * @hbi_count: hbi count + * @fs_sync_enable: indicates if fetch engine working + * wokring in sync with write engine + * @go_cmd_sel: softwrae go_cmd or hw go_cmd + * @client_enable: enable read engine + * @source_addr: adrress of buffer to read from + * @width: buffer width + * @height: buffer height + * @stride: buffer stride (here equal to width) + * @format: format of image in buffer + * @unpacker_cfg: unpacker config type + * @latency_buf_size: latency buffer for read engine + */ +struct cam_fe_config { + uint64_t version; + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t fs_line_sync_en; + uint32_t hbi_count; + uint32_t fs_sync_enable; + uint32_t go_cmd_sel; + uint32_t client_enable; + uint32_t source_addr; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t unpacker_cfg; + uint32_t latency_buf_size; +} __attribute__((packed)); + +/** + * struct cam_isp_core_config - ISP core registers configuration + * + * @version: Version info + * @vid_ds16_r2pd: Enables Y and C merging PD output for video DS16 + * @vid_ds4_r2pd: Enables Y and C merging PD output for video DS4 + * @disp_ds16_r2pd: Enables Y and C merging PD output for disp DS16 + * @disp_ds4_r2pd: Enables Y and C merging PD output for disp DS4 + * @dsp_streaming_tap_point: This selects source for DSP streaming interface + * @ihist_src_sel: Selects input for IHIST module + * @hdr_be_src_sel: Selects input for HDR BE module + * @hdr_bhist_src_sel: Selects input for HDR BHIST module + * @input_mux_sel_pdaf: Selects input for PDAF + * @input_mux_sel_pp: Selects input for Pixel Pipe + * @reserved: Reserved + */ +struct cam_isp_core_config { + uint32_t version; + uint32_t vid_ds16_r2pd; + uint32_t vid_ds4_r2pd; + uint32_t disp_ds16_r2pd; + uint32_t disp_ds4_r2pd; + uint32_t dsp_streaming_tap_point; + uint32_t ihist_src_sel; + uint32_t hdr_be_src_sel; + uint32_t hdr_bhist_src_sel; + uint32_t input_mux_sel_pdaf; + uint32_t input_mux_sel_pp; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_isp_acquire_hw_info - ISP acquire HW params + * + * @common_info_version : Version of common info struct used + * @common_info_size : Size of common info struct used + * @common_info_offset : Offset of common info from start of data + * @num_inputs : Number of inputs + * @input_info_version : Version of input info struct used + * @input_info_size : Size of input info struct used + * @input_info_offset : Offset of input info from start of data + * @data : Start of data region + */ +struct cam_isp_acquire_hw_info { + uint16_t common_info_version; + uint16_t common_info_size; + uint32_t common_info_offset; + uint32_t num_inputs; + uint32_t input_info_version; + uint32_t input_info_size; + uint32_t input_info_offset; + uint64_t data; +}; + +/** + * struct cam_isp_vfe_wm_config - VFE write master config per port + * + * @port_type : Unique ID of output port + * @wm_mode : Write master mode + * 0x0 - Line based mode + * 0x1 - Frame based mode + * 0x2 - Index based mode, valid for BAF only + * @h_init : Horizontal starting coordinate in pixels. Must be a + * multiple of 3 for TP10 format + * @height : Height in pixels + * @width : Width in pixels + * @virtual_frame_en : Enabling virtual frame will prevent actual request from + * being sent to NOC + * @stride : Write master stride + * @offset : Write master offset + * @reserved_1 : Reserved field for Write master config + * @reserved_2 : Reserved field for Write master config + * @reserved_3 : Reserved field for Write master config + * @reserved_4 : Reserved field for Write master config + */ +struct cam_isp_vfe_wm_config { + uint32_t port_type; + uint32_t wm_mode; + uint32_t h_init; + uint32_t height; + uint32_t width; + uint32_t virtual_frame_en; + uint32_t stride; + uint32_t offset; + uint32_t reserved_1; + uint32_t reserved_2; + uint32_t reserved_3; + uint32_t reserved_4; +}; + +/** + * struct cam_isp_vfe_out_config - VFE write master config + * + * @num_ports : Number of ports + * @reserved : Reserved field + * @wm_config : VFE out config + */ +struct cam_isp_vfe_out_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_vfe_wm_config wm_config[1]; +}; + +#define CAM_ISP_ACQUIRE_COMMON_VER0 0x1000 + +#define CAM_ISP_ACQUIRE_COMMON_SIZE_VER0 0x0 + +#define CAM_ISP_ACQUIRE_INPUT_VER0 0x2000 + +#define CAM_ISP_ACQUIRE_INPUT_SIZE_VER0 sizeof(struct cam_isp_in_port_info) + +#define CAM_ISP_ACQUIRE_OUT_VER0 0x3000 + +#define CAM_ISP_ACQUIRE_OUT_SIZE_VER0 sizeof(struct cam_isp_out_port_info) + +#endif /* __UAPI_CAM_ISP_H__ */ diff --git a/include/uapi/media/cam_isp_ife.h b/include/uapi/media/cam_isp_ife.h new file mode 100644 index 000000000000..7ce826d94a78 --- /dev/null +++ b/include/uapi/media/cam_isp_ife.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_IFE_H__ +#define __UAPI_CAM_ISP_IFE_H__ + +/* IFE output port resource type (global unique)*/ +#define CAM_ISP_IFE_OUT_RES_BASE 0x3000 + +#define CAM_ISP_IFE_OUT_RES_FULL (CAM_ISP_IFE_OUT_RES_BASE + 0) +#define CAM_ISP_IFE_OUT_RES_DS4 (CAM_ISP_IFE_OUT_RES_BASE + 1) +#define CAM_ISP_IFE_OUT_RES_DS16 (CAM_ISP_IFE_OUT_RES_BASE + 2) +#define CAM_ISP_IFE_OUT_RES_RAW_DUMP (CAM_ISP_IFE_OUT_RES_BASE + 3) +#define CAM_ISP_IFE_OUT_RES_FD (CAM_ISP_IFE_OUT_RES_BASE + 4) +#define CAM_ISP_IFE_OUT_RES_PDAF (CAM_ISP_IFE_OUT_RES_BASE + 5) +#define CAM_ISP_IFE_OUT_RES_RDI_0 (CAM_ISP_IFE_OUT_RES_BASE + 6) +#define CAM_ISP_IFE_OUT_RES_RDI_1 (CAM_ISP_IFE_OUT_RES_BASE + 7) +#define CAM_ISP_IFE_OUT_RES_RDI_2 (CAM_ISP_IFE_OUT_RES_BASE + 8) +#define CAM_ISP_IFE_OUT_RES_RDI_3 (CAM_ISP_IFE_OUT_RES_BASE + 9) +#define CAM_ISP_IFE_OUT_RES_STATS_HDR_BE (CAM_ISP_IFE_OUT_RES_BASE + 10) +#define CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST (CAM_ISP_IFE_OUT_RES_BASE + 11) +#define CAM_ISP_IFE_OUT_RES_STATS_TL_BG (CAM_ISP_IFE_OUT_RES_BASE + 12) +#define CAM_ISP_IFE_OUT_RES_STATS_BF (CAM_ISP_IFE_OUT_RES_BASE + 13) +#define CAM_ISP_IFE_OUT_RES_STATS_AWB_BG (CAM_ISP_IFE_OUT_RES_BASE + 14) +#define CAM_ISP_IFE_OUT_RES_STATS_BHIST (CAM_ISP_IFE_OUT_RES_BASE + 15) +#define CAM_ISP_IFE_OUT_RES_STATS_RS (CAM_ISP_IFE_OUT_RES_BASE + 16) +#define CAM_ISP_IFE_OUT_RES_STATS_CS (CAM_ISP_IFE_OUT_RES_BASE + 17) +#define CAM_ISP_IFE_OUT_RES_STATS_IHIST (CAM_ISP_IFE_OUT_RES_BASE + 18) +#define CAM_ISP_IFE_OUT_RES_FULL_DISP (CAM_ISP_IFE_OUT_RES_BASE + 19) +#define CAM_ISP_IFE_OUT_RES_DS4_DISP (CAM_ISP_IFE_OUT_RES_BASE + 20) +#define CAM_ISP_IFE_OUT_RES_DS16_DISP (CAM_ISP_IFE_OUT_RES_BASE + 21) +#define CAM_ISP_IFE_OUT_RES_2PD (CAM_ISP_IFE_OUT_RES_BASE + 22) +#define CAM_ISP_IFE_OUT_RES_RDI_RD (CAM_ISP_IFE_OUT_RES_BASE + 23) +#define CAM_ISP_IFE_OUT_RES_LCR (CAM_ISP_IFE_OUT_RES_BASE + 24) + +#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 25) + + +/* IFE input port resource type (global unique) */ +#define CAM_ISP_IFE_IN_RES_BASE 0x4000 + +#define CAM_ISP_IFE_IN_RES_TPG (CAM_ISP_IFE_IN_RES_BASE + 0) +#define CAM_ISP_IFE_IN_RES_PHY_0 (CAM_ISP_IFE_IN_RES_BASE + 1) +#define CAM_ISP_IFE_IN_RES_PHY_1 (CAM_ISP_IFE_IN_RES_BASE + 2) +#define CAM_ISP_IFE_IN_RES_PHY_2 (CAM_ISP_IFE_IN_RES_BASE + 3) +#define CAM_ISP_IFE_IN_RES_PHY_3 (CAM_ISP_IFE_IN_RES_BASE + 4) +#define CAM_ISP_IFE_IN_RES_RD (CAM_ISP_IFE_IN_RES_BASE + 5) +#define CAM_ISP_IFE_IN_RES_MAX (CAM_ISP_IFE_IN_RES_BASE + 6) + +#endif /* __UAPI_CAM_ISP_IFE_H__ */ diff --git a/include/uapi/media/cam_isp_vfe.h b/include/uapi/media/cam_isp_vfe.h new file mode 100644 index 000000000000..5f9ce7a49108 --- /dev/null +++ b/include/uapi/media/cam_isp_vfe.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_VFE_H__ +#define __UAPI_CAM_ISP_VFE_H__ + +/* VFE output port resource type (global unique) */ +#define CAM_ISP_VFE_OUT_RES_BASE 0x1000 + +#define CAM_ISP_VFE_OUT_RES_ENC (CAM_ISP_VFE_OUT_RES_BASE + 0) +#define CAM_ISP_VFE_OUT_RES_VIEW (CAM_ISP_VFE_OUT_RES_BASE + 1) +#define CAM_ISP_VFE_OUT_RES_VID (CAM_ISP_VFE_OUT_RES_BASE + 2) +#define CAM_ISP_VFE_OUT_RES_RDI_0 (CAM_ISP_VFE_OUT_RES_BASE + 3) +#define CAM_ISP_VFE_OUT_RES_RDI_1 (CAM_ISP_VFE_OUT_RES_BASE + 4) +#define CAM_ISP_VFE_OUT_RES_RDI_2 (CAM_ISP_VFE_OUT_RES_BASE + 5) +#define CAM_ISP_VFE_OUT_RES_RDI_3 (CAM_ISP_VFE_OUT_RES_BASE + 6) +#define CAM_ISP_VFE_OUT_RES_STATS_AEC (CAM_ISP_VFE_OUT_RES_BASE + 7) +#define CAM_ISP_VFE_OUT_RES_STATS_AF (CAM_ISP_VFE_OUT_RES_BASE + 8) +#define CAM_ISP_VFE_OUT_RES_STATS_AWB (CAM_ISP_VFE_OUT_RES_BASE + 9) +#define CAM_ISP_VFE_OUT_RES_STATS_RS (CAM_ISP_VFE_OUT_RES_BASE + 10) +#define CAM_ISP_VFE_OUT_RES_STATS_CS (CAM_ISP_VFE_OUT_RES_BASE + 11) +#define CAM_ISP_VFE_OUT_RES_STATS_IHIST (CAM_ISP_VFE_OUT_RES_BASE + 12) +#define CAM_ISP_VFE_OUT_RES_STATS_SKIN (CAM_ISP_VFE_OUT_RES_BASE + 13) +#define CAM_ISP_VFE_OUT_RES_STATS_BG (CAM_ISP_VFE_OUT_RES_BASE + 14) +#define CAM_ISP_VFE_OUT_RES_STATS_BF (CAM_ISP_VFE_OUT_RES_BASE + 15) +#define CAM_ISP_VFE_OUT_RES_STATS_BE (CAM_ISP_VFE_OUT_RES_BASE + 16) +#define CAM_ISP_VFE_OUT_RES_STATS_BHIST (CAM_ISP_VFE_OUT_RES_BASE + 17) +#define CAM_ISP_VFE_OUT_RES_STATS_BF_SCALE (CAM_ISP_VFE_OUT_RES_BASE + 18) +#define CAM_ISP_VFE_OUT_RES_STATS_HDR_BE (CAM_ISP_VFE_OUT_RES_BASE + 19) +#define CAM_ISP_VFE_OUT_RES_STATS_HDR_BHIST (CAM_ISP_VFE_OUT_RES_BASE + 20) +#define CAM_ISP_VFE_OUT_RES_STATS_AEC_BG (CAM_ISP_VFE_OUT_RES_BASE + 21) +#define CAM_ISP_VFE_OUT_RES_CAMIF_RAW (CAM_ISP_VFE_OUT_RES_BASE + 22) +#define CAM_ISP_VFE_OUT_RES_IDEAL_RAW (CAM_ISP_VFE_OUT_RES_BASE + 23) +#define CAM_ISP_VFE_OUT_RES_MAX (CAM_ISP_VFE_OUT_RES_BASE + 24) + +/* VFE input port_ resource type (global unique) */ +#define CAM_ISP_VFE_IN_RES_BASE 0x2000 + +#define CAM_ISP_VFE_IN_RES_TPG (CAM_ISP_VFE_IN_RES_BASE + 0) +#define CAM_ISP_VFE_IN_RES_PHY_0 (CAM_ISP_VFE_IN_RES_BASE + 1) +#define CAM_ISP_VFE_IN_RES_PHY_1 (CAM_ISP_VFE_IN_RES_BASE + 2) +#define CAM_ISP_VFE_IN_RES_PHY_2 (CAM_ISP_VFE_IN_RES_BASE + 3) +#define CAM_ISP_VFE_IN_RES_PHY_3 (CAM_ISP_VFE_IN_RES_BASE + 4) +#define CAM_ISP_VFE_IN_RES_FE (CAM_ISP_VFE_IN_RES_BASE + 5) +#define CAM_ISP_VFE_IN_RES_MAX (CAM_ISP_VFE_IN_RES_BASE + 6) + +#endif /* __UAPI_CAM_ISP_VFE_H__ */ diff --git a/include/uapi/media/cam_jpeg.h b/include/uapi/media/cam_jpeg.h new file mode 100644 index 000000000000..6513bbae740b --- /dev/null +++ b/include/uapi/media/cam_jpeg.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_JPEG_H__ +#define __UAPI_CAM_JPEG_H__ + +#include "cam_defs.h" + +/* enc, dma, cdm(enc/dma) are used in querycap */ +#define CAM_JPEG_DEV_TYPE_ENC 0 +#define CAM_JPEG_DEV_TYPE_DMA 1 +#define CAM_JPEG_DEV_TYPE_MAX 2 + +#define CAM_JPEG_NUM_DEV_PER_RES_MAX 1 + +/* definitions needed for jpeg aquire device */ +#define CAM_JPEG_RES_TYPE_ENC 0 +#define CAM_JPEG_RES_TYPE_DMA 1 +#define CAM_JPEG_RES_TYPE_MAX 2 + +/* packet opcode types */ +#define CAM_JPEG_OPCODE_ENC_UPDATE 0 +#define CAM_JPEG_OPCODE_DMA_UPDATE 1 + +/* ENC input port resource type */ +#define CAM_JPEG_ENC_INPUT_IMAGE 0x0 + +/* ENC output port resource type */ +#define CAM_JPEG_ENC_OUTPUT_IMAGE 0x1 + +#define CAM_JPEG_ENC_IO_IMAGES_MAX 0x2 + +/* DMA input port resource type */ +#define CAM_JPEG_DMA_INPUT_IMAGE 0x0 + +/* DMA output port resource type */ +#define CAM_JPEG_DMA_OUTPUT_IMAGE 0x1 + +#define CAM_JPEG_DMA_IO_IMAGES_MAX 0x2 + +#define CAM_JPEG_IMAGE_MAX 0x2 + +/** + * struct cam_jpeg_dev_ver - Device information for particular hw type + * + * This is used to get device version info of JPEG ENC, JPEG DMA + * from hardware and use this info in CAM_QUERY_CAP IOCTL + * + * @size : Size of struct passed + * @dev_type: Hardware type for the cap info(jpeg enc, jpeg dma) + * @hw_ver: Major, minor and incr values of a device version + */ +struct cam_jpeg_dev_ver { + uint32_t size; + uint32_t dev_type; + struct cam_hw_version hw_ver; +}; + +/** + * struct cam_jpeg_query_cap_cmd - JPEG query device capability payload + * + * @dev_iommu_handle: Jpeg iommu handles for secure/non secure + * modes + * @cdm_iommu_handle: Iommu handles for secure/non secure modes + * @num_enc: Number of encoder + * @num_dma: Number of dma + * @dev_ver: Returned device capability array + */ +struct cam_jpeg_query_cap_cmd { + struct cam_iommu_handle dev_iommu_handle; + struct cam_iommu_handle cdm_iommu_handle; + uint32_t num_enc; + uint32_t num_dma; + struct cam_jpeg_dev_ver dev_ver[CAM_JPEG_DEV_TYPE_MAX]; +}; + +/** + * struct cam_jpeg_res_info - JPEG output resource info + * + * @format: Format of the resource + * @width: Width in pixels + * @height: Height in lines + * @fps: Fps + */ +struct cam_jpeg_res_info { + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t fps; +}; + +/** + * struct cam_jpeg_acquire_dev_info - An JPEG device info + * + * @dev_type: Device type (ENC/DMA) + * @reserved: Reserved Bytes + * @in_res: In resource info + * @in_res: Iut resource info + */ +struct cam_jpeg_acquire_dev_info { + uint32_t dev_type; + uint32_t reserved; + struct cam_jpeg_res_info in_res; + struct cam_jpeg_res_info out_res; +}; + +/** + * struct cam_jpeg_config_inout_param_info - JPEG Config time + * input output params + * + * @clk_index: Input Param- clock selection index.(-1 default) + * @output_size: Output Param - jpeg encode/dma output size in + * bytes + */ +struct cam_jpeg_config_inout_param_info { + int32_t clk_index; + int32_t output_size; +}; + +#endif /* __UAPI_CAM_JPEG_H__ */ diff --git a/include/uapi/media/cam_lrme.h b/include/uapi/media/cam_lrme.h new file mode 100644 index 000000000000..90e3e76e0624 --- /dev/null +++ b/include/uapi/media/cam_lrme.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_LRME_H__ +#define __UAPI_CAM_LRME_H__ + +#include "cam_defs.h" + +/* LRME Resource Types */ + +enum CAM_LRME_IO_TYPE { + CAM_LRME_IO_TYPE_TAR, + CAM_LRME_IO_TYPE_REF, + CAM_LRME_IO_TYPE_RES, + CAM_LRME_IO_TYPE_DS2, +}; + +#define CAM_LRME_INPUT_PORT_TYPE_TAR (1 << 0) +#define CAM_LRME_INPUT_PORT_TYPE_REF (1 << 1) + +#define CAM_LRME_OUTPUT_PORT_TYPE_DS2 (1 << 0) +#define CAM_LRME_OUTPUT_PORT_TYPE_RES (1 << 1) + +#define CAM_LRME_DEV_MAX 1 + + +struct cam_lrme_hw_version { + uint32_t gen; + uint32_t rev; + uint32_t step; +}; + +struct cam_lrme_dev_cap { + struct cam_lrme_hw_version clc_hw_version; + struct cam_lrme_hw_version bus_rd_hw_version; + struct cam_lrme_hw_version bus_wr_hw_version; + struct cam_lrme_hw_version top_hw_version; + struct cam_lrme_hw_version top_titan_version; +}; + +/** + * struct cam_lrme_query_cap_cmd - LRME query device capability payload + * + * @dev_iommu_handle: LRME iommu handles for secure/non secure + * modes + * @cdm_iommu_handle: Iommu handles for secure/non secure modes + * @num_devices: number of hardware devices + * @dev_caps: Returned device capability array + */ +struct cam_lrme_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + uint32_t num_devices; + struct cam_lrme_dev_cap dev_caps[CAM_LRME_DEV_MAX]; +}; + +struct cam_lrme_soc_info { + uint64_t clock_rate; + uint64_t bandwidth; + uint64_t reserved[4]; +}; + +struct cam_lrme_acquire_args { + struct cam_lrme_soc_info lrme_soc_info; +}; + +#endif /* __UAPI_CAM_LRME_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h new file mode 100644 index 000000000000..f495eb883fcd --- /dev/null +++ b/include/uapi/media/cam_req_mgr.h @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_LINUX_CAM_REQ_MGR_H +#define __UAPI_LINUX_CAM_REQ_MGR_H + +#include +#include +#include +#include +#include "cam_defs.h" + +#define CAM_REQ_MGR_VNODE_NAME "cam-req-mgr-devnode" + +#define CAM_DEVICE_TYPE_BASE (MEDIA_ENT_F_OLD_BASE) +#define CAM_VNODE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE) +#define CAM_SENSOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 1) +#define CAM_IFE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 2) +#define CAM_ICP_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 3) +#define CAM_LRME_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 4) +#define CAM_JPEG_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 5) +#define CAM_FD_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 6) +#define CAM_CPAS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 7) +#define CAM_CSIPHY_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 8) +#define CAM_ACTUATOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 9) +#define CAM_CCI_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 10) +#define CAM_FLASH_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 11) +#define CAM_EEPROM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 12) +#define CAM_OIS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 13) + +/* cam_req_mgr hdl info */ +#define CAM_REQ_MGR_HDL_IDX_POS 8 +#define CAM_REQ_MGR_HDL_IDX_MASK ((1 << CAM_REQ_MGR_HDL_IDX_POS) - 1) +#define CAM_REQ_MGR_GET_HDL_IDX(hdl) (hdl & CAM_REQ_MGR_HDL_IDX_MASK) + +/** + * Max handles supported by cam_req_mgr + * It includes both session and device handles + */ +#define CAM_REQ_MGR_MAX_HANDLES 64 +#define MAX_LINKS_PER_SESSION 2 + +/* V4L event type which user space will subscribe to */ +#define V4L_EVENT_CAM_REQ_MGR_EVENT (V4L2_EVENT_PRIVATE_START + 0) + +/* Specific event ids to get notified in user space */ +#define V4L_EVENT_CAM_REQ_MGR_SOF 0 +#define V4L_EVENT_CAM_REQ_MGR_ERROR 1 +#define V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS 2 + +/* SOF Event status */ +#define CAM_REQ_MGR_SOF_EVENT_SUCCESS 0 +#define CAM_REQ_MGR_SOF_EVENT_ERROR 1 + +/* Link control operations */ +#define CAM_REQ_MGR_LINK_ACTIVATE 0 +#define CAM_REQ_MGR_LINK_DEACTIVATE 1 + +/** + * Request Manager : flush_type + * @CAM_REQ_MGR_FLUSH_TYPE_ALL: Req mgr will remove all the pending + * requests from input/processing queue. + * @CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ: Req mgr will remove only particular + * request id from input/processing queue. + * @CAM_REQ_MGR_FLUSH_TYPE_MAX: Max number of the flush type + * @opcode: CAM_REQ_MGR_FLUSH_REQ + */ +#define CAM_REQ_MGR_FLUSH_TYPE_ALL 0 +#define CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ 1 +#define CAM_REQ_MGR_FLUSH_TYPE_MAX 2 + +/** + * Request Manager : Sync Mode type + * @CAM_REQ_MGR_SYNC_MODE_NO_SYNC: Req mgr will apply non-sync mode for this + * request. + * @CAM_REQ_MGR_SYNC_MODE_SYNC: Req mgr will apply sync mode for this request. + */ +#define CAM_REQ_MGR_SYNC_MODE_NO_SYNC 0 +#define CAM_REQ_MGR_SYNC_MODE_SYNC 1 + +/** + * struct cam_req_mgr_event_data + * @session_hdl: session handle + * @link_hdl: link handle + * @frame_id: frame id + * @reserved: reserved for 64 bit aligngment + * @req_id: request id + * @tv_sec: timestamp in seconds + * @tv_usec: timestamp in micro seconds + */ +struct cam_req_mgr_event_data { + int32_t session_hdl; + int32_t link_hdl; + int32_t frame_id; + int32_t reserved; + int64_t req_id; + uint64_t tv_sec; + uint64_t tv_usec; +}; + +/** + * struct cam_req_mgr_session_info + * @session_hdl: In/Output param - session_handle + * @opcode1: CAM_REQ_MGR_CREATE_SESSION + * @opcode2: CAM_REQ_MGR_DESTROY_SESSION + */ +struct cam_req_mgr_session_info { + int32_t session_hdl; + int32_t reserved; +}; + +/** + * struct cam_req_mgr_link_info + * @session_hdl: Input param - Identifier for CSL session + * @num_devices: Input Param - Num of devices to be linked + * @dev_hdls: Input param - List of device handles to be linked + * @link_hdl: Output Param -Identifier for link + * @opcode: CAM_REQ_MGR_LINK + */ +struct cam_req_mgr_link_info { + int32_t session_hdl; + uint32_t num_devices; + int32_t dev_hdls[CAM_REQ_MGR_MAX_HANDLES]; + int32_t link_hdl; +}; + +/** + * struct cam_req_mgr_unlink_info + * @session_hdl: input param - session handle + * @link_hdl: input param - link handle + * @opcode: CAM_REQ_MGR_UNLINK + */ +struct cam_req_mgr_unlink_info { + int32_t session_hdl; + int32_t link_hdl; +}; + +/** + * struct cam_req_mgr_flush_info + * @brief: User can tell drivers to flush a particular request id or + * flush all requests from its pending processing queue. Flush is a + * blocking call and driver shall ensure all requests are flushed + * before returning. + * @session_hdl: Input param - Identifier for CSL session + * @link_hdl: Input Param -Identifier for link + * @flush_type: User can cancel a particular req id or can flush + * all requests in queue + * @reserved: reserved for 64 bit aligngment + * @req_id: field is valid only if flush type is cancel request + * for flush all this field value is not considered. + * @opcode: CAM_REQ_MGR_FLUSH_REQ + */ +struct cam_req_mgr_flush_info { + int32_t session_hdl; + int32_t link_hdl; + uint32_t flush_type; + uint32_t reserved; + int64_t req_id; +}; + +/** struct cam_req_mgr_sched_info + * @session_hdl: Input param - Identifier for CSL session + * @link_hdl: Input Param -Identifier for link + * inluding itself. + * @bubble_enable: Input Param - Cam req mgr will do bubble recovery if this + * flag is set. + * @sync_mode: Type of Sync mode for this request + * @req_id: Input Param - Request Id from which all requests will be flushed + */ +struct cam_req_mgr_sched_request { + int32_t session_hdl; + int32_t link_hdl; + int32_t bubble_enable; + int32_t sync_mode; + int64_t req_id; +}; + +/** + * struct cam_req_mgr_sync_mode + * @session_hdl: Input param - Identifier for CSL session + * @sync_mode: Input Param - Type of sync mode + * @num_links: Input Param - Num of links in sync mode (Valid only + * when sync_mode is one of SYNC enabled modes) + * @link_hdls: Input Param - Array of link handles to be in sync mode + * (Valid only when sync_mode is one of SYNC + * enabled modes) + * @master_link_hdl: Input Param - To dictate which link's SOF drives system + * (Valid only when sync_mode is one of SYNC + * enabled modes) + * + * @opcode: CAM_REQ_MGR_SYNC_MODE + */ +struct cam_req_mgr_sync_mode { + int32_t session_hdl; + int32_t sync_mode; + int32_t num_links; + int32_t link_hdls[MAX_LINKS_PER_SESSION]; + int32_t master_link_hdl; + int32_t reserved; +}; + +/** + * struct cam_req_mgr_link_control + * @ops: Link operations: activate/deactive + * @session_hdl: Input param - Identifier for CSL session + * @num_links: Input Param - Num of links + * @reserved: reserved field + * @link_hdls: Input Param - Links to be activated/deactivated + * + * @opcode: CAM_REQ_MGR_LINK_CONTROL + */ +struct cam_req_mgr_link_control { + int32_t ops; + int32_t session_hdl; + int32_t num_links; + int32_t reserved; + int32_t link_hdls[MAX_LINKS_PER_SESSION]; +}; + +/** + * cam_req_mgr specific opcode ids + */ +#define CAM_REQ_MGR_CREATE_DEV_NODES (CAM_COMMON_OPCODE_MAX + 1) +#define CAM_REQ_MGR_CREATE_SESSION (CAM_COMMON_OPCODE_MAX + 2) +#define CAM_REQ_MGR_DESTROY_SESSION (CAM_COMMON_OPCODE_MAX + 3) +#define CAM_REQ_MGR_LINK (CAM_COMMON_OPCODE_MAX + 4) +#define CAM_REQ_MGR_UNLINK (CAM_COMMON_OPCODE_MAX + 5) +#define CAM_REQ_MGR_SCHED_REQ (CAM_COMMON_OPCODE_MAX + 6) +#define CAM_REQ_MGR_FLUSH_REQ (CAM_COMMON_OPCODE_MAX + 7) +#define CAM_REQ_MGR_SYNC_MODE (CAM_COMMON_OPCODE_MAX + 8) +#define CAM_REQ_MGR_ALLOC_BUF (CAM_COMMON_OPCODE_MAX + 9) +#define CAM_REQ_MGR_MAP_BUF (CAM_COMMON_OPCODE_MAX + 10) +#define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11) +#define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) +#define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) +/* end of cam_req_mgr opcodes */ + +#define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) +#define CAM_MEM_FLAG_HW_READ_ONLY (1<<1) +#define CAM_MEM_FLAG_HW_WRITE_ONLY (1<<2) +#define CAM_MEM_FLAG_KMD_ACCESS (1<<3) +#define CAM_MEM_FLAG_UMD_ACCESS (1<<4) +#define CAM_MEM_FLAG_PROTECTED_MODE (1<<5) +#define CAM_MEM_FLAG_CMD_BUF_TYPE (1<<6) +#define CAM_MEM_FLAG_PIXEL_BUF_TYPE (1<<7) +#define CAM_MEM_FLAG_STATS_BUF_TYPE (1<<8) +#define CAM_MEM_FLAG_PACKET_BUF_TYPE (1<<9) +#define CAM_MEM_FLAG_CACHE (1<<10) +#define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11) +#define CAM_MEM_FLAG_CDSP_OUTPUT (1<<12) + +#define CAM_MEM_MMU_MAX_HANDLE 16 + +/* Maximum allowed buffers in existence */ +#define CAM_MEM_BUFQ_MAX 1024 + +#define CAM_MEM_MGR_SECURE_BIT_POS 15 +#define CAM_MEM_MGR_HDL_IDX_SIZE 15 +#define CAM_MEM_MGR_HDL_FD_SIZE 16 +#define CAM_MEM_MGR_HDL_IDX_END_POS 16 +#define CAM_MEM_MGR_HDL_FD_END_POS 32 + +#define CAM_MEM_MGR_HDL_IDX_MASK ((1 << CAM_MEM_MGR_HDL_IDX_SIZE) - 1) + +#define GET_MEM_HANDLE(idx, fd) \ + ((idx & CAM_MEM_MGR_HDL_IDX_MASK) | \ + (fd << (CAM_MEM_MGR_HDL_FD_END_POS - CAM_MEM_MGR_HDL_FD_SIZE))) \ + +#define GET_FD_FROM_HANDLE(hdl) \ + (hdl >> (CAM_MEM_MGR_HDL_FD_END_POS - CAM_MEM_MGR_HDL_FD_SIZE)) \ + +#define CAM_MEM_MGR_GET_HDL_IDX(hdl) (hdl & CAM_MEM_MGR_HDL_IDX_MASK) + +#define CAM_MEM_MGR_SET_SECURE_HDL(hdl, flag) \ + ((flag) ? (hdl |= (1 << CAM_MEM_MGR_SECURE_BIT_POS)) : \ + ((hdl) &= ~(1 << CAM_MEM_MGR_SECURE_BIT_POS))) + +#define CAM_MEM_MGR_IS_SECURE_HDL(hdl) \ + (((hdl) & \ + (1<> CAM_MEM_MGR_SECURE_BIT_POS) + +/** + * memory allocation type + */ +#define CAM_MEM_DMA_NONE 0 +#define CAM_MEM_DMA_BIDIRECTIONAL 1 +#define CAM_MEM_DMA_TO_DEVICE 2 +#define CAM_MEM_DMA_FROM_DEVICE 3 + + +/** + * memory cache operation + */ +#define CAM_MEM_CLEAN_CACHE 1 +#define CAM_MEM_INV_CACHE 2 +#define CAM_MEM_CLEAN_INV_CACHE 3 + + +/** + * struct cam_mem_alloc_out_params + * @buf_handle: buffer handle + * @fd: output buffer file descriptor + * @vaddr: virtual address pointer + */ +struct cam_mem_alloc_out_params { + uint32_t buf_handle; + int32_t fd; + uint64_t vaddr; +}; + +/** + * struct cam_mem_map_out_params + * @buf_handle: buffer handle + * @reserved: reserved for future + * @vaddr: virtual address pointer + */ +struct cam_mem_map_out_params { + uint32_t buf_handle; + uint32_t reserved; + uint64_t vaddr; +}; + +/** + * struct cam_mem_mgr_alloc_cmd + * @len: size of buffer to allocate + * @align: alignment of the buffer + * @mmu_hdls: array of mmu handles + * @num_hdl: number of handles + * @flags: flags of the buffer + * @out: out params + */ +/* CAM_REQ_MGR_ALLOC_BUF */ +struct cam_mem_mgr_alloc_cmd { + uint64_t len; + uint64_t align; + int32_t mmu_hdls[CAM_MEM_MMU_MAX_HANDLE]; + uint32_t num_hdl; + uint32_t flags; + struct cam_mem_alloc_out_params out; +}; + +/** + * struct cam_mem_mgr_map_cmd + * @mmu_hdls: array of mmu handles + * @num_hdl: number of handles + * @flags: flags of the buffer + * @fd: output buffer file descriptor + * @reserved: reserved field + * @out: out params + */ + +/* CAM_REQ_MGR_MAP_BUF */ +struct cam_mem_mgr_map_cmd { + int32_t mmu_hdls[CAM_MEM_MMU_MAX_HANDLE]; + uint32_t num_hdl; + uint32_t flags; + int32_t fd; + uint32_t reserved; + struct cam_mem_map_out_params out; +}; + +/** + * struct cam_mem_mgr_map_cmd + * @buf_handle: buffer handle + * @reserved: reserved field + */ +/* CAM_REQ_MGR_RELEASE_BUF */ +struct cam_mem_mgr_release_cmd { + int32_t buf_handle; + uint32_t reserved; +}; + +/** + * struct cam_mem_mgr_map_cmd + * @buf_handle: buffer handle + * @ops: cache operations + */ +/* CAM_REQ_MGR_CACHE_OPS */ +struct cam_mem_cache_ops_cmd { + int32_t buf_handle; + uint32_t mem_cache_ops; +}; + +/** + * Request Manager : error message type + * @CAM_REQ_MGR_ERROR_TYPE_DEVICE: Device error message, fatal to session + * @CAM_REQ_MGR_ERROR_TYPE_REQUEST: Error on a single request, not fatal + * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal + * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered + */ +#define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 +#define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 +#define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 +#define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 + +/** + * struct cam_req_mgr_error_msg + * @error_type: type of error + * @request_id: request id of frame + * @device_hdl: device handle + * @linke_hdl: link_hdl + * @resource_size: size of the resource + */ +struct cam_req_mgr_error_msg { + uint32_t error_type; + uint32_t request_id; + int32_t device_hdl; + int32_t link_hdl; + uint64_t resource_size; +}; + +/** + * struct cam_req_mgr_frame_msg + * @request_id: request id of the frame + * @frame_id: frame id of the frame + * @timestamp: timestamp of the frame + * @link_hdl: link handle associated with this message + * @sof_status: sof status success or fail + */ +struct cam_req_mgr_frame_msg { + uint64_t request_id; + uint64_t frame_id; + uint64_t timestamp; + int32_t link_hdl; + uint32_t sof_status; +}; + +/** + * struct cam_req_mgr_message + * @session_hdl: session to which the frame belongs to + * @reserved: reserved field + * @u: union which can either be error or frame message + */ +struct cam_req_mgr_message { + int32_t session_hdl; + int32_t reserved; + union { + struct cam_req_mgr_error_msg err_msg; + struct cam_req_mgr_frame_msg frame_msg; + } u; +}; +#endif /* __UAPI_LINUX_CAM_REQ_MGR_H */ diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h new file mode 100644 index 000000000000..57a5c4674ca2 --- /dev/null +++ b/include/uapi/media/cam_sensor.h @@ -0,0 +1,485 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_SENSOR_H__ +#define __UAPI_CAM_SENSOR_H__ + +#include +#include +#include "cam_defs.h" + +#define CAM_SENSOR_PROBE_CMD (CAM_COMMON_OPCODE_MAX + 1) +#define CAM_FLASH_MAX_LED_TRIGGERS 3 +#define MAX_OIS_NAME_SIZE 32 +#define CAM_CSIPHY_SECURE_MODE_ENABLED 1 +/** + * struct cam_sensor_query_cap - capabilities info for sensor + * + * @slot_info : Indicates about the slotId or cell Index + * @secure_camera : Camera is in secure/Non-secure mode + * @pos_pitch : Sensor position pitch + * @pos_roll : Sensor position roll + * @pos_yaw : Sensor position yaw + * @actuator_slot_id : Actuator slot id which connected to sensor + * @eeprom_slot_id : EEPROM slot id which connected to sensor + * @ois_slot_id : OIS slot id which connected to sensor + * @flash_slot_id : Flash slot id which connected to sensor + * @csiphy_slot_id : CSIphy slot id which connected to sensor + * + */ +struct cam_sensor_query_cap { + uint32_t slot_info; + uint32_t secure_camera; + uint32_t pos_pitch; + uint32_t pos_roll; + uint32_t pos_yaw; + uint32_t actuator_slot_id; + uint32_t eeprom_slot_id; + uint32_t ois_slot_id; + uint32_t flash_slot_id; + uint32_t csiphy_slot_id; +} __attribute__((packed)); + +/** + * struct cam_csiphy_query_cap - capabilities info for csiphy + * + * @slot_info : Indicates about the slotId or cell Index + * @version : CSIphy version + * @clk lane : Of the 5 lanes, informs lane configured + * as clock lane + * @reserved + */ +struct cam_csiphy_query_cap { + uint32_t slot_info; + uint32_t version; + uint32_t clk_lane; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_actuator_query_cap - capabilities info for actuator + * + * @slot_info : Indicates about the slotId or cell Index + * @reserved + */ +struct cam_actuator_query_cap { + uint32_t slot_info; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_eeprom_query_cap_t - capabilities info for eeprom + * + * @slot_info : Indicates about the slotId or cell Index + * @eeprom_kernel_probe : Indicates about the kernel or userspace probe + */ +struct cam_eeprom_query_cap_t { + uint32_t slot_info; + uint16_t eeprom_kernel_probe; + uint16_t is_multimodule_mode; +} __attribute__((packed)); + +/** + * struct cam_ois_query_cap_t - capabilities info for ois + * + * @slot_info : Indicates about the slotId or cell Index + */ +struct cam_ois_query_cap_t { + uint32_t slot_info; + uint16_t reserved; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_info - Contains slave I2C related info + * + * @slave_addr : Slave address + * @i2c_freq_mode : 4 bits are used for I2c freq mode + * @cmd_type : Explains type of command + */ +struct cam_cmd_i2c_info { + uint32_t slave_addr; + uint8_t i2c_freq_mode; + uint8_t cmd_type; + uint16_t reserved; +} __attribute__((packed)); + +/** + * struct cam_ois_opcode - Contains OIS opcode + * + * @prog : OIS FW prog register address + * @coeff : OIS FW coeff register address + * @pheripheral : OIS pheripheral + * @memory : OIS memory + */ +struct cam_ois_opcode { + uint32_t prog; + uint32_t coeff; + uint32_t pheripheral; + uint32_t memory; +} __attribute__((packed)); + +/** + * struct cam_cmd_ois_info - Contains OIS slave info + * + * @slave_addr : OIS i2c slave address + * @i2c_freq_mode : i2c frequency mode + * @cmd_type : Explains type of command + * @ois_fw_flag : indicates if fw is present or not + * @is_ois_calib : indicates the calibration data is available + * @ois_name : OIS name + * @opcode : opcode + */ +struct cam_cmd_ois_info { + uint16_t slave_addr; + uint8_t i2c_freq_mode; + uint8_t cmd_type; + uint8_t ois_fw_flag; + uint8_t is_ois_calib; + char ois_name[MAX_OIS_NAME_SIZE]; + struct cam_ois_opcode opcode; +} __attribute__((packed)); + +/** + * struct cam_cmd_probe - Contains sensor slave info + * + * @data_type : Slave register data type + * @addr_type : Slave register address type + * @op_code : Don't Care + * @cmd_type : Explains type of command + * @reg_addr : Slave register address + * @expected_data : Data expected at slave register address + * @data_mask : Data mask if only few bits are valid + * @camera_id : Indicates the slot to which camera + * needs to be probed + * @reserved + */ +struct cam_cmd_probe { + uint8_t data_type; + uint8_t addr_type; + uint8_t op_code; + uint8_t cmd_type; + uint32_t reg_addr; + uint32_t expected_data; + uint32_t data_mask; + uint16_t camera_id; + uint16_t reserved; +} __attribute__((packed)); + +/** + * struct cam_power_settings - Contains sensor power setting info + * + * @power_seq_type : Type of power sequence + * @reserved + * @config_val_low : Lower 32 bit value configuration value + * @config_val_high : Higher 32 bit value configuration value + * + */ +struct cam_power_settings { + uint16_t power_seq_type; + uint16_t reserved; + uint32_t config_val_low; + uint32_t config_val_high; +} __attribute__((packed)); + +/** + * struct cam_cmd_power - Explains about the power settings + * + * @count : Number of power settings follows + * @reserved + * @cmd_type : Explains type of command + * @power_settings : Contains power setting info + */ +struct cam_cmd_power { + uint32_t count; + uint8_t reserved; + uint8_t cmd_type; + uint16_t more_reserved; + struct cam_power_settings power_settings[1]; +} __attribute__((packed)); + +/** + * struct i2c_rdwr_header - header of READ/WRITE I2C command + * + * @ count : Number of registers / data / reg-data pairs + * @ op_code : Operation code + * @ cmd_type : Command buffer type + * @ data_type : I2C data type + * @ addr_type : I2C address type + * @ reserved + */ +struct i2c_rdwr_header { + uint32_t count; + uint8_t op_code; + uint8_t cmd_type; + uint8_t data_type; + uint8_t addr_type; +} __attribute__((packed)); + +/** + * struct i2c_random_wr_payload - payload for I2C random write + * + * @ reg_addr : Register address + * @ reg_data : Register data + * + */ +struct i2c_random_wr_payload { + uint32_t reg_addr; + uint32_t reg_data; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_random_wr - I2C random write command + * @ header : header of READ/WRITE I2C command + * @ random_wr_payload : payload for I2C random write + */ +struct cam_cmd_i2c_random_wr { + struct i2c_rdwr_header header; + struct i2c_random_wr_payload random_wr_payload[1]; +} __attribute__((packed)); + +/** + * struct cam_cmd_read - I2C read command + * @ reg_data : Register data + * @ reserved + */ +struct cam_cmd_read { + uint32_t reg_data; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_continuous_wr - I2C continuous write command + * @ header : header of READ/WRITE I2C command + * @ reg_addr : Register address + * @ data_read : I2C read command + */ +struct cam_cmd_i2c_continuous_wr { + struct i2c_rdwr_header header; + uint32_t reg_addr; + struct cam_cmd_read data_read[1]; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_random_rd - I2C random read command + * @ header : header of READ/WRITE I2C command + * @ data_read : I2C read command + */ +struct cam_cmd_i2c_random_rd { + struct i2c_rdwr_header header; + struct cam_cmd_read data_read[1]; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_continuous_rd - I2C continuous continuous read command + * @ header : header of READ/WRITE I2C command + * @ reg_addr : Register address + * + */ +struct cam_cmd_i2c_continuous_rd { + struct i2c_rdwr_header header; + uint32_t reg_addr; +} __attribute__((packed)); + +/** + * struct cam_cmd_conditional_wait - Conditional wait command + * @data_type : Data type + * @addr_type : Address type + * @op_code : Opcode + * @cmd_type : Explains type of command + * @timeout : Timeout for retries + * @reserved + * @reg_addr : Register Address + * @reg_data : Register data + * @data_mask : Data mask if only few bits are valid + * @camera_id : Indicates the slot to which camera + * needs to be probed + * + */ +struct cam_cmd_conditional_wait { + uint8_t data_type; + uint8_t addr_type; + uint16_t reserved; + uint8_t op_code; + uint8_t cmd_type; + uint16_t timeout; + uint32_t reg_addr; + uint32_t reg_data; + uint32_t data_mask; +} __attribute__((packed)); + +/** + * struct cam_cmd_unconditional_wait - Un-conditional wait command + * @delay : Delay + * @op_code : Opcode + * @cmd_type : Explains type of command + */ +struct cam_cmd_unconditional_wait { + int16_t delay; + int16_t reserved; + uint8_t op_code; + uint8_t cmd_type; + uint16_t reserved1; +} __attribute__((packed)); + +/** + * cam_csiphy_info: Provides cmdbuffer structre + * @lane_mask : Lane mask details + * @lane_assign : Lane sensor will be using + * @csiphy_3phase : Total number of lanes + * @combo_mode : Info regarding combo_mode is enable / disable + * @lane_cnt : Total number of lanes + * @secure_mode : Secure mode flag to enable / disable + * @3phase : Details whether 3Phase / 2Phase operation + * @settle_time : Settling time in ms + * @data_rate : Data rate + * + */ +struct cam_csiphy_info { + uint16_t lane_mask; + uint16_t lane_assign; + uint8_t csiphy_3phase; + uint8_t combo_mode; + uint8_t lane_cnt; + uint8_t secure_mode; + uint64_t settle_time; + uint64_t data_rate; +} __attribute__((packed)); + +/** + * cam_csiphy_acquire_dev_info : Information needed for + * csiphy at the time of acquire + * @combo_mode : Indicates the device mode of operation + * @reserved + * + */ +struct cam_csiphy_acquire_dev_info { + uint32_t combo_mode; + uint32_t reserved; +} __attribute__((packed)); + +/** + * cam_sensor_acquire_dev : Updates sensor acuire cmd + * @device_handle : Updates device handle + * @session_handle : Session handle for acquiring device + * @handle_type : Resource handle type + * @reserved + * @info_handle : Handle to additional info + * needed for sensor sub modules + * + */ +struct cam_sensor_acquire_dev { + uint32_t session_handle; + uint32_t device_handle; + uint32_t handle_type; + uint32_t reserved; + uint64_t info_handle; +} __attribute__((packed)); + +/** + * cam_sensor_streamon_dev : StreamOn command for the sensor + * @session_handle : Session handle for acquiring device + * @device_handle : Updates device handle + * @handle_type : Resource handle type + * @reserved + * @info_handle : Information Needed at the time of streamOn + * + */ +struct cam_sensor_streamon_dev { + uint32_t session_handle; + uint32_t device_handle; + uint32_t handle_type; + uint32_t reserved; + uint64_t info_handle; +} __attribute__((packed)); + +/** + * struct cam_flash_init : Init command for the flash + * @flash_type : flash hw type + * @reserved + * @cmd_type : command buffer type + */ +struct cam_flash_init { + uint8_t flash_type; + uint16_t reserved; + uint8_t cmd_type; +} __attribute__((packed)); + +/** + * struct cam_flash_set_rer : RedEyeReduction command buffer + * + * @count : Number of flash leds + * @opcode : Command buffer opcode + * CAM_FLASH_FIRE_RER + * @cmd_type : command buffer operation type + * @num_iteration : Number of led turn on/off sequence + * @reserved + * @led_on_delay_ms : flash led turn on time in ms + * @led_off_delay_ms : flash led turn off time in ms + * @led_current_ma : flash led current in ma + * + */ +struct cam_flash_set_rer { + uint32_t count; + uint8_t opcode; + uint8_t cmd_type; + uint16_t num_iteration; + uint32_t led_on_delay_ms; + uint32_t led_off_delay_ms; + uint32_t led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS]; +} __attribute__((packed)); + +/** + * struct cam_flash_set_on_off : led turn on/off command buffer + * + * @count : Number of Flash leds + * @opcode : command buffer opcodes + * CAM_FLASH_FIRE_LOW + * CAM_FLASH_FIRE_HIGH + * CAM_FLASH_OFF + * @cmd_type : command buffer operation type + * @led_current_ma : flash led current in ma + * + */ +struct cam_flash_set_on_off { + uint32_t count; + uint8_t opcode; + uint8_t cmd_type; + uint16_t reserved; + uint32_t led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS]; +} __attribute__((packed)); + +/** + * struct cam_flash_query_curr : query current command buffer + * + * @reserved + * @opcode : command buffer opcode + * @cmd_type : command buffer operation type + * @query_current_ma : battery current in ma + * + */ +struct cam_flash_query_curr { + uint16_t reserved; + uint8_t opcode; + uint8_t cmd_type; + uint32_t query_current_ma; +} __attribute__ ((packed)); + +/** + * struct cam_flash_query_cap : capabilities info for flash + * + * @slot_info : Indicates about the slotId or cell Index + * @max_current_flash : max supported current for flash + * @max_duration_flash : max flash turn on duration + * @max_current_torch : max supported current for torch + * + */ +struct cam_flash_query_cap_info { + uint32_t slot_info; + uint32_t max_current_flash[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t max_duration_flash[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t max_current_torch[CAM_FLASH_MAX_LED_TRIGGERS]; +} __attribute__ ((packed)); + +#endif diff --git a/include/uapi/media/cam_sync.h b/include/uapi/media/cam_sync.h new file mode 100644 index 000000000000..d1ab63fd4294 --- /dev/null +++ b/include/uapi/media/cam_sync.h @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_SYNC_H__ +#define __UAPI_CAM_SYNC_H__ + +#include +#include +#include +#include + +#define CAM_SYNC_DEVICE_NAME "cam_sync_device" + +/* V4L event which user space will subscribe to */ +#define CAM_SYNC_V4L_EVENT (V4L2_EVENT_PRIVATE_START + 0) + +/* Specific event ids to get notified in user space */ +#define CAM_SYNC_V4L_EVENT_ID_CB_TRIG 0 + +/* Size of opaque payload sent to kernel for safekeeping until signal time */ +#define CAM_SYNC_USER_PAYLOAD_SIZE 2 + +/* Device type for sync device needed for device discovery */ +#define CAM_SYNC_DEVICE_TYPE (MEDIA_ENT_F_OLD_BASE) + +#define CAM_SYNC_GET_PAYLOAD_PTR(ev, type) \ + (type *)((char *)ev.u.data + sizeof(struct cam_sync_ev_header)) + +#define CAM_SYNC_GET_HEADER_PTR(ev) \ + ((struct cam_sync_ev_header *)ev.u.data) + +#define CAM_SYNC_STATE_INVALID 0 +#define CAM_SYNC_STATE_ACTIVE 1 +#define CAM_SYNC_STATE_SIGNALED_SUCCESS 2 +#define CAM_SYNC_STATE_SIGNALED_ERROR 3 + +/** + * struct cam_sync_ev_header - Event header for sync event notification + * + * @sync_obj: Sync object + * @status: Status of the object + */ +struct cam_sync_ev_header { + int32_t sync_obj; + int32_t status; +}; + +/** + * struct cam_sync_info - Sync object creation information + * + * @name: Optional string representation of the sync object + * @sync_obj: Sync object returned after creation in kernel + */ +struct cam_sync_info { + char name[64]; + int32_t sync_obj; +}; + +/** + * struct cam_sync_signal - Sync object signaling struct + * + * @sync_obj: Sync object to be signaled + * @sync_state: State of the sync object to which it should be signaled + */ +struct cam_sync_signal { + int32_t sync_obj; + uint32_t sync_state; +}; + +/** + * struct cam_sync_merge - Merge information for sync objects + * + * @sync_objs: Pointer to sync objects + * @num_objs: Number of objects in the array + * @merged: Merged sync object + */ +struct cam_sync_merge { + __u64 sync_objs; + uint32_t num_objs; + int32_t merged; +}; + +/** + * struct cam_sync_userpayload_info - Payload info from user space + * + * @sync_obj: Sync object for which payload has to be registered for + * @reserved: Reserved + * @payload: Pointer to user payload + */ +struct cam_sync_userpayload_info { + int32_t sync_obj; + uint32_t reserved; + __u64 payload[CAM_SYNC_USER_PAYLOAD_SIZE]; +}; + +/** + * struct cam_sync_wait - Sync object wait information + * + * @sync_obj: Sync object to wait on + * @reserved: Reserved + * @timeout_ms: Timeout in milliseconds + */ +struct cam_sync_wait { + int32_t sync_obj; + uint32_t reserved; + uint64_t timeout_ms; +}; + +/** + * struct cam_private_ioctl_arg - Sync driver ioctl argument + * + * @id: IOCTL command id + * @size: Size of command payload + * @result: Result of command execution + * @reserved: Reserved + * @ioctl_ptr: Pointer to user data + */ +struct cam_private_ioctl_arg { + __u32 id; + __u32 size; + __u32 result; + __u32 reserved; + __u64 ioctl_ptr; +}; + +#define CAM_PRIVATE_IOCTL_CMD \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct cam_private_ioctl_arg) + +#define CAM_SYNC_CREATE 0 +#define CAM_SYNC_DESTROY 1 +#define CAM_SYNC_SIGNAL 2 +#define CAM_SYNC_MERGE 3 +#define CAM_SYNC_REGISTER_PAYLOAD 4 +#define CAM_SYNC_DEREGISTER_PAYLOAD 5 +#define CAM_SYNC_WAIT 6 + +#endif /* __UAPI_CAM_SYNC_H__ */ -- GitLab From c28468e27892b0f8e6f3cab3e39719d1d9e9812d Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Thu, 23 May 2019 07:16:09 -0700 Subject: [PATCH 004/410] msm: camera: Add custom ratelimit logs and use for old blob type Adding custom ratelimited log types and use it in generic blob handler for isp and icp. Change-Id: Iec6c94f41506839055c5e0036d2e343849dc12b5 Signed-off-by: Mukund Madhusudan Atre Signed-off-by: Karthik Anantha Ram --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 3 +- drivers/cam_utils/cam_debug_util.h | 81 ++++++++++++++++++- 3 files changed, 82 insertions(+), 4 deletions(-) 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 2a77519d92cb..9cb19fae68c9 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 @@ -4118,7 +4118,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, switch (blob_type) { case CAM_ICP_CMD_GENERIC_BLOB_CLK: - CAM_WARN(CAM_ICP, + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_ICP, 300, 1, "Using deprecated blob type GENERIC_BLOB_CLK"); if (blob_size != sizeof(struct cam_icp_clk_bw_request)) { CAM_ERR(CAM_ICP, "Mismatch blob size %d expected %lu", diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index cb0b341b981f..07a7c196522c 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -4625,7 +4625,8 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, struct cam_isp_bw_config *bw_config; struct cam_isp_prepare_hw_update_data *prepare_hw_data; - CAM_WARN(CAM_ISP, "Deprecated Blob TYPE_BW_CONFIG"); + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_ISP, 300, 1, + "Deprecated Blob TYPE_BW_CONFIG"); if (blob_size < sizeof(struct cam_isp_bw_config)) { CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); return -EINVAL; diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 7380312dcde0..55f316b41da4 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_DEBUG_UTIL_H_ @@ -109,7 +109,7 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_INFO_RATE_LIMIT(__module, fmt, args...) \ - pr_err_ratelimited("CAM_INFO: %s: %s: %d " fmt "\n", \ + pr_info_ratelimited("CAM_INFO: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) /* @@ -130,5 +130,82 @@ const char *cam_get_module_name(unsigned int module_id); #define CAM_ERR_RATE_LIMIT(__module, fmt, args...) \ pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) +/* + * CAM_WARN_RATE_LIMIT + * @brief : This Macro will print warning logs with ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_WARN_RATE_LIMIT(__module, fmt, args...) \ + pr_warn_ratelimited("CAM_WARN: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +/* + * CAM_WARN_RATE_LIMIT_CUSTOM + * @brief : This Macro will print warn logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_WARN_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_warn( \ + "CAM_WARN: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, \ + __LINE__, ##args); \ + }) + +/* + * CAM_INFO_RATE_LIMIT_CUSTOM + * @brief : This Macro will print info logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_INFO_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_info( \ + "CAM_INFO: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, \ + __LINE__, ##args); \ + }) + +/* + * CAM_ERR_RATE_LIMIT_CUSTOM + * @brief : This Macro will print error logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_ERR_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_err( \ + "CAM_ERR: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, \ + __LINE__, ##args); \ + }) #endif /* _CAM_DEBUG_UTIL_H_ */ -- GitLab From 396a4cc5761c12c0ad084225d1aa74b4a854fcec Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Thu, 23 May 2019 08:13:23 -0700 Subject: [PATCH 005/410] msm: camera: Add LCR in axi bw vote and checks for memory free Adding LCR resource id in isp bw voting for axi bw voting v1 path and v2 path. Also, adding checks for unwanted memory free during cpas probe. Change-Id: Ib3dca34727b640326893fb227b160a42dab457fc Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_cpas/cam_cpas_soc.c | 13 +++++--- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 36 +++++---------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index 9dd24cdaa3d1..6c34dd0687e6 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -102,12 +102,17 @@ int cam_cpas_node_tree_cleanup(struct cam_cpas *cpas_core, } for (i = 0; i < CAM_CPAS_MAX_TREE_LEVELS; i++) { - of_node_put(soc_private->level_node[i]); - soc_private->level_node[i] = NULL; + if (soc_private->level_node[i]) { + of_node_put(soc_private->level_node[i]); + soc_private->level_node[i] = NULL; + } + } + + if (soc_private->camera_bus_node) { + of_node_put(soc_private->camera_bus_node); + soc_private->camera_bus_node = NULL; } - of_node_put(soc_private->camera_bus_node); - soc_private->camera_bus_node = NULL; mutex_destroy(&cpas_core->tree_lock); return 0; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 07a7c196522c..2895e6f9d824 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2715,7 +2715,8 @@ static int cam_isp_classify_vote_info( if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD) || - (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB)) { + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_LCR)) { if (split_idx == CAM_ISP_HW_SPLIT_LEFT) { if (*camif_l_bw_updated) return rc; @@ -2890,8 +2891,11 @@ static int cam_isp_blob_bw_update( if (!hw_mgr_res->hw_res[i]) continue; - if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) - || (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD)) + if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) + || (hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_LCR)) if (i == CAM_ISP_HW_SPLIT_LEFT) { if (camif_l_bw_updated) continue; @@ -2925,32 +2929,8 @@ static int cam_isp_blob_bw_update( bw_config->rdi_vote[idx].cam_bw_bps; ext_bw_bps = bw_config->rdi_vote[idx].ext_bw_bps; - } else if (hw_mgr_res->res_id == - CAM_ISP_HW_VFE_IN_PDLIB) { - if (i == CAM_ISP_HW_SPLIT_LEFT) { - if (camif_l_bw_updated) - continue; - - cam_bw_bps = - bw_config->left_pix_vote.cam_bw_bps; - ext_bw_bps = - bw_config->left_pix_vote.ext_bw_bps; - - camif_l_bw_updated = true; - } else { - if (camif_r_bw_updated) - continue; - - cam_bw_bps = - bw_config->right_pix_vote.cam_bw_bps; - ext_bw_bps = - bw_config->right_pix_vote.ext_bw_bps; - - camif_r_bw_updated = true; - } } else { - if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_LCR - && hw_mgr_res->hw_res[i]) { + if (hw_mgr_res->hw_res[i]) { CAM_ERR(CAM_ISP, "Invalid res_id %u", hw_mgr_res->res_id); rc = -EINVAL; -- GitLab From 40047f58dfcf74a0ac9372bb262394ac0bb33f25 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 11 Jun 2019 11:31:11 -0700 Subject: [PATCH 006/410] msm: camera: core : Validate the dev name during the node ioctl handler Validate the context device name with node name. If device name is not matching return the error. Change-Id: I8dee4e6f64e17b0d1e486077a2c8b0df562a702e Signed-off-by: Rishabh Jain --- drivers/cam_core/cam_context.c | 2 +- drivers/cam_core/cam_context.h | 7 ++- drivers/cam_core/cam_node.c | 44 ++++++++++++++++++- drivers/cam_core/cam_node.h | 5 +-- drivers/cam_fd/cam_fd_context.c | 4 +- drivers/cam_icp/cam_icp_context.c | 2 +- drivers/cam_isp/cam_isp_context.c | 2 +- drivers/cam_jpeg/cam_jpeg_context.c | 2 +- drivers/cam_lrme/cam_lrme_context.c | 4 +- .../cam_actuator/cam_actuator_dev.h | 5 ++- drivers/cam_sensor_module/cam_csiphy/Makefile | 1 + .../cam_csiphy/cam_csiphy_dev.h | 4 +- drivers/cam_sensor_module/cam_eeprom/Makefile | 2 + .../cam_eeprom/cam_eeprom_dev.h | 4 +- .../cam_flash/cam_flash_dev.c | 2 + .../cam_flash/cam_flash_dev.h | 3 ++ drivers/cam_sensor_module/cam_ois/Makefile | 1 + .../cam_sensor_module/cam_ois/cam_ois_dev.h | 7 +-- .../cam_sensor/cam_sensor_dev.h | 5 ++- 19 files changed, 83 insertions(+), 23 deletions(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 85908a3b6a4d..d2ec399e2895 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -519,7 +519,7 @@ int cam_context_init(struct cam_context *ctx, mutex_init(&ctx->sync_mutex); spin_lock_init(&ctx->lock); - ctx->dev_name = dev_name; + strlcpy(ctx->dev_name, dev_name, CAM_CTX_DEV_NAME_MAX_LENGTH); ctx->dev_id = dev_id; ctx->ctx_id = ctx_id; ctx->last_flush_req = 0; diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 55fd376f33d6..1583dd06df3f 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CONTEXT_H_ @@ -15,6 +15,9 @@ /* Forward declarations */ struct cam_context; +/* max device name string length*/ +#define CAM_CTX_DEV_NAME_MAX_LENGTH 20 + /* max request number */ #define CAM_CTX_REQ_MAX 20 #define CAM_CTX_CFG_MAX 20 @@ -177,7 +180,7 @@ struct cam_ctx_ops { * */ struct cam_context { - const char *dev_name; + char dev_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; uint64_t dev_id; uint32_t ctx_id; struct list_head list; diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 1ef4aa59302e..9c4c6f242336 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -27,7 +27,7 @@ static void cam_node_print_ctx_state( spin_lock_bh(&ctx->lock); CAM_INFO(CAM_CORE, "[%s][%d] : state=%d, refcount=%d, active_req_list=%d, pending_req_list=%d, wait_req_list=%d, free_req_list=%d", - ctx->dev_name ? ctx->dev_name : "null", + ctx->dev_name, i, ctx->state, atomic_read(&(ctx->refcount.refcount.refs)), list_empty(&ctx->active_req_list), @@ -148,6 +148,12 @@ static int __cam_node_handle_acquire_hw_v1(struct cam_node *node, return -EINVAL; } + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + rc = cam_context_handle_acquire_hw(ctx, acquire); if (rc) { CAM_ERR(CAM_CORE, "Acquire device failed for node %s", @@ -226,6 +232,12 @@ static int __cam_node_handle_start_dev(struct cam_node *node, return -EINVAL; } + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + rc = cam_context_handle_start_dev(ctx, start); if (rc) CAM_ERR(CAM_CORE, "Start failure for node %s", node->name); @@ -259,6 +271,12 @@ static int __cam_node_handle_stop_dev(struct cam_node *node, return -EINVAL; } + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + rc = cam_context_handle_stop_dev(ctx, stop); if (rc) CAM_ERR(CAM_CORE, "Stop failure for node %s", node->name); @@ -292,6 +310,12 @@ static int __cam_node_handle_config_dev(struct cam_node *node, return -EINVAL; } + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + rc = cam_context_handle_config_dev(ctx, config); if (rc) CAM_ERR(CAM_CORE, "Config failure for node %s", node->name); @@ -325,6 +349,12 @@ static int __cam_node_handle_flush_dev(struct cam_node *node, return -EINVAL; } + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + rc = cam_context_handle_flush_dev(ctx, flush); if (rc) CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name); @@ -358,6 +388,12 @@ static int __cam_node_handle_release_dev(struct cam_node *node, return -EINVAL; } + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + if (ctx->state > CAM_CTX_UNINIT && ctx->state < CAM_CTX_STATE_MAX) { rc = cam_context_handle_release_dev(ctx, release); if (rc) @@ -413,6 +449,12 @@ static int __cam_node_handle_release_hw_v1(struct cam_node *node, return -EINVAL; } + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + rc = cam_context_handle_release_hw(ctx, release); if (rc) CAM_ERR(CAM_CORE, "context release failed node %s", node->name); diff --git a/drivers/cam_core/cam_node.h b/drivers/cam_core/cam_node.h index ad49c4b619a9..062d0213115c 100644 --- a/drivers/cam_core/cam_node.h +++ b/drivers/cam_core/cam_node.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_NODE_H_ @@ -11,7 +11,6 @@ #include "cam_hw_mgr_intf.h" #include "cam_req_mgr_interface.h" -#define CAM_NODE_NAME_LENGTH_MAX 256 #define CAM_NODE_STATE_UNINIT 0 #define CAM_NODE_STATE_INIT 1 @@ -31,7 +30,7 @@ * */ struct cam_node { - char name[CAM_NODE_NAME_LENGTH_MAX]; + char name[CAM_CTX_DEV_NAME_MAX_LENGTH]; uint32_t state; /* context pool */ diff --git a/drivers/cam_fd/cam_fd_context.c b/drivers/cam_fd/cam_fd_context.c index 427fcf788081..8805859abb00 100644 --- a/drivers/cam_fd/cam_fd_context.c +++ b/drivers/cam_fd/cam_fd_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include @@ -10,7 +10,7 @@ #include "cam_fd_context.h" #include "cam_trace.h" -static const char fd_dev_name[] = "fd"; +static const char fd_dev_name[] = "cam-fd"; /* Functions in Available state */ static int __cam_fd_ctx_acquire_dev_in_available(struct cam_context *ctx, diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index c7d9c63f8429..86876a35b671 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -20,7 +20,7 @@ #include "cam_debug_util.h" #include "cam_packet_util.h" -static const char icp_dev_name[] = "icp"; +static const char icp_dev_name[] = "cam-icp"; static int cam_icp_context_dump_active_request(void *data, unsigned long iova, uint32_t buf_info) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 7e1fa25910b2..282bf55cbf4f 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -20,7 +20,7 @@ #include "cam_isp_context.h" #include "cam_common_util.h" -static const char isp_dev_name[] = "isp"; +static const char isp_dev_name[] = "cam-isp"; #define INC_STATE_MONITOR_HEAD(head) \ (atomic64_add_return(1, head) % \ diff --git a/drivers/cam_jpeg/cam_jpeg_context.c b/drivers/cam_jpeg/cam_jpeg_context.c index e28aae21e7d9..b16a9dfed011 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.c +++ b/drivers/cam_jpeg/cam_jpeg_context.c @@ -14,7 +14,7 @@ #include "cam_debug_util.h" #include "cam_packet_util.h" -static const char jpeg_dev_name[] = "jpeg"; +static const char jpeg_dev_name[] = "cam-jpeg"; static int cam_jpeg_context_dump_active_request(void *data, unsigned long iova, uint32_t buf_info) diff --git a/drivers/cam_lrme/cam_lrme_context.c b/drivers/cam_lrme/cam_lrme_context.c index 3270d77af5fe..ae8f93c500ef 100644 --- a/drivers/cam_lrme/cam_lrme_context.c +++ b/drivers/cam_lrme/cam_lrme_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include @@ -9,7 +9,7 @@ #include "cam_debug_util.h" #include "cam_lrme_context.h" -static const char lrme_dev_name[] = "lrme"; +static const char lrme_dev_name[] = "cam-lrme"; static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h index 9c704c0cd48e..e4e5e4305246 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -25,6 +25,7 @@ #include "cam_sensor_util.h" #include "cam_soc_util.h" #include "cam_debug_util.h" +#include "cam_context.h" #define NUM_MASTERS 2 #define NUM_QUEUES 2 @@ -83,6 +84,7 @@ struct intf_params { /** * struct cam_actuator_ctrl_t + * @device_name: Device name * @i2c_driver: I2C device info * @pdev: Platform device * @cci_i2c_master: I2C structure @@ -98,10 +100,10 @@ struct intf_params { * @i2c_data: I2C register settings structure * @act_info: Sensor query cap structure * @of_node: Node ptr - * @device_name: Device name * @last_flush_req: Last request to flush */ struct cam_actuator_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; struct i2c_driver *i2c_driver; enum cci_i2c_master_t cci_i2c_master; enum cci_device_num cci_num; @@ -116,7 +118,6 @@ struct cam_actuator_ctrl_t { struct i2c_data_settings i2c_data; struct cam_actuator_query_cap act_info; struct intf_params bridge_intf; - char device_name[20]; uint32_t last_flush_req; }; diff --git a/drivers/cam_sensor_module/cam_csiphy/Makefile b/drivers/cam_sensor_module/cam_csiphy/Makefile index 88ab6ed9a1bb..eb23b89c2108 100644 --- a/drivers/cam_sensor_module/cam_csiphy/Makefile +++ b/drivers/cam_sensor_module/cam_csiphy/Makefile @@ -8,5 +8,6 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_u ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy_soc.o cam_csiphy_dev.o cam_csiphy_core.o diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 7453db1e0658..2bae9a51529b 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -26,6 +26,7 @@ #include #include "cam_soc_util.h" #include "cam_debug_util.h" +#include "cam_context.h" #define MAX_CSIPHY 6 #define MAX_DPHY_DATA_LN 4 @@ -235,6 +236,7 @@ struct cam_csiphy_param { /** * struct csiphy_device + * @device_name: Device name * @pdev: Platform device * @irq: Interrupt structure * @base: Base address @@ -263,6 +265,7 @@ struct cam_csiphy_param { * @csiphy_cpas_cp_reg_mask: CP reg mask for phy instance */ struct csiphy_device { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; struct mutex mutex; uint32_t hw_version; enum cam_csiphy_state csiphy_state; @@ -282,7 +285,6 @@ struct csiphy_device { uint32_t clk_lane; uint32_t acquire_count; uint32_t start_dev_count; - char device_name[20]; uint32_t is_acquired_dev_combo_mode; struct cam_hw_soc_info soc_info; uint32_t cpas_handle; diff --git a/drivers/cam_sensor_module/cam_eeprom/Makefile b/drivers/cam_sensor_module/cam_eeprom/Makefile index e52bc01dc5a5..850b16787c11 100644 --- a/drivers/cam_sensor_module/cam_eeprom/Makefile +++ b/drivers/cam_sensor_module/cam_eeprom/Makefile @@ -8,4 +8,6 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_u ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core + obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom_dev.o cam_eeprom_core.o cam_eeprom_soc.o diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h index 2bac99f8c298..6bf08d11ed6a 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -22,6 +22,7 @@ #include #include #include "cam_soc_util.h" +#include "cam_context.h" #define DEFINE_MSM_MUTEX(mutexname) \ static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) @@ -152,6 +153,7 @@ struct eebin_info { /** * struct cam_eeprom_ctrl_t - EEPROM control structure + * @device_name : Device name * @pdev : platform device * @spi : spi device * @eeprom_mutex : eeprom mutex @@ -170,6 +172,7 @@ struct eebin_info { * @eebin_info : EEBIN address, size info */ struct cam_eeprom_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; struct platform_device *pdev; struct spi_device *spi; struct mutex eeprom_mutex; @@ -184,7 +187,6 @@ struct cam_eeprom_ctrl_t { enum cam_eeprom_state cam_eeprom_state; bool userspace_probe; struct cam_eeprom_memory_block_t cal_data; - char device_name[20]; uint16_t is_multimodule_mode; struct i2c_settings_array wr_settings; struct eebin_info eebin_info; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index d0610667e626..5eccfd8aa11b 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -379,6 +379,8 @@ static int cam_flash_init_subdev(struct cam_flash_ctrl *fctrl) { int rc = 0; + strlcpy(fctrl->device_name, CAM_FLASH_NAME, + sizeof(fctrl->device_name)); fctrl->v4l2_dev_str.internal_ops = &cam_flash_internal_ops; fctrl->v4l2_dev_str.ops = &cam_flash_subdev_ops; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index c4f17656ace0..8bd5b9115f05 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -28,6 +28,7 @@ #include "cam_debug_util.h" #include "cam_sensor_io.h" #include "cam_flash_core.h" +#include "cam_context.h" #define CAMX_FLASH_DEV_NAME "cam-flash-dev" @@ -153,6 +154,7 @@ struct cam_flash_func_tbl { /** * struct cam_flash_ctrl + * @device_name : Device name * @soc_info : Soc related information * @pdev : Platform device * @per_frame[] : Per_frame setting array @@ -179,6 +181,7 @@ struct cam_flash_func_tbl { * @last_flush_req : last request to flush */ struct cam_flash_ctrl { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; struct cam_hw_soc_info soc_info; struct platform_device *pdev; struct cam_sensor_power_ctrl_t power_info; diff --git a/drivers/cam_sensor_module/cam_ois/Makefile b/drivers/cam_sensor_module/cam_ois/Makefile index e987a2257e9e..345203739517 100644 --- a/drivers/cam_sensor_module/cam_ois/Makefile +++ b/drivers/cam_sensor_module/cam_ois/Makefile @@ -8,5 +8,6 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois_dev.o cam_ois_core.o cam_ois_soc.o diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index 0c2a450fe058..1808a2b2f0c6 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_OIS_DEV_H_ #define _CAM_OIS_DEV_H_ @@ -20,6 +20,7 @@ #include #include #include "cam_soc_util.h" +#include "cam_context.h" #define DEFINE_MSM_MUTEX(mutexname) \ static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) @@ -83,6 +84,7 @@ struct cam_ois_intf_params { /** * struct cam_ois_ctrl_t - OIS ctrl private data + * @device_name : ois device_name * @pdev : platform device * @ois_mutex : ois mutex * @soc_info : ois soc related info @@ -95,7 +97,6 @@ struct cam_ois_intf_params { * @i2c_calib_data : ois i2c calib settings * @ois_device_type : ois device type * @cam_ois_state : ois_device_state - * @ois_name : ois name * @ois_fw_flag : flag for firmware download * @is_ois_calib : flag for Calibration data * @opcode : ois opcode @@ -103,6 +104,7 @@ struct cam_ois_intf_params { * */ struct cam_ois_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; struct platform_device *pdev; struct mutex ois_mutex; struct cam_hw_soc_info soc_info; @@ -116,7 +118,6 @@ struct cam_ois_ctrl_t { struct i2c_settings_array i2c_mode_data; enum msm_camera_device_type_t ois_device_type; enum cam_ois_state cam_ois_state; - char device_name[20]; char ois_name[32]; uint8_t ois_fw_flag; uint8_t is_ois_calib; diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h index 86676a4c8f0a..37e0affdf991 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -23,6 +23,7 @@ #include #include #include "cam_debug_util.h" +#include "cam_context.h" #define NUM_MASTERS 2 #define NUM_QUEUES 2 @@ -65,6 +66,7 @@ struct intf_params { /** * struct cam_sensor_ctrl_t: Camera control structure + * @device_name: Sensor device name * @pdev: Platform device * @cam_sensor_mutex: Sensor mutex * @sensordata: Sensor board Information @@ -80,7 +82,6 @@ struct intf_params { * @i2c_data: Sensor I2C register settings * @sensor_info: Sensor query cap structure * @bridge_intf: Bridge interface structure - * @device_name: Sensor device structure * @streamon_count: Count to hold the number of times stream on called * @streamoff_count: Count to hold the number of times stream off called * @bob_reg_index: Hold to BoB regulator index @@ -89,6 +90,7 @@ struct intf_params { * @pipeline_delay: Sensor pipeline delay */ struct cam_sensor_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; struct platform_device *pdev; struct cam_hw_soc_info soc_info; struct mutex cam_sensor_mutex; @@ -106,7 +108,6 @@ struct cam_sensor_ctrl_t { struct i2c_data_settings i2c_data; struct cam_sensor_query_cap sensor_info; struct intf_params bridge_intf; - char device_name[20]; uint32_t streamon_count; uint32_t streamoff_count; int bob_reg_index; -- GitLab From aeffc3147d8af1f5157b5a4f9279e5e1cb3f075f Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 11 Jun 2019 11:32:53 -0700 Subject: [PATCH 007/410] msm: camera: Adds state variable in mem manager Add state variable for camera mem manager to show initialization status. Ensure that all operations are rejected before initialization. Change-Id: I1ddbaaf6fbed59e4804476562c97f6895d99e916 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_req_mgr/cam_mem_mgr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 73ac694eeafa..b7f77506d004 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -234,6 +234,11 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) return -EINVAL; } + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!buf_handle || !vaddr_ptr || !len) return -EINVAL; -- GitLab From f8b0159a3e6dbdc551986bf38c36f95950ce85f7 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 11 Jun 2019 11:34:01 -0700 Subject: [PATCH 008/410] msm: camera: Update dynamic clock voting for csiphy Update the clock voting, datarate settings for csiphy version 1.2.2. Change-Id: I7b08819c1918d2eeec530733d42828e092bf2aa9 Signed-off-by: Shankar Ravi --- drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 4dd5273e0438..f66f8de722eb 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -302,10 +302,14 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_common_reg_1_2; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = true; csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; -- GitLab From 391b3fa3d62f2ecfe2ce44b2dad694695cb8599f Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 11 Jun 2019 11:34:49 -0700 Subject: [PATCH 009/410] msm: camera: Update csiphy settings for lito Update the register settings for CPHY 3phase. Change-Id: I5cdc5cd348f9f861215206c59e674efdcdc7159c Signed-off-by: Shankar Ravi --- .../cam_csiphy/cam_csiphy_soc.c | 7 +- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 86 ++++++------------- 2 files changed, 31 insertions(+), 62 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index f66f8de722eb..a6aba5940181 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -302,14 +302,13 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_common_reg_1_2; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_2; - csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; - csiphy_dev->is_divisor_32_comp = true; + csiphy_dev->is_divisor_32_comp = false; csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; - csiphy_dev->ctrl_reg->data_rates_settings_table = - &data_rate_delta_table; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 6ee9e155b93d..d99c4ee3758a 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,10 +12,10 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 6, - .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 22, - .csiphy_3ph_config_array_size = 38, + .csiphy_common_array_size = 5, + .csiphy_reset_array_size = 4, + .csiphy_2ph_config_array_size = 21, + .csiphy_3ph_config_array_size = 32, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -23,17 +23,15 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { struct csiphy_reg_t csiphy_common_reg_1_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, - {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, - {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; @@ -71,11 +69,10 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -99,7 +96,6 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -123,7 +119,6 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -147,7 +142,6 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -171,7 +165,6 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -195,11 +188,10 @@ struct csiphy_reg_t {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -223,7 +215,6 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -247,7 +238,6 @@ struct csiphy_reg_t {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -271,7 +261,6 @@ struct csiphy_reg_t {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -295,14 +284,13 @@ struct csiphy_reg_t {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; struct csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { - {0x015C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -310,10 +298,10 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x016C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -331,29 +319,23 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x035C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x036C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -371,18 +353,12 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x055C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -390,10 +366,10 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x056C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -411,15 +387,9 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From 7fd239ba2485784d8863662e3049d5b089865846 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 11 Jun 2019 11:36:01 -0700 Subject: [PATCH 010/410] msm: camera: Enable top debug status cfg register In case of VFE Overflow print additional debug information based on whether the overflow is on bus side or in the IFE modules. Change-Id: I292bab0e75824bd1f151a4824f25220784c81172 Signed-off-by: Vishalsingh Hajeri Signed-off-by: Venkat Chinta --- drivers/cam_cpas/cam_cpas_hw.c | 6 +- .../isp_hw/include/cam_vfe_hw_intf.h | 1 + .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 16 +++ .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h | 9 ++ .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 113 +++++++++++++++--- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h | 1 + .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 92 ++++++++++++-- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.h | 1 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h | 15 +++ 9 files changed, 218 insertions(+), 36 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index f7bf5a22129f..d180b4ecf9aa 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -377,15 +377,13 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, if (!CAM_CPAS_CLIENT_VALID(client_indx)) return -EINVAL; - mutex_lock(&cpas_core->client_mutex[client_indx]); cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index); - rc = -EPERM; - goto unlock_client; + return -EPERM; } if (mb) @@ -397,8 +395,6 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, *value = reg_value; -unlock_client: - mutex_unlock(&cpas_core->client_mutex[client_indx]); return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index 7944cbc8933f..a1d1c6a60881 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -60,6 +60,7 @@ enum cam_vfe_hw_irq_regs { CAM_IFE_IRQ_CAMIF_REG_STATUS1 = 1, CAM_IFE_IRQ_CAMIF_REG_STATUS2 = 2, CAM_IFE_IRQ_VIOLATION_STATUS = 3, + CAM_IFE_IRQ_BUS_OVERFLOW_STATUS = 4, CAM_IFE_IRQ_REGISTERS_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index e855a54dc723..48eb7f1b028d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -80,6 +80,7 @@ static struct cam_vfe_camif_ver3_reg_data vfe_480_camif_reg_data = { .enable_diagnostic_hw = 0x1, .pp_camif_cfg_en_shift = 0, .pp_camif_cfg_ife_out_en_shift = 8, + .top_debug_cfg_en = 1, }; static struct cam_vfe_top_ver3_reg_offset_common vfe480_top_common_reg = { @@ -106,6 +107,21 @@ static struct cam_vfe_top_ver3_reg_offset_common vfe480_top_common_reg = { .diag_sensor_status_0 = 0x00000068, .diag_sensor_status_1 = 0x00000098, .bus_overflow_status = 0x0000AA68, + .top_debug_cfg = 0x000000DC, + .top_debug_0 = 0x00000080, + .top_debug_1 = 0x00000084, + .top_debug_2 = 0x00000088, + .top_debug_3 = 0x0000008C, + .top_debug_4 = 0x0000009C, + .top_debug_5 = 0x000000A0, + .top_debug_6 = 0x000000A4, + .top_debug_7 = 0x000000A8, + .top_debug_8 = 0x000000AC, + .top_debug_9 = 0x000000B0, + .top_debug_10 = 0x000000B4, + .top_debug_11 = 0x000000B8, + .top_debug_12 = 0x000000BC, + .top_debug_13 = 0x000000C0, }; static struct cam_vfe_camif_lite_ver3_reg vfe480_camif_rdi[3] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h index c9d66ed94e97..221c372f72b1 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h @@ -48,6 +48,11 @@ static struct cam_vfe_top_ver3_reg_offset_common vfe48x_top_common_reg = { .diag_config = 0x00000050, .diag_sensor_status_0 = 0x00000054, .bus_overflow_status = 0x00001A68, + .top_debug_cfg = 0x00000074, + .top_debug_0 = 0x0000005C, + .top_debug_1 = 0x00000068, + .top_debug_2 = 0x0000006C, + .top_debug_3 = 0x00000070, }; static struct cam_vfe_camif_lite_ver3_reg vfe48x_camif_rdi[4] = { @@ -118,6 +123,7 @@ static struct cam_vfe_camif_lite_ver3_reg_data vfe48x_camif_rdi_reg_data[4] = { .error_irq_mask2 = 0x100, .subscribe_irq_mask1 = 0x3, .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, }, { .extern_reg_update_shift = 0, @@ -131,6 +137,7 @@ static struct cam_vfe_camif_lite_ver3_reg_data vfe48x_camif_rdi_reg_data[4] = { .error_irq_mask2 = 0x200, .subscribe_irq_mask1 = 0x30, .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, }, { .extern_reg_update_shift = 0, @@ -144,6 +151,7 @@ static struct cam_vfe_camif_lite_ver3_reg_data vfe48x_camif_rdi_reg_data[4] = { .error_irq_mask2 = 0x400, .subscribe_irq_mask1 = 0x300, .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, }, { .extern_reg_update_shift = 0, @@ -157,6 +165,7 @@ static struct cam_vfe_camif_lite_ver3_reg_data vfe48x_camif_rdi_reg_data[4] = { .error_irq_mask2 = 0x800, .subscribe_irq_mask1 = 0x3000, .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, }, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index bf527440e2d7..e71754098e80 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -17,6 +17,7 @@ #include "cam_vfe_camif_lite_ver3.h" #include "cam_debug_util.h" #include "cam_cdm_util.h" +#include "cam_cpas_api.h" struct cam_vfe_mux_camif_lite_data { void __iomem *mem_base; @@ -142,9 +143,8 @@ static int cam_vfe_camif_lite_err_irq_top_half( evt_payload->irq_reg_val[i] = cam_io_r(camif_lite_priv->mem_base + camif_lite_priv->common_reg->violation_status); - if (error_flag && !soc_private->is_ife_lite) - CAM_INFO(CAM_ISP, "Violation status = 0x%X", - evt_payload->irq_reg_val[i]); + evt_payload->irq_reg_val[++i] = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->bus_overflow_status); th_payload->evt_payload_priv = evt_payload; @@ -308,6 +308,10 @@ static int cam_vfe_camif_lite_resource_start( memset(err_irq_mask, 0, sizeof(err_irq_mask)); memset(irq_mask, 0, sizeof(irq_mask)); + /* config debug status registers */ + cam_io_w_mb(rsrc_data->reg_data->top_debug_cfg_en, rsrc_data->mem_base + + rsrc_data->common_reg->top_debug_cfg); + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = rsrc_data->reg_data->error_irq_mask0; err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = @@ -726,23 +730,93 @@ static int cam_vfe_camif_lite_process_cmd( return rc; } +static void cam_vfe_camif_lite_overflow_debug_info(uint32_t *status, + struct cam_vfe_mux_camif_lite_data *camif_lite_priv) +{ + uint32_t bus_overflow_status = 0; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t val0, val1, val2, val3; + + bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; + soc_private = camif_lite_priv->soc_info->soc_private; + + if (bus_overflow_status) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); + + } else { + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_0); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_1); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_2); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_3); + CAM_INFO(CAM_ISP, + "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", + val0, val1, val2, val3); + + if (soc_private->is_ife_lite) + return; + + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_4); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_5); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_6); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_7); + CAM_INFO(CAM_ISP, + "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", + val0, val1, val2, val3); + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_8); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_9); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_10); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_11); + CAM_INFO(CAM_ISP, + "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", + val0, val1, val2, val3); + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_12); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_13); + CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", + val0, val1); + } +} + static void cam_vfe_camif_lite_print_status(uint32_t *status, - int err_type, bool is_ife_lite) + int err_type, struct cam_vfe_mux_camif_lite_data *camif_lite_priv) { uint32_t violation_mask = 0x3F00, violation_status = 0; uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; + struct cam_vfe_soc_private *soc_private = NULL; if (!status) { CAM_ERR(CAM_ISP, "Invalid params"); return; } - bus_overflow_status = status[CAM_IFE_IRQ_REGISTERS_MAX]; + bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; violation_status = status[CAM_IFE_IRQ_VIOLATION_STATUS]; status_0 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; status_2 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]; + soc_private = camif_lite_priv->soc_info->soc_private; - if (is_ife_lite) + if (soc_private->is_ife_lite) goto ife_lite; if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW) { @@ -792,7 +866,8 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { CAM_INFO(CAM_ISP, "PDLIB / LCR Module hang"); - /* print debug registers here */ + /* print debug registers */ + cam_vfe_camif_lite_overflow_debug_info(status, camif_lite_priv); return; } @@ -874,6 +949,13 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "RDI3 BUS OVERFLOW"); } + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { + CAM_INFO(CAM_ISP, "RDI hang"); + /* print debug registers */ + cam_vfe_camif_lite_overflow_debug_info(status, camif_lite_priv); + return; + } + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION) { if (status_2 & 0x100) CAM_INFO(CAM_ISP, "RDI0 CAMIF VIOLATION"); @@ -942,9 +1024,8 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; struct cam_vfe_soc_private *soc_private = NULL; - uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX + 1]; + uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; int i = 0; - bool is_ife_lite = true; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -961,10 +1042,6 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( return -ENODEV; } - is_ife_lite = soc_private->is_ife_lite; - - memset(irq_status, 0, - sizeof(uint32_t) * (CAM_IFE_IRQ_REGISTERS_MAX + 1)); for (i = 0; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) irq_status[i] = payload->irq_reg_val[i]; @@ -1023,13 +1100,10 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( camif_lite_priv->event_cb(camif_lite_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); - irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = - cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->bus_overflow_status); - ret = CAM_VFE_IRQ_STATUS_OVERFLOW; - cam_vfe_camif_lite_print_status(irq_status, ret, is_ife_lite); + cam_vfe_camif_lite_print_status(irq_status, ret, + camif_lite_priv); if (camif_lite_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) cam_vfe_camif_lite_reg_dump(camif_lite_node); @@ -1047,7 +1121,8 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( ret = CAM_VFE_IRQ_STATUS_VIOLATION; - cam_vfe_camif_lite_print_status(irq_status, ret, is_ife_lite); + cam_vfe_camif_lite_print_status(irq_status, ret, + camif_lite_priv); if (camif_lite_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) cam_vfe_camif_lite_reg_dump(camif_lite_node); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h index ad8e44ef8e6c..54a38bdf41ca 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h @@ -40,6 +40,7 @@ struct cam_vfe_camif_lite_ver3_reg_data { uint32_t error_irq_mask2; uint32_t subscribe_irq_mask1; uint32_t enable_diagnostic_hw; + uint32_t top_debug_cfg_en; }; struct cam_vfe_camif_lite_ver3_hw_info { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 450d03428c63..e4a05a1031b7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -141,9 +141,8 @@ static int cam_vfe_camif_ver3_err_irq_top_half( evt_payload->irq_reg_val[i] = cam_io_r(camif_priv->mem_base + camif_priv->common_reg->violation_status); - if (error_flag) - CAM_INFO(CAM_ISP, "Violation status = 0x%X", - evt_payload->irq_reg_val[i]); + evt_payload->irq_reg_val[++i] = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->bus_overflow_status); th_payload->evt_payload_priv = evt_payload; @@ -374,6 +373,10 @@ static int cam_vfe_camif_ver3_resource_start( return -ENODEV; } + /* config debug status registers */ + cam_io_w_mb(rsrc_data->reg_data->top_debug_cfg_en, rsrc_data->mem_base + + rsrc_data->common_reg->top_debug_cfg); + /*config vfe core*/ val = (rsrc_data->pix_pattern << rsrc_data->reg_data->pixel_pattern_shift); @@ -733,8 +736,76 @@ static int cam_vfe_camif_ver3_process_cmd( return rc; } + +static void cam_vfe_camif_ver3_overflow_debug_info(uint32_t *status, + struct cam_vfe_mux_camif_ver3_data *camif_priv) +{ + struct cam_vfe_soc_private *soc_private; + uint32_t bus_overflow_status; + uint32_t val0, val1, val2, val3; + + bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; + soc_private = camif_priv->soc_info->soc_private; + + if (bus_overflow_status) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); + } else { + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_0); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_1); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_2); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_3); + CAM_INFO(CAM_ISP, + "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_4); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_5); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_6); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_7); + CAM_INFO(CAM_ISP, + "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_8); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_9); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_10); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_11); + CAM_INFO(CAM_ISP, + "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_12); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_13); + CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", + val0, val1); + } + +} + static void cam_vfe_camif_ver3_print_status(uint32_t *status, - int err_type) + int err_type, struct cam_vfe_mux_camif_ver3_data *camif_priv) { uint32_t violation_mask = 0x3F, module_id = 0; uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; @@ -744,7 +815,7 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, return; } - bus_overflow_status = status[CAM_IFE_IRQ_REGISTERS_MAX]; + bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; status_0 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; status_2 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]; @@ -829,6 +900,7 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { CAM_INFO(CAM_ISP, "PIXEL PIPE Module hang"); /* print debug registers */ + cam_vfe_camif_ver3_overflow_debug_info(status, camif_priv); return; } @@ -1100,7 +1172,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_mux_camif_ver3_data *camif_priv; struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; - uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX + 1] = {0}; + uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; int i = 0; if (!handler_priv || !evt_payload_priv) { @@ -1177,13 +1249,9 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); - irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = - cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->bus_overflow_status); - ret = CAM_VFE_IRQ_STATUS_OVERFLOW; - cam_vfe_camif_ver3_print_status(irq_status, ret); + cam_vfe_camif_ver3_print_status(irq_status, ret, camif_priv); if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) cam_vfe_camif_ver3_reg_dump(camif_node); @@ -1198,7 +1266,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_VIOLATION; - cam_vfe_camif_ver3_print_status(irq_status, ret); + cam_vfe_camif_ver3_print_status(irq_status, ret, camif_priv); if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) cam_vfe_camif_ver3_reg_dump(camif_node); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h index 3c82ca2ba7d6..40d8e40ae852 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h @@ -56,6 +56,7 @@ struct cam_vfe_camif_ver3_reg_data { uint32_t enable_diagnostic_hw; uint32_t pp_camif_cfg_en_shift; uint32_t pp_camif_cfg_ife_out_en_shift; + uint32_t top_debug_cfg_en; }; struct cam_vfe_camif_ver3_hw_info { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h index 1ae8e5d54a4d..dd0bb94c42c7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h @@ -48,6 +48,21 @@ struct cam_vfe_top_ver3_reg_offset_common { uint32_t diag_sensor_status_0; uint32_t diag_sensor_status_1; uint32_t bus_overflow_status; + uint32_t top_debug_cfg; + uint32_t top_debug_0; + uint32_t top_debug_1; + uint32_t top_debug_2; + uint32_t top_debug_3; + uint32_t top_debug_4; + uint32_t top_debug_5; + uint32_t top_debug_6; + uint32_t top_debug_7; + uint32_t top_debug_8; + uint32_t top_debug_9; + uint32_t top_debug_10; + uint32_t top_debug_11; + uint32_t top_debug_12; + uint32_t top_debug_13; }; struct cam_vfe_camif_common_cfg { -- GitLab From 2c55550c19d2f4bd75f2230a9db076ae343a30fa Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 11 Jun 2019 11:40:17 -0700 Subject: [PATCH 011/410] msm: camera: isp: Add debugfs parameter for state monitor dump This change adds a debugfs parameter to enable isp context state monitor dump rather than always print by default. This change also changes isp context substate to HALT only after stop hw is complete. Change-Id: I1025a46e9be63b4ee5808c2eb44672687d901c2e Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 44 ++++++++++++++++++++++++++----- drivers/cam_isp/cam_isp_context.h | 12 +++++++++ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 282bf55cbf4f..84f5e4937a9e 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -22,6 +22,8 @@ static const char isp_dev_name[] = "cam-isp"; +static struct cam_isp_ctx_debug isp_ctx_debug; + #define INC_STATE_MONITOR_HEAD(head) \ (atomic64_add_return(1, head) % \ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) @@ -3440,12 +3442,6 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( (struct cam_isp_context *) ctx->ctx_priv; struct cam_isp_stop_args stop_isp; - /* Mask off all the incoming hardware events */ - spin_lock_bh(&ctx->lock); - ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; - spin_unlock_bh(&ctx->lock); - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); - /* stop hw first */ if (ctx_isp->hw_ctx) { stop.ctxt_to_hw_map = ctx_isp->hw_ctx; @@ -3462,6 +3458,12 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( &stop); } + /* Mask off all the incoming hardware events */ + spin_lock_bh(&ctx->lock); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + while (!list_empty(&ctx->pending_req_list)) { req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); @@ -3725,7 +3727,8 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context, } else { CAM_DBG(CAM_ISP, "No handle function for substate %d", ctx_isp->substate_activated); - __cam_isp_ctx_dump_state_monitor_array(ctx_isp); + if (isp_ctx_debug.enable_state_monitor_dump) + __cam_isp_ctx_dump_state_monitor_array(ctx_isp); } CAM_DBG(CAM_ISP, "Exit: State %d Substate %d", @@ -3867,6 +3870,31 @@ static int cam_isp_context_dump_active_request(void *data, unsigned long iova, return rc; } +static int cam_isp_context_debug_register(void) +{ + isp_ctx_debug.dentry = debugfs_create_dir("camera_isp_ctx", + NULL); + + if (!isp_ctx_debug.dentry) { + CAM_ERR(CAM_ISP, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_u32("enable_state_monitor_dump", + 0644, + isp_ctx_debug.dentry, + &isp_ctx_debug.enable_state_monitor_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_state_monitor_dump"); + goto err; + } + + return 0; + +err: + debugfs_remove_recursive(isp_ctx_debug.dentry); + return -ENOMEM; +} + int cam_isp_context_init(struct cam_isp_context *ctx, struct cam_context *ctx_base, struct cam_req_mgr_kmd_ops *crm_node_intf, @@ -3918,6 +3946,8 @@ int cam_isp_context_init(struct cam_isp_context *ctx, CAM_ISP_CTX_ACTIVATED_MAX; } atomic64_set(&ctx->state_monitor_head, -1); + + cam_isp_context_debug_register(); err: return rc; } diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index bbf39b5617cf..1f5bd1048f5b 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -70,6 +70,18 @@ enum cam_isp_state_change_trigger { CAM_ISP_STATE_CHANGE_TRIGGER_MAX }; +/** + * struct cam_isp_ctx_debug - Contains debug parameters + * + * @dentry: Debugfs entry + * @enable_state_monitor_dump: Enable isp state monitor dump + * + */ +struct cam_isp_ctx_debug { + struct dentry *dentry; + uint32_t enable_state_monitor_dump; +}; + /** * struct cam_isp_ctx_irq_ops - Function table for handling IRQ callbacks * -- GitLab From 657d77d87d2474394bc22a50a62c9a0aecb1a16f Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 19 Jun 2019 12:17:30 -0700 Subject: [PATCH 012/410] msm: camera: icp: Protect icp context access at time of pagefault Take mutex before acessing icp context to prevent improper free. Change-Id: If2fd2c66dd9a00f1ab5c9ec1710573c2921dce6a Signed-off-by: Prakasha Nayak --- drivers/cam_icp/cam_icp_context.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 86876a35b671..6e043fd95c63 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -37,6 +37,14 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, return -EINVAL; } + mutex_lock(&ctx->ctx_mutex); + + if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { + CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", + ctx->ctx_id, ctx->state); + goto end; + } + CAM_INFO(CAM_ICP, "iommu fault for icp ctx %d state %d", ctx->ctx_id, ctx->state); @@ -55,6 +63,8 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, req->request_id, rc); } +end: + mutex_unlock(&ctx->ctx_mutex); return rc; } -- GitLab From eedac0e21c2c6158976b501775778750d06845c7 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 19 Jun 2019 12:19:58 -0700 Subject: [PATCH 013/410] msm: camera: Correct the return logic for error case Currently for the flush request error case, mutex unlock is executed without mutex lock which result in instability of system. This change returns with appropriate error code if error occurs. Change-Id: I2ff0056002c7d96a7100295f2ed6ba5cc0da2254 Signed-off-by: Jigarkumar Zala --- drivers/cam_req_mgr/cam_req_mgr_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 9f11077f05c4..e6c9d97b1c97 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3057,14 +3057,12 @@ int cam_req_mgr_flush_requests( if (!flush_info) { CAM_ERR(CAM_CRM, "flush req is NULL"); - rc = -EFAULT; - goto end; + return -EFAULT; } if (flush_info->flush_type >= CAM_REQ_MGR_FLUSH_TYPE_MAX) { CAM_ERR(CAM_CRM, "incorrect flush type %x", flush_info->flush_type); - rc = -EINVAL; - goto end; + return -EINVAL; } mutex_lock(&g_crm_core_dev->crm_lock); -- GitLab From af6455ddfd65a021203668a6d9b8cd1c36bfe077 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Fri, 24 May 2019 16:51:50 -0700 Subject: [PATCH 014/410] msm: camera: cpas: Add updated QoS settings for kona Adding updated values for registers in camnoc address space which determine QoS for different axi bw paths. Change-Id: I6a24b7650f542938fd9720ae86a0330b5d4fd048 Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_cpas/cpas_top/cpastop_v480_100.h | 106 +++++++------------ 1 file changed, 38 insertions(+), 68 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h index d4782d7df110..cbb521d30778 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -203,27 +203,25 @@ static struct cam_camnoc_specific .port_type = CAM_CAMNOC_CDM, .enable = true, .priority_lut_low = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x30, /* CDM_PRIORITYLUT_LOW */ - .value = 0x22222222, + .value = 0x0, }, .priority_lut_high = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x34, /* CDM_PRIORITYLUT_HIGH */ - .value = 0x22222222, + .value = 0x0, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0x38, /* CDM_URGENCY_LOW */ - .mask = 0x7, /* CDM_URGENCY_LOW_READ_MASK */ - .shift = 0x0, /* CDM_URGENCY_LOW_READ_SHIFT */ - .value = 0x2, + .value = 0x3, }, .danger_lut = { .enable = false, @@ -247,25 +245,25 @@ static struct cam_camnoc_specific .port_type = CAM_CAMNOC_FD, .enable = true, .priority_lut_low = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x630, /* FD_PRIORITYLUT_LOW */ - .value = 0x44444444, + .value = 0x0, }, .priority_lut_high = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x634, /* FD_PRIORITYLUT_HIGH */ - .value = 0x44444444, + .value = 0x0, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x638, /* FD_URGENCY_LOW */ - .value = 0x2, + .value = 0x33, }, .danger_lut = { .enable = false, @@ -305,13 +303,9 @@ static struct cam_camnoc_specific .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0xA38, /* IFE_LINEAR_URGENCY_LOW */ - /* IFE_LINEAR_URGENCY_LOW_WRITE_MASK */ - .mask = 0x70, - /* IFE_LINEAR_URGENCY_LOW_WRITE_SHIFT */ - .shift = 0x4, - .value = 3, + .value = 0x1030, }, .danger_lut = { .enable = true, @@ -323,7 +317,7 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0xA48, /* IFE_LINEAR_SAFELUT_LOW */ - .value = 0x1, + .value = 0xFFF0, }, .ubwc_ctl = { /* @@ -338,41 +332,37 @@ static struct cam_camnoc_specific .port_type = CAM_CAMNOC_IFE_RDI_RD, .enable = true, .priority_lut_low = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x1030, /* IFE_RDI_RD_PRIORITYLUT_LOW */ - .value = 0x66665433, + .value = 0x0, }, .priority_lut_high = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x1034, /* IFE_RDI_RD_PRIORITYLUT_HIGH */ - .value = 0x66666666, + .value = 0x0, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0x1038, /* IFE_RDI_RD_URGENCY_LOW */ - /* IFE_RDI_RD_URGENCY_LOW_WRITE_MASK */ - .mask = 0x70, - /* IFE_RDI_RD_URGENCY_LOW_WRITE_SHIFT */ - .shift = 0x4, - .value = 3, + .value = 0x3, }, .danger_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1040, /* IFE_RDI_RD_DANGERLUT_LOW */ - .value = 0xFFFFFF00, + .value = 0x0, }, .safe_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1048, /* IFE_RDI_RD_SAFELUT_LOW */ - .value = 0x1, + .value = 0x0, }, .ubwc_ctl = { /* @@ -403,13 +393,9 @@ static struct cam_camnoc_specific .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0x1438, /* IFE_RDI_WR_URGENCY_LOW */ - /* IFE_RDI_WR_URGENCY_LOW_WRITE_MASK */ - .mask = 0x70, - /* IFE_RDI_WR_URGENCY_LOW_WRITE_SHIFT */ - .shift = 0x4, - .value = 3, + .value = 0x1030, }, .danger_lut = { .enable = true, @@ -421,7 +407,7 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1448, /* IFE_RDI_WR_SAFELUT_LOW */ - .value = 0x1, + .value = 0xFFF0, }, .ubwc_ctl = { /* @@ -452,13 +438,9 @@ static struct cam_camnoc_specific .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0x1A38, /* IFE_UBWC_STATS_URGENCY_LOW */ - /* IFE_UBWC_STATS_URGENCY_LOW_WRITE_MASK */ - .mask = 0x70, - /* IFE_UBWC_STATS_URGENCY_LOW_WRITE_SHIFT */ - .shift = 0x4, - .value = 3, + .value = 0x1030, }, .danger_lut = { .enable = true, @@ -470,7 +452,7 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1A48, /* IFE_UBWC_STATS_SAFELUT_LOW */ - .value = 0x1, + .value = 0xFFF0, }, .ubwc_ctl = { /* @@ -489,14 +471,14 @@ static struct cam_camnoc_specific .port_type = CAM_CAMNOC_IPE0_RD, .enable = true, .priority_lut_low = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x1E30, /* IPE0_RD_PRIORITYLUT_LOW */ .value = 0x33333333, }, .priority_lut_high = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x1E34, /* IPE0_RD_PRIORITYLUT_HIGH */ @@ -505,13 +487,9 @@ static struct cam_camnoc_specific .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0x1E38, /* IPE0_RD_URGENCY_LOW */ - /* IPE0_RD_URGENCY_LOW_READ_MASK */ - .mask = 0x7, - /* IPE0_RD_URGENCY_LOW_READ_SHIFT */ - .shift = 0x0, - .value = 3, + .value = 0x3, }, .danger_lut = { .enable = false, @@ -544,14 +522,14 @@ static struct cam_camnoc_specific .port_type = CAM_CAMNOC_IPE1_BPS_RD, .enable = true, .priority_lut_low = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2430, /* IPE1_BPS_RD_PRIORITYLUT_LOW */ .value = 0x33333333, }, .priority_lut_high = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2434, /* IPE1_BPS_RD_PRIORITYLUT_HIGH */ @@ -560,13 +538,9 @@ static struct cam_camnoc_specific .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0x2438, /* IPE1_BPS_RD_URGENCY_LOW */ - /* IPE1_BPS_RD_URGENCY_LOW_READ_MASK */ - .mask = 0x7, - /* IPE1_BPS_RD_URGENCY_LOW_READ_SHIFT */ - .shift = 0x0, - .value = 3, + .value = 0x3, }, .danger_lut = { .enable = false, @@ -615,13 +589,9 @@ static struct cam_camnoc_specific .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .masked_value = 1, + .masked_value = 0, .offset = 0x2838, /* IPE_BPS_WR_URGENCY_LOW */ - /* IPE_BPS_WR_URGENCY_LOW_WRITE_MASK */ - .mask = 0x70, - /* IPE_BPS_WR_URGENCY_LOW_WRITE_SHIFT */ - .shift = 0x4, - .value = 3, + .value = 0x30, }, .danger_lut = { .enable = false, -- GitLab From e7e5e70f17403c3eb8be3076d5d020cab7b984c0 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 4 Jun 2019 16:46:56 -0700 Subject: [PATCH 015/410] msm: camera: ife: Enable sample drop on CSID RDI paths This change enables CSID sample drop on RDI paths by default. The sample drop pattern, as always, is set to 0 at init. This allows the userspace driver to simply program sample drop pattern on desired RDI paths to obtain sample dropped output without having to also overwrite config register to enable drop. This change also takes care of programming max value to sample drop period on version 480 hardware due to hardware limitations. It also adds a separate header file for CSID Lite version 480 hardware. Change-Id: I6e8ace1df3241b7ab4e34d9a13b382f5dde8b4f3 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 7 + .../isp_hw/ife_csid_hw/cam_ife_csid480.h | 2 + .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 37 +- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 4 + .../isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c | 13 +- .../isp_hw/ife_csid_hw/cam_ife_csid_lite480.h | 339 ++++++++++++++++++ .../isp_hw/include/cam_ife_csid_hw_intf.h | 2 + 7 files changed, 392 insertions(+), 12 deletions(-) create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 2895e6f9d824..fac5c41aa1a4 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1568,6 +1568,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( csid_acquire.out_port = in_port->data; csid_acquire.node_res = NULL; csid_acquire.crop_enable = crop_enable; + csid_acquire.drop_enable = false; hw_intf = cid_res->hw_res[i]->hw_intf; @@ -1697,6 +1698,12 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; csid_acquire.node_res = NULL; + /* + * Enable RDI pixel drop by default. CSID will enable only for + * ver 480 HW to allow userspace to control pixel drop pattern. + */ + csid_acquire.drop_enable = true; + /* Enable RDI crop for single ife use case only */ if (in_port->usage_type) csid_acquire.crop_enable = false; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h index c18a21ff7c32..f8eee4109b65 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h @@ -354,6 +354,8 @@ static struct cam_ife_csid_common_reg_offset .plain_fmt_shit_val = 10, .crop_v_en_shift_val = 6, .crop_h_en_shift_val = 5, + .drop_v_en_shift_val = 4, + .drop_h_en_shift_val = 3, .crop_shift = 16, .ipp_irq_mask_all = 0x7FFF, .rdi_irq_mask_all = 0x7FFF, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index cce05296f04a..a41d203d4402 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1015,6 +1015,7 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->start_line = reserve->in_port->line_start; path_data->end_line = reserve->in_port->line_stop; path_data->crop_enable = reserve->crop_enable; + path_data->drop_enable = reserve->drop_enable; CAM_DBG(CAM_ISP, "Res id: %d height:%d line_start %d line_stop %d crop_en %d", @@ -1589,10 +1590,6 @@ static int cam_ife_csid_init_config_pxl_path( csid_reg->cmn_reg->crop_v_en_shift_val) | (1 << 1) | 1; - val |= (1 << pxl_reg->pix_store_en_shift_val); - cam_io_w_mb(val, soc_info->reg_map[0].mem_base + - pxl_reg->csid_pxl_cfg0_addr); - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); if (rc) { CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); @@ -1600,6 +1597,16 @@ static int cam_ife_csid_init_config_pxl_path( } CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + if (camera_hw_version == CAM_CPAS_TITAN_480_V100) + val |= (path_data->drop_enable << + csid_reg->cmn_reg->drop_h_en_shift_val) | + (path_data->drop_enable << + csid_reg->cmn_reg->drop_v_en_shift_val); + + val |= (1 << pxl_reg->pix_store_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + if (path_data->is_valid_vc1_dt1 && camera_hw_version == CAM_CPAS_TITAN_480_V100) { val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -2012,9 +2019,6 @@ static int cam_ife_csid_init_config_rdi_path( csid_reg->cmn_reg->crop_v_en_shift_val) | (1 << 2) | 3; - cam_io_w_mb(val, soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); if (rc) { CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); @@ -2022,6 +2026,15 @@ static int cam_ife_csid_init_config_rdi_path( } CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + if (camera_hw_version == CAM_CPAS_TITAN_480_V100) + val |= (path_data->drop_enable << + csid_reg->cmn_reg->drop_h_en_shift_val) | + (path_data->drop_enable << + csid_reg->cmn_reg->drop_v_en_shift_val); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + if (path_data->is_valid_vc1_dt1 && camera_hw_version == CAM_CPAS_TITAN_480_V100) { val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -2077,8 +2090,16 @@ static int cam_ife_csid_init_config_rdi_path( /* set pixel drop pattern to 0 and period to 1 */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_pattern_addr); - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + + /* Write max value to pixel drop period due to a bug in ver 480 HW */ + if (camera_hw_version == CAM_CPAS_TITAN_480_V100 && + path_data->drop_enable) + cam_io_w_mb(0x1F, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_period_addr); + else + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_period_addr); + /* set line drop pattern to 0 and period to 1 */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_rpp_line_drop_pattern_addr); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index a3c54fed7c03..a68c56188c5f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -303,6 +303,8 @@ struct cam_ife_csid_common_reg_offset { uint32_t plain_fmt_shit_val; uint32_t crop_v_en_shift_val; uint32_t crop_h_en_shift_val; + uint32_t drop_v_en_shift_val; + uint32_t drop_h_en_shift_val; uint32_t crop_shift; uint32_t ipp_irq_mask_all; uint32_t rdi_irq_mask_all; @@ -410,6 +412,7 @@ struct cam_ife_csid_cid_data { * @out_format: output format * @crop_enable: crop is enable or disabled, if enabled * then remaining parameters are valid. + * @drop_enable: flag to indicate pixel drop enable or disable * @start_pixel: start pixel * @end_pixel: end_pixel * @width: width @@ -435,6 +438,7 @@ struct cam_ife_csid_path_cfg { uint32_t in_format; uint32_t out_format; bool crop_enable; + bool drop_enable; uint32_t start_pixel; uint32_t end_pixel; uint32_t width; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c index 0a80f1a51cf5..07d555b17009 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c @@ -5,27 +5,32 @@ #include #include "cam_ife_csid_lite17x.h" +#include "cam_ife_csid_lite480.h" #include "cam_ife_csid_core.h" #include "cam_ife_csid_dev.h" #define CAM_CSID_LITE_DRV_NAME "csid_lite" -static struct cam_ife_csid_hw_info cam_ife_csid_lite_hw_info = { +static struct cam_ife_csid_hw_info cam_ife_csid_lite_17x_hw_info = { .csid_reg = &cam_ife_csid_lite_17x_reg_offset, }; +static struct cam_ife_csid_hw_info cam_ife_csid_lite_480_hw_info = { + .csid_reg = &cam_ife_csid_lite_480_reg_offset, +}; + static const struct of_device_id cam_ife_csid_lite_dt_match[] = { { .compatible = "qcom,csid-lite170", - .data = &cam_ife_csid_lite_hw_info, + .data = &cam_ife_csid_lite_17x_hw_info, }, { .compatible = "qcom,csid-lite175", - .data = &cam_ife_csid_lite_hw_info, + .data = &cam_ife_csid_lite_17x_hw_info, }, { .compatible = "qcom,csid-lite480", - .data = &cam_ife_csid_lite_hw_info, + .data = &cam_ife_csid_lite_480_hw_info, }, {} }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h new file mode 100644 index 000000000000..ca4373b62814 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_LITE_480_H_ +#define _CAM_IFE_CSID_LITE_480_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x30, + .csid_rdi_irq_mask_addr = 0x34, + .csid_rdi_irq_clear_addr = 0x38, + .csid_rdi_irq_set_addr = 0x3c, + .csid_rdi_cfg0_addr = 0x200, + .csid_rdi_cfg1_addr = 0x204, + .csid_rdi_ctrl_addr = 0x208, + .csid_rdi_frm_drop_pattern_addr = 0x20c, + .csid_rdi_frm_drop_period_addr = 0x210, + .csid_rdi_irq_subsample_pattern_addr = 0x214, + .csid_rdi_irq_subsample_period_addr = 0x218, + .csid_rdi_rpp_hcrop_addr = 0x21c, + .csid_rdi_rpp_vcrop_addr = 0x220, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x224, + .csid_rdi_rpp_pix_drop_period_addr = 0x228, + .csid_rdi_rpp_line_drop_pattern_addr = 0x22c, + .csid_rdi_rpp_line_drop_period_addr = 0x230, + .csid_rdi_rst_strobes_addr = 0x240, + .csid_rdi_status_addr = 0x250, + .csid_rdi_misr_val0_addr = 0x254, + .csid_rdi_misr_val1_addr = 0x258, + .csid_rdi_misr_val2_addr = 0x25c, + .csid_rdi_misr_val3_addr = 0x260, + .csid_rdi_format_measure_cfg0_addr = 0x270, + .csid_rdi_format_measure_cfg1_addr = 0x274, + .csid_rdi_format_measure0_addr = 0x278, + .csid_rdi_format_measure1_addr = 0x27c, + .csid_rdi_format_measure2_addr = 0x280, + .csid_rdi_timestamp_curr0_sof_addr = 0x290, + .csid_rdi_timestamp_curr1_sof_addr = 0x294, + .csid_rdi_timestamp_prev0_sof_addr = 0x298, + .csid_rdi_timestamp_prev1_sof_addr = 0x29c, + .csid_rdi_timestamp_curr0_eof_addr = 0x2a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x2a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x2a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x2ac, + .csid_rdi_err_recovery_cfg0_addr = 0x2b0, + .csid_rdi_err_recovery_cfg1_addr = 0x2b4, + .csid_rdi_err_recovery_cfg2_addr = 0x2b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x2bc, + .csid_rdi_byte_cntr_ping_addr = 0x2e0, + .csid_rdi_byte_cntr_pong_addr = 0x2e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_err_recovery_cfg0_addr = 0x3b0, + .csid_rdi_err_recovery_cfg1_addr = 0x3b4, + .csid_rdi_err_recovery_cfg2_addr = 0x3b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x3bc, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_err_recovery_cfg0_addr = 0x4b0, + .csid_rdi_err_recovery_cfg1_addr = 0x4b4, + .csid_rdi_err_recovery_cfg2_addr = 0x4b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x4bc, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_3_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_err_recovery_cfg0_addr = 0x5b0, + .csid_rdi_err_recovery_cfg1_addr = 0x5b4, + .csid_rdi_err_recovery_cfg2_addr = 0x5b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x5bc, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_lite_480_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_lite_480_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_lite_480_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 4, + .minor_version = 8, + .version_incr = 0, + .num_rdis = 4, + .num_pix = 0, + .num_ppp = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .drop_v_en_shift_val = 4, + .drop_h_en_shift_val = 3, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_lite_480_reg_offset = { + .cmn_reg = &cam_ife_csid_lite_480_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_lite_480_csi2_reg_offset, + .ipp_reg = NULL, + .ppp_reg = NULL, + .rdi_reg = { + &cam_ife_csid_lite_480_rdi_0_reg_offset, + &cam_ife_csid_lite_480_rdi_1_reg_offset, + &cam_ife_csid_lite_480_rdi_2_reg_offset, + &cam_ife_csid_lite_480_rdi_3_reg_offset, + }, + .tpg_reg = &cam_ife_csid_lite_480_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_LITE480_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 247dfc5960fb..777dfdb5d145 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -115,6 +115,7 @@ struct cam_isp_in_port_generic_info { * reserve * @node_res : Reserved resource structure pointer * @crop_enable : Flag to indicate CSID crop enable + * @drop_enable : Flag to indicate CSID drop enable * */ struct cam_csid_hw_reserve_resource_args { @@ -127,6 +128,7 @@ struct cam_csid_hw_reserve_resource_args { uint32_t cid; struct cam_isp_resource_node *node_res; bool crop_enable; + bool drop_enable; }; /** -- GitLab From a52b95db19457a892f69c2df188065198a56720d Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Wed, 19 Jun 2019 16:53:51 +0530 Subject: [PATCH 016/410] msm: camera: cpas: QoS setting for IFE1 It corrects QoS value for IFE1. Change-Id: Iab70f9262cb275be575704206f09c820327564ab Signed-off-by: Abhilash Kumar --- drivers/cam_cpas/cpas_top/cpastop_v175_130.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h index fe6e274c5668..43c1068cc22c 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h @@ -387,7 +387,7 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x3248, /* SPECIFIC_IFE1_SAFELUT_LOW */ - .value = 0xF, + .value = 0xFFFFFFFF, }, .ubwc_ctl = { /* -- GitLab From 146826aa4158127367909d4fb83960622bdce422 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 29 May 2019 10:24:40 -0700 Subject: [PATCH 017/410] msm: camera: eeprom: Fix OOB condition for memory map count Fix OOB check for memory map count to access correct memory map. Change-Id: Ifa3d323103725e4df57e86295bb7567835654b71 Signed-off-by: Jigarkumar Zala --- drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index b211471adf00..c067ff08c3ae 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -435,7 +435,8 @@ static int32_t cam_eeprom_parse_memory_map( validate_size = sizeof(struct cam_cmd_unconditional_wait); if (remain_buf_len < validate_size || - *num_map >= MSM_EEPROM_MAX_MEM_MAP_CNT) { + *num_map >= (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { CAM_ERR(CAM_EEPROM, "not enough buffer"); return -EINVAL; } @@ -445,7 +446,9 @@ static int32_t cam_eeprom_parse_memory_map( if (i2c_random_wr->header.count == 0 || i2c_random_wr->header.count >= MSM_EEPROM_MAX_MEM_MAP_CNT || - (size_t)*num_map > U16_MAX - i2c_random_wr->header.count) { + (size_t)*num_map >= ((MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE) - + i2c_random_wr->header.count)) { CAM_ERR(CAM_EEPROM, "OOB Error"); return -EINVAL; } -- GitLab From 326d40f7f167ef23a0190d77aa7fb833924db9b2 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 18 Jun 2019 15:51:26 -0700 Subject: [PATCH 018/410] msm: camera: eeprom: Increase memory map count For write operation while read memory memptr should not need to increase as it leads to crash. This change removes that increase opertion. Also, increasing map count to support more data reading for eeprom. Change-Id: Ie71deb225c2513e7c18229d174a9a0e129fdd1f7 Signed-off-by: Jigarkumar Zala --- drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 1 - drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index c067ff08c3ae..c1320d97f644 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -70,7 +70,6 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, rc); return rc; } - memptr = block->mapdata + emap[j].mem.valid_size; } if (emap[j].pageen.valid_size) { diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h index 6bf08d11ed6a..41817e97eae1 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -30,7 +30,7 @@ #define PROPERTY_MAXSIZE 32 #define MSM_EEPROM_MEMORY_MAP_MAX_SIZE 80 -#define MSM_EEPROM_MAX_MEM_MAP_CNT 8 +#define MSM_EEPROM_MAX_MEM_MAP_CNT 100 #define MSM_EEPROM_MEM_MAP_PROPERTIES_CNT 8 enum cam_eeprom_state { -- GitLab From c952930533a5ed73de5b7dc76e9dd73ed9c56715 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Mon, 24 Jun 2019 16:48:27 -0700 Subject: [PATCH 019/410] msm: camera: isp: Add CSID binning Add support to configure CSID binning Change-Id: I09b76b287c243149c89cba958a786f7476c8addb Signed-off-by: Vishalsingh Hajeri --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 4 ++++ .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h | 2 ++ .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 8 ++++++++ .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h | 3 +++ .../isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h | 2 ++ .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 8 ++++++++ 6 files changed, 27 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index fac5c41aa1a4..75f157f0d5b8 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2147,6 +2147,8 @@ static int cam_ife_mgr_acquire_get_unified_structure_v0( port_info->dsp_mode = in->dsp_mode; port_info->hbi_cnt = in->hbi_cnt; port_info->cust_node = 0; + port_info->horizontal_bin = 0; + port_info->qcfa_bin = 0; port_info->num_out_res = in->num_out_res; port_info->data = kcalloc(in->num_out_res, @@ -2246,6 +2248,8 @@ static int cam_ife_mgr_acquire_get_unified_structure_v2( port_info->dsp_mode = in->dsp_mode; port_info->hbi_cnt = in->hbi_cnt; port_info->cust_node = in->cust_node; + port_info->horizontal_bin = in->horizontal_bin; + port_info->qcfa_bin = in->qcfa_bin; port_info->num_out_res = in->num_out_res; port_info->data = kcalloc(in->num_out_res, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h index f8eee4109b65..b545ccc2a246 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h @@ -50,6 +50,8 @@ static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_480_ipp_reg_offset = { /* configurations */ .pix_store_en_shift_val = 7, .early_eof_en_shift_val = 29, + .horizontal_bin_en_shift_val = 2, + .quad_cfa_bin_en_shift_val = 30, .ccif_violation_en = 1, .overflow_ctrl_en = 1, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index a41d203d4402..252c1a5aa36a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1016,6 +1016,8 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->end_line = reserve->in_port->line_stop; path_data->crop_enable = reserve->crop_enable; path_data->drop_enable = reserve->drop_enable; + path_data->horizontal_bin = reserve->in_port->horizontal_bin; + path_data->qcfa_bin = reserve->in_port->qcfa_bin; CAM_DBG(CAM_ISP, "Res id: %d height:%d line_start %d line_stop %d crop_en %d", @@ -1603,6 +1605,12 @@ static int cam_ife_csid_init_config_pxl_path( (path_data->drop_enable << csid_reg->cmn_reg->drop_v_en_shift_val); + if (path_data->horizontal_bin || path_data->qcfa_bin) { + val |= (1 << pxl_reg->horizontal_bin_en_shift_val); + if (path_data->qcfa_bin) + val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val); + } + val |= (1 << pxl_reg->pix_store_en_shift_val); cam_io_w_mb(val, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_cfg0_addr); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index a68c56188c5f..3e998858b596 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -133,6 +133,7 @@ struct cam_ife_csid_pxl_reg_offset { /* configuration */ uint32_t pix_store_en_shift_val; uint32_t early_eof_en_shift_val; + uint32_t horizontal_bin_en_shift_val; uint32_t quad_cfa_bin_en_shift_val; uint32_t ccif_violation_en; uint32_t overflow_ctrl_en; @@ -448,6 +449,8 @@ struct cam_ife_csid_path_cfg { enum cam_isp_hw_sync_mode sync_mode; uint32_t master_idx; uint64_t clk_rate; + uint32_t horizontal_bin; + uint32_t qcfa_bin; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 777dfdb5d145..d8ba811c7ad5 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -95,6 +95,8 @@ struct cam_isp_in_port_generic_info { uint32_t hbi_cnt; uint32_t cust_node; uint32_t num_out_res; + uint32_t horizontal_bin; + uint32_t qcfa_bin; struct cam_isp_out_port_generic_info *data; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index e4a05a1031b7..bbc25bc96045 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -49,6 +49,8 @@ struct cam_vfe_mux_camif_ver3_data { bool enable_sof_irq_debug; uint32_t irq_debug_cnt; uint32_t camif_debug; + uint32_t horizontal_bin; + uint32_t qcfa_bin; }; static int cam_vfe_camif_ver3_get_evt_payload( @@ -250,6 +252,9 @@ int cam_vfe_camif_ver3_acquire_resource( camif_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; camif_data->first_line = acquire_data->vfe_in.in_port->line_start; camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + camif_data->horizontal_bin = + acquire_data->vfe_in.in_port->horizontal_bin; + camif_data->qcfa_bin = acquire_data->vfe_in.in_port->qcfa_bin; camif_data->event_cb = acquire_data->event_cb; camif_data->priv = acquire_data->priv; @@ -441,6 +446,9 @@ static int cam_vfe_camif_ver3_resource_start( * frame width. We use '/ 4' instead of '/ 2' * cause it is multipixel path */ + if (rsrc_data->horizontal_bin || rsrc_data->qcfa_bin) + epoch0_line_cfg >>= 1; + epoch1_line_cfg = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; computed_epoch_line_cfg = (epoch1_line_cfg << 16) | -- GitLab From a0129f5975378d62be93617c5f85f94fb1702aa6 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Thu, 13 Jun 2019 06:16:03 +0530 Subject: [PATCH 020/410] msm: camera: icp: setting QoS for a5 firmware It sets the bus access priority for A5 core. Change-Id: Ic110bc10d14ea512f79dfff361e61db4e9db6fe7 Signed-off-by: Alok Pandey --- drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 9 +++++++++ drivers/cam_icp/icp_hw/a5_hw/a5_core.h | 2 ++ drivers/cam_icp/icp_hw/a5_hw/a5_soc.c | 7 +++++++ drivers/cam_icp/icp_hw/a5_hw/a5_soc.h | 1 + 4 files changed, 19 insertions(+) diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index baac5ff5976c..f7d94b2ce679 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -241,6 +241,7 @@ int cam_a5_init_hw(void *device_priv, struct cam_hw_info *a5_dev = device_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_a5_device_core_info *core_info = NULL; + struct a5_soc_info *a5_soc_info; struct cam_icp_cpas_vote cpas_vote; int rc = 0; @@ -258,6 +259,8 @@ int cam_a5_init_hw(void *device_priv, return -EINVAL; } + a5_soc_info = soc_info->soc_private; + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; cpas_vote.axi_vote.num_paths = 1; @@ -291,6 +294,12 @@ int cam_a5_init_hw(void *device_priv, CAM_ERR(CAM_ICP, "cpas stop is failed"); else core_info->cpas_start = false; + } else { + CAM_DBG(CAM_ICP, "a5_qos %d", a5_soc_info->a5_qos_val); + if (a5_soc_info->a5_qos_val) + cam_io_w_mb(a5_soc_info->a5_qos_val, + soc_info->reg_map[A5_SIERRA_BASE].mem_base + + ICP_SIERRA_A5_CSR_ACCESS); } error: diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.h b/drivers/cam_icp/icp_hw/a5_hw/a5_core.h index a5c0fffde1d1..6c46b3ac8784 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.h +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.h @@ -20,6 +20,8 @@ #define A5_WDT_0 0x2 #define A5_WDT_1 0x4 +#define ICP_SIERRA_A5_CSR_ACCESS 0x3C + #define ELF_GUARD_PAGE (2 * 1024 * 1024) struct cam_a5_device_hw_info { diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c index bcdc12632356..62a88ac87f67 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c @@ -40,6 +40,13 @@ static int cam_a5_get_dt_properties(struct cam_hw_soc_info *soc_info) goto end; } + rc = of_property_read_u32(of_node, "qos-val", + &a5_soc_info->a5_qos_val); + if (rc < 0) { + CAM_WARN(CAM_ICP, "QoS need not be set"); + a5_soc_info->a5_qos_val = 0; + } + ubwc_cfg_ext = &a5_soc_info->uconfig.ubwc_cfg_ext; num_ubwc_cfg = of_property_count_u32_elems(of_node, "ubwc-ipe-fetch-cfg"); diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h index eadf9d726696..c44bcde120fb 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h @@ -20,6 +20,7 @@ struct a5_ubwc_cfg_ext { struct a5_soc_info { char *fw_name; bool ubwc_config_ext; + uint32_t a5_qos_val; union { uint32_t ubwc_cfg[ICP_UBWC_MAX]; struct a5_ubwc_cfg_ext ubwc_cfg_ext; -- GitLab From f1135e91b97e2c28e84e389a83714e9a67070675 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Fri, 5 Jul 2019 13:10:11 -0700 Subject: [PATCH 021/410] msm: camara: sync: Add callback registration logic for synx Synx driver is dependent on camera driver for registering callback functions of sync driver. This change invert the logic, and camera driver will register the callback functions for synx driver at the time of sync driver probe. Change-Id: I2dbee15ba4c7a9dde336a4bb1f2a4dddcd90348b Signed-off-by: Jigarkumar Zala --- drivers/cam_sync/Makefile | 1 + drivers/cam_sync/cam_sync.c | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sync/Makefile b/drivers/cam_sync/Makefile index b0868f522549..e15ed0ce8931 100644 --- a/drivers/cam_sync/Makefile +++ b/drivers/cam_sync/Makefile @@ -2,6 +2,7 @@ ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-$(CONFIG_MSM_GLOBAL_SYNX) += -I$(srctree)/drivers/media/platform/msm/synx ccflags-y += -I$(src) obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync.o cam_sync_util.o diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 5342de04da8f..10ed0cdecebf 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -13,6 +13,9 @@ #include "cam_debug_util.h" #include "cam_common_util.h" +#ifdef CONFIG_MSM_GLOBAL_SYNX +#include +#endif struct sync_device *sync_dev; /* @@ -956,6 +959,25 @@ static int cam_sync_create_debugfs(void) return 0; } +#ifdef CONFIG_MSM_GLOBAL_SYNX +static void cam_sync_register_synx_bind_ops(void) +{ + int rc = 0; + struct synx_register_params params; + + params.name = CAM_SYNC_NAME; + params.type = SYNX_TYPE_CSL; + params.ops.register_callback = cam_sync_register_callback; + params.ops.deregister_callback = cam_sync_deregister_callback; + params.ops.enable_signaling = cam_sync_get_obj_ref; + params.ops.signal = cam_sync_signal; + + rc = synx_register_ops(¶ms); + if (rc) + CAM_ERR(CAM_SYNC, "synx registration fail with %d", rc); +} +#endif + static int cam_sync_probe(struct platform_device *pdev) { int rc; @@ -1023,7 +1045,9 @@ static int cam_sync_probe(struct platform_device *pdev) trigger_cb_without_switch = false; cam_sync_create_debugfs(); - +#ifdef CONFIG_MSM_GLOBAL_SYNX + cam_sync_register_synx_bind_ops(); +#endif return rc; v4l2_fail: -- GitLab From 4f13d6fe1f0ebb39d66a63091b152e6b182c6155 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Wed, 26 Jun 2019 16:33:51 -0700 Subject: [PATCH 022/410] msm: camera: cpas: Update SafeLut values in CAMNOC QoS settings for Kona Update SafeLut values for ife paths in CAMNOC QoS settings according to recommended settings in CAMNOC HPG. Change-Id: I12fa796757f4fe000e47ab2074c7ee88165864ab Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_cpas/cpas_top/cpastop_v480_100.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h index cbb521d30778..fcf25383ec66 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -317,7 +317,7 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0xA48, /* IFE_LINEAR_SAFELUT_LOW */ - .value = 0xFFF0, + .value = 0x000F, }, .ubwc_ctl = { /* @@ -407,7 +407,7 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1448, /* IFE_RDI_WR_SAFELUT_LOW */ - .value = 0xFFF0, + .value = 0x000F, }, .ubwc_ctl = { /* @@ -452,7 +452,7 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1A48, /* IFE_UBWC_STATS_SAFELUT_LOW */ - .value = 0xFFF0, + .value = 0x000F, }, .ubwc_ctl = { /* -- GitLab From 2f6c89b46f9b4a7cf130c11c1e15cd874c9171c4 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Thu, 27 Jun 2019 22:14:38 +0800 Subject: [PATCH 023/410] msm: camera: csid: add csiphy4 and csiphy5 support Add csiphy4 and csiphy5 support. Change-Id: I8523523556671ed6ffd7f880af2d18043c30d4eb Signed-off-by: Depeng Shao --- drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h | 2 +- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h index b545ccc2a246..cfa8e152b4c3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h @@ -291,7 +291,7 @@ static struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, - .csi2_rx_phy_num_mask = 0x3, + .csi2_rx_phy_num_mask = 0x7, }; static struct cam_ife_csid_csi2_tpg_reg_offset diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h index ca4373b62814..7d9a53567ee6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h @@ -247,7 +247,7 @@ static struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, - .csi2_rx_phy_num_mask = 0x3, + .csi2_rx_phy_num_mask = 0x7, }; static struct cam_ife_csid_csi2_tpg_reg_offset -- GitLab From 93e8362a07cb856193e61a7b953a29656afae521 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 11:57:38 -0700 Subject: [PATCH 024/410] msm: camera: cpas: Enable camnoc interrupts Enable camnoc interrupts to get notifications for UBWC encoder and decoder errors. Change-Id: Ie7d89dcaf4c81e9ce5af9f28e9a5e0a9cf3eeaa8 Signed-off-by: Suresh Vankadara Signed-off-by: Jigarkumar Zala --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 4 ++++ drivers/cam_cpas/cpas_top/cpastop_v175_130.h | 16 +++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 57eb9de92be4..33ee95888fd8 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -334,6 +334,9 @@ static int cam_cpastop_reset_irq(struct cam_hw_info *cpas_hw) { int i; + if (camnoc_info->irq_sbm->sbm_enable.enable == false) + return 0; + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, &camnoc_info->irq_sbm->sbm_clear); for (i = 0; i < camnoc_info->irq_err_size; i++) { @@ -508,6 +511,7 @@ static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) { int i; + cam_cpastop_reset_irq(cpas_hw); for (i = 0; i < camnoc_info->specific_size; i++) { if (camnoc_info->specific[i].enable) { cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h index 43c1068cc22c..2d3d96ea819a 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h @@ -67,18 +67,19 @@ static struct cam_camnoc_irq_err .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x3BA0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .offset = 0x3BA0, /* SPECIFIC_IFE0_MAIN_ENCERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x3B90, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + /* SPECIFIC_IFE0_MAIN_ENCERRSTATUS_LOW */ + .offset = 0x3B90, }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x3B98, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .offset = 0x3B98, /* SPECIFIC_IFE0_MAIN_ENCERRCLR_LOW */ .value = 1, }, }, @@ -89,18 +90,19 @@ static struct cam_camnoc_irq_err .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x55a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .offset = 0x55A0, /* SPECIFIC_IFE1_WR_ENCERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x5590, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + /* SPECIFIC_IFE1_WR_ENCERRSTATUS_LOW */ + .offset = 0x5590, }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x5598, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .offset = 0x5598, /* SPECIFIC_IFE1_WR_ENCERRCLR_LOW */ .value = 1, }, }, @@ -133,7 +135,7 @@ static struct cam_camnoc_irq_err .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x2Ba0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .offset = 0x2BA0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ .value = 1, }, .err_status = { -- GitLab From 13bec8b88ea7065788bf24f1aa29dc94aa784e14 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 11:58:49 -0700 Subject: [PATCH 025/410] Revert "msm: camera: ife: Stop tasklet after deinit" This reverts commit ff736fcb813649b3998fca3d732145f341235cf5. The above change was committed to prevent tasklet deinit before ISRs have completed execution due to erratic delays in tasklet scheduling on early builds which was not stable. As builds have stabilized now, we need to revert to normal driver behavior for stop sequence. Change-Id: I57127d3fe6fbbd5579241c1cfc978362ba302aef Signed-off-by: Venkat Chinta Signed-off-by: Jigarkumar Zala --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 75f157f0d5b8..473a274eaf5c 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -3334,19 +3334,17 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); } + cam_tasklet_stop(ctx->common.tasklet_info); + cam_ife_mgr_pause_hw(ctx); - if (stop_isp->stop_only) { - cam_tasklet_stop(ctx->common.tasklet_info); + if (stop_isp->stop_only) goto end; - } if (cam_cdm_stream_off(ctx->cdm_handle)) CAM_ERR(CAM_ISP, "CDM stream off failed %d", ctx->cdm_handle); cam_ife_hw_mgr_deinit_hw(ctx); - cam_tasklet_stop(ctx->common.tasklet_info); - CAM_DBG(CAM_ISP, "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); -- GitLab From b630768467b2ea046f1fe8db6c73e0c9696a92b7 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 11:59:44 -0700 Subject: [PATCH 026/410] msm: camera: icp: Add support for semi real time device types Add support for IPE/BPS semi real time device types. Change-Id: I1d9974eb796ce1723205072651d53ecb84023e88 Signed-off-by: Karthik Anantha Ram Signed-off-by: Vishalsingh Hajeri Signed-off-by: Jigarkumar Zala --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) 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 9cb19fae68c9..57a88f5a3070 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 @@ -5012,10 +5012,31 @@ static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, return 0; } +static uint32_t cam_icp_unify_dev_type( + uint32_t dev_type) +{ + switch (dev_type) { + case CAM_ICP_RES_TYPE_BPS: + return CAM_ICP_RES_TYPE_BPS; + case CAM_ICP_RES_TYPE_BPS_RT: + return CAM_ICP_RES_TYPE_BPS; + case CAM_ICP_RES_TYPE_BPS_SEMI_RT: + return CAM_ICP_RES_TYPE_BPS; + case CAM_ICP_RES_TYPE_IPE: + return CAM_ICP_RES_TYPE_IPE; + case CAM_ICP_RES_TYPE_IPE_RT: + return CAM_ICP_RES_TYPE_IPE; + case CAM_ICP_RES_TYPE_IPE_SEMI_RT: + return CAM_ICP_RES_TYPE_IPE; + default: + return CAM_ICP_RES_TYPE_MAX; + } +} + static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { int rc = 0, bitmap_size = 0; - uint32_t ctx_id = 0; + uint32_t ctx_id = 0, dev_type; uint64_t io_buf_addr; size_t io_buf_size; struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; @@ -5108,6 +5129,10 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) goto create_handle_failed; } + CAM_DBG(CAM_ICP, + "created stream handle for dev_type %u", + icp_dev_acquire_info->dev_type); + cmd_mem_region.num_regions = 1; cmd_mem_region.map_info_array[0].mem_handle = icp_dev_acquire_info->io_config_cmd_handle; @@ -5167,10 +5192,12 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) /* Start context timer*/ cam_icp_ctx_timer_start(ctx_data); hw_mgr->ctxt_cnt++; + dev_type = cam_icp_unify_dev_type(icp_dev_acquire_info->dev_type); + icp_dev_acquire_info->dev_type = dev_type; mutex_unlock(&hw_mgr->hw_mgr_mutex); - CAM_DBG(CAM_ICP, "Acquire Done for ctx_id %u dev name %s dev type %d", - ctx_data->ctx_id, cam_icp_dev_type_to_name( - icp_dev_acquire_info->dev_type), + + CAM_DBG(CAM_ICP, "Acquire Done for ctx_id %u dev type %d", + ctx_data->ctx_id, icp_dev_acquire_info->dev_type); return 0; -- GitLab From d707886ae1570d5b1eafe53151cbd8f756b1c7dd Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 12:03:32 -0700 Subject: [PATCH 027/410] msm: camera: isp: Move bw voting functions to common file for vfe Currently, vfe top has different files for different targets. Some of the APIs are unchanged between these files. In order to avoid duplication of code and make sure no change is missed between different versions of vfe top, a common file is added to vfe top for unchanged APIs. With the common top, number of input resources are moved to architecture specific header files to ensure special conditions need not be created for a particular architecture in common code. Move bw voting related APIs to this common file. Change-Id: Ibcb9519a206c25d42c9e7f0336f8d588a8240717 Signed-off-by: Mukund Madhusudan Atre Signed-off-by: Jigarkumar Zala --- .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 3 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 1 + .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 1 + .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 1 + .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h | 3 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h | 1 + .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile | 2 +- .../vfe_hw/vfe_top/cam_vfe_top_common.c | 373 ++++++++++++ .../vfe_hw/vfe_top/cam_vfe_top_common.h | 44 ++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 558 ++++-------------- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h | 6 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 549 ++++------------- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h | 6 +- 13 files changed, 646 insertions(+), 902 deletions(-) create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 748c324f5496..663bc247b27f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE170_H_ @@ -166,6 +166,7 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { NULL, }, }, + .num_mux = 4, .mux_type = { CAM_VFE_CAMIF_VER_2_0, CAM_VFE_RDI_VER_1_0, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index db61bfbdc84b..6823b6386b91 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -201,6 +201,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { NULL, }, }, + .num_mux = 5, .mux_type = { CAM_VFE_CAMIF_VER_2_0, CAM_VFE_RDI_VER_1_0, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 03a6409324d8..8acd77d1f1e2 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -254,6 +254,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { .fe_reg = &vfe175_130_fe_reg, .reg_data = &vfe_175_130_fe_reg_data, }, + .num_mux = 6, .mux_type = { CAM_VFE_CAMIF_VER_2_0, CAM_VFE_RDI_VER_1_0, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index 48eb7f1b028d..ae65df7c1126 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -304,6 +304,7 @@ static struct cam_vfe_top_ver3_hw_info vfe480_top_hw_info = { .camif_lite_reg = &vfe480_camif_lcr, .reg_data = &vfe480_camif_lcr_reg_data, }, + .num_mux = 6, .mux_type = { CAM_VFE_CAMIF_VER_3_0, CAM_VFE_RDI_VER_1_0, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h index 0c94b63be2e0..f356d6c24b20 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_LITE17X_H_ @@ -97,6 +97,7 @@ static struct cam_vfe_top_ver2_hw_info vfe17x_top_hw_info = { &vfe17x_rdi_3_data, }, }, + .num_mux = 4, .mux_type = { CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h index 221c372f72b1..c19ade50bec9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h @@ -199,6 +199,7 @@ static struct cam_vfe_top_ver3_hw_info vfe48x_top_hw_info = { .rdi_hw_info[1] = &vfe48x_rdi_hw_info[1], .rdi_hw_info[2] = &vfe48x_rdi_hw_info[2], .rdi_hw_info[3] = &vfe48x_rdi_hw_info[3], + .num_mux = 4, .mux_type = { CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile index 0ed6a870efa9..2ab4651e4271 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -13,6 +13,6 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw -obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_lite_ver2.o cam_vfe_top.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_lite_ver2.o cam_vfe_top.o cam_vfe_top_common.o obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top_ver3.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_ver3.o cam_vfe_rdi.o cam_vfe_fe_ver1.o cam_vfe_camif_lite_ver3.o diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c new file mode 100644 index 000000000000..2eae53205c8c --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_vfe_top_common.h" +#include "cam_debug_util.h" + +static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction( + struct cam_vfe_top_priv_common *top_common, + uint64_t *to_be_applied_bw) +{ + uint32_t i, j; + int vote_idx = -1; + uint64_t max_bw = 0; + uint64_t total_bw; + struct cam_axi_vote *curr_l_vote; + + for (i = 0; i < CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES; i++) { + total_bw = 0; + curr_l_vote = &top_common->last_vote[i]; + for (j = 0; j < curr_l_vote->num_paths; j++) { + if (total_bw > + (U64_MAX - + curr_l_vote->axi_path[j].camnoc_bw)) { + CAM_ERR(CAM_PERF, + "ife[%d] : Integer overflow at hist idx: %d, path: %d, total_bw = %llu, camnoc_bw = %llu", + top_common->hw_idx, i, j, total_bw, + curr_l_vote->axi_path[j].camnoc_bw); + return NULL; + } + + total_bw += curr_l_vote->axi_path[j].camnoc_bw; + } + + if (total_bw > max_bw) { + vote_idx = i; + max_bw = total_bw; + } + } + + if (vote_idx < 0) + return NULL; + + *to_be_applied_bw = max_bw; + + return &top_common->last_vote[vote_idx]; +} + +int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, bool start_stop) +{ + struct cam_axi_vote agg_vote = {0}; + struct cam_axi_vote *to_be_applied_axi_vote = NULL; + int rc = 0; + uint32_t i; + uint32_t num_paths = 0; + uint64_t total_bw_new_vote = 0; + bool bw_unchanged = true; + bool apply_bw_update = false; + + for (i = 0; i < top_common->num_mux; i++) { + if (top_common->axi_vote_control[i] == + CAM_VFE_BW_CONTROL_INCLUDE) { + if (num_paths + + top_common->req_axi_vote[i].num_paths > + CAM_CPAS_MAX_PATHS_PER_CLIENT) { + CAM_ERR(CAM_PERF, + "Required paths(%d) more than max(%d)", + num_paths + + top_common->req_axi_vote[i].num_paths, + CAM_CPAS_MAX_PATHS_PER_CLIENT); + return -EINVAL; + } + + memcpy(&agg_vote.axi_path[num_paths], + &top_common->req_axi_vote[i].axi_path[0], + top_common->req_axi_vote[i].num_paths * + sizeof( + struct cam_axi_per_path_bw_vote)); + num_paths += top_common->req_axi_vote[i].num_paths; + } + } + + agg_vote.num_paths = num_paths; + + for (i = 0; i < agg_vote.num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]", + top_common->hw_idx, + top_common->last_counter, + cam_cpas_axi_util_path_type_to_string( + agg_vote.axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + agg_vote.axi_path[i].transac_type), + agg_vote.axi_path[i].camnoc_bw, + agg_vote.axi_path[i].mnoc_ab_bw, + agg_vote.axi_path[i].mnoc_ib_bw); + + total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; + } + + memcpy(&top_common->last_vote[top_common->last_counter], &agg_vote, + sizeof(struct cam_axi_vote)); + top_common->last_counter = (top_common->last_counter + 1) % + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES; + + if ((agg_vote.num_paths != top_common->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_common->total_bw_applied)) + bw_unchanged = false; + + CAM_DBG(CAM_PERF, + "ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d", + top_common->hw_idx, top_common->total_bw_applied, + total_bw_new_vote, bw_unchanged, start_stop); + + if (bw_unchanged) { + CAM_DBG(CAM_PERF, "BW config unchanged"); + return 0; + } + + if (start_stop) { + /* need to vote current request immediately */ + to_be_applied_axi_vote = &agg_vote; + /* Reset everything, we can start afresh */ + memset(top_common->last_vote, 0x0, sizeof(struct cam_axi_vote) * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); + top_common->last_counter = 0; + top_common->last_vote[top_common->last_counter] = agg_vote; + top_common->last_counter = (top_common->last_counter + 1) % + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES; + } else { + /* + * Find max bw request in last few frames. This will the bw + * that we want to vote to CPAS now. + */ + to_be_applied_axi_vote = + cam_vfe_top_delay_bw_reduction(top_common, + &total_bw_new_vote); + if (!to_be_applied_axi_vote) { + CAM_ERR(CAM_PERF, "to_be_applied_axi_vote is NULL"); + return -EINVAL; + } + } + + for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]", + top_common->hw_idx, + cam_cpas_axi_util_path_type_to_string( + to_be_applied_axi_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + to_be_applied_axi_vote->axi_path[i].transac_type), + to_be_applied_axi_vote->axi_path[i].camnoc_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw); + } + + if ((to_be_applied_axi_vote->num_paths != + top_common->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_common->total_bw_applied)) + apply_bw_update = true; + + CAM_DBG(CAM_PERF, + "ife[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d", + top_common->hw_idx, top_common->total_bw_applied, + total_bw_new_vote, apply_bw_update, start_stop); + + if (apply_bw_update) { + rc = cam_cpas_update_axi_vote(soc_private->cpas_handle, + to_be_applied_axi_vote); + if (!rc) { + memcpy(&top_common->applied_axi_vote, + to_be_applied_axi_vote, + sizeof(struct cam_axi_vote)); + top_common->total_bw_applied = total_bw_new_vote; + } else { + CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc); + } + } + + return rc; +} + +int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bw_update_args_v2 *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_update = (struct cam_vfe_bw_update_args_v2 *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_common->num_mux; i++) { + if (top_common->mux_rsrc[i].res_id == res->res_id) { + memcpy(&top_common->req_axi_vote[i], + &bw_update->isp_vote, + sizeof(struct cam_axi_vote)); + top_common->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_PERF, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common, + false); + } + + return rc; +} + +int cam_vfe_top_bw_update(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bw_update_args *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + struct cam_axi_vote *mux_axi_vote; + bool vid_exists = false; + bool rdi_exists = false; + + bw_update = (struct cam_vfe_bw_update_args *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + CAM_DBG(CAM_PERF, "res_id=%d, BW=[%lld %lld]", + res->res_id, bw_update->camnoc_bw_bytes, + bw_update->external_bw_bytes); + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_common->num_mux; i++) { + mux_axi_vote = &top_common->req_axi_vote[i]; + if (top_common->mux_rsrc[i].res_id == res->res_id) { + mux_axi_vote->num_paths = 1; + if ((res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && + (res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) { + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_RDI0 + + (res->res_id - CAM_ISP_HW_VFE_IN_RDI0); + } else { + /* + * Vote all bw into VIDEO path as we cannot + * differentiate to which path this has to go + */ + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; + } + + mux_axi_vote->axi_path[0].transac_type = + CAM_AXI_TRANSACTION_WRITE; + mux_axi_vote->axi_path[0].camnoc_bw = + bw_update->camnoc_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ib_bw = + bw_update->external_bw_bytes; + /* Make ddr bw same as mnoc bw */ + mux_axi_vote->axi_path[0].ddr_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].ddr_ib_bw = + bw_update->external_bw_bytes; + + top_common->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + + if (mux_axi_vote->num_paths == 1) { + if (mux_axi_vote->axi_path[0].path_data_type == + CAM_AXI_PATH_DATA_IFE_VID) + vid_exists = true; + else if ((mux_axi_vote->axi_path[0].path_data_type >= + CAM_AXI_PATH_DATA_IFE_RDI0) && + (mux_axi_vote->axi_path[0].path_data_type <= + CAM_AXI_PATH_DATA_IFE_RDI3)) + rdi_exists = true; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_PERF, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common, + false); + } + + return rc; +} + +int cam_vfe_top_bw_control(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bw_control_args *bw_ctrl = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args; + res = bw_ctrl->node_res; + + if (!res || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_common->num_mux; i++) { + if (top_common->mux_rsrc[i].res_id == res->res_id) { + top_common->axi_vote_control[i] = bw_ctrl->action; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_PERF, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common, true); + } + + return rc; +} diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h new file mode 100644 index 000000000000..03be713e6068 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_COMMON_H_ +#define _CAM_VFE_TOP_COMMON_H_ + +#define CAM_VFE_TOP_MUX_MAX 6 +#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 18 + +#include "cam_cpas_api.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" + +struct cam_vfe_top_priv_common { + struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_MUX_MAX]; + uint32_t num_mux; + uint32_t hw_idx; + struct cam_axi_vote applied_axi_vote; + struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_MUX_MAX]; + struct cam_axi_vote last_vote[ + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; + uint32_t last_counter; + uint64_t total_bw_applied; + enum cam_vfe_bw_control_action axi_vote_control[CAM_VFE_TOP_MUX_MAX]; +}; + +int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, bool start_stop); + +int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size); + +int cam_vfe_top_bw_update(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size); + +int cam_vfe_top_bw_control(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size); + +#endif /* _CAM_VFE_TOP_COMMON_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 78a72eb6846a..e057b15aee43 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -10,12 +10,10 @@ #include "cam_vfe_top.h" #include "cam_vfe_top_ver2.h" #include "cam_debug_util.h" -#include "cam_cpas_api.h" #include "cam_vfe_soc.h" #define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00003F9F #define CAM_VFE_HW_RESET_HW_VAL 0x00003F87 -#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 3 struct cam_vfe_top_ver2_common_data { struct cam_hw_soc_info *soc_info; @@ -25,17 +23,10 @@ struct cam_vfe_top_ver2_common_data { struct cam_vfe_top_ver2_priv { struct cam_vfe_top_ver2_common_data common_data; - struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX]; unsigned long hw_clk_rate; - struct cam_axi_vote applied_axi_vote; - struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX]; - unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX]; - struct cam_axi_vote last_vote[CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; - uint32_t last_counter; - uint64_t total_bw_applied; - enum cam_vfe_bw_control_action - axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX]; + unsigned long req_clk_rate[ + CAM_VFE_TOP_MUX_MAX]; + struct cam_vfe_top_priv_common top_common; }; static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv, @@ -94,14 +85,14 @@ static int cam_vfe_top_set_hw_clk_rate( soc_info = top_priv->common_data.soc_info; - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { if (top_priv->req_clk_rate[i] > max_clk_rate) max_clk_rate = top_priv->req_clk_rate[i]; } if (max_clk_rate == top_priv->hw_clk_rate) return 0; - CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%llu", + CAM_DBG(CAM_PERF, "VFE: Clock name=%s idx=%d clk=%llu", soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); @@ -110,196 +101,7 @@ static int cam_vfe_top_set_hw_clk_rate( if (!rc) top_priv->hw_clk_rate = max_clk_rate; else - CAM_ERR(CAM_ISP, "Set Clock rate failed, rc=%d", rc); - - return rc; -} - -static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction( - struct cam_vfe_top_ver2_priv *top_priv, - uint64_t *to_be_applied_bw) -{ - uint32_t i, j; - int vote_idx = -1; - uint64_t max_bw = 0; - uint64_t total_bw; - struct cam_axi_vote *curr_l_vote; - - for (i = 0; i < (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { - total_bw = 0; - curr_l_vote = &top_priv->last_vote[i]; - for (j = 0; j < curr_l_vote->num_paths; j++) { - if (total_bw > - (U64_MAX - - curr_l_vote->axi_path[j].camnoc_bw)) { - CAM_ERR(CAM_ISP, "Overflow at idx: %d", j); - return NULL; - } - - total_bw += curr_l_vote->axi_path[j].camnoc_bw; - } - - if (total_bw > max_bw) { - vote_idx = i; - max_bw = total_bw; - } - } - - if (vote_idx < 0) - return NULL; - - *to_be_applied_bw = max_bw; - - return &top_priv->last_vote[vote_idx]; -} - -static int cam_vfe_top_set_axi_bw_vote( - struct cam_vfe_top_ver2_priv *top_priv, - bool start_stop) -{ - struct cam_axi_vote agg_vote = {0}; - struct cam_axi_vote *to_be_applied_axi_vote = NULL; - int rc = 0; - uint32_t i; - uint32_t num_paths = 0; - uint64_t total_bw_new_vote = 0; - bool bw_unchanged = true; - struct cam_hw_soc_info *soc_info = - top_priv->common_data.soc_info; - struct cam_vfe_soc_private *soc_private = - soc_info->soc_private; - bool apply_bw_update = false; - - if (!soc_private) { - CAM_ERR(CAM_ISP, "Error soc_private NULL"); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - if (top_priv->axi_vote_control[i] == - CAM_VFE_BW_CONTROL_INCLUDE) { - if (num_paths + - top_priv->req_axi_vote[i].num_paths > - CAM_CPAS_MAX_PATHS_PER_CLIENT) { - CAM_ERR(CAM_ISP, - "Required paths(%d) more than max(%d)", - num_paths + - top_priv->req_axi_vote[i].num_paths, - CAM_CPAS_MAX_PATHS_PER_CLIENT); - return -EINVAL; - } - - memcpy(&agg_vote.axi_path[num_paths], - &top_priv->req_axi_vote[i].axi_path[0], - top_priv->req_axi_vote[i].num_paths * - sizeof( - struct cam_axi_per_path_bw_vote)); - num_paths += top_priv->req_axi_vote[i].num_paths; - } - } - - agg_vote.num_paths = num_paths; - - for (i = 0; i < agg_vote.num_paths; i++) { - CAM_DBG(CAM_PERF, - "ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]", - top_priv->common_data.hw_intf->hw_idx, - top_priv->last_counter, - cam_cpas_axi_util_path_type_to_string( - agg_vote.axi_path[i].path_data_type), - cam_cpas_axi_util_trans_type_to_string( - agg_vote.axi_path[i].transac_type), - agg_vote.axi_path[i].camnoc_bw, - agg_vote.axi_path[i].mnoc_ab_bw, - agg_vote.axi_path[i].mnoc_ib_bw); - - total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; - } - - memcpy(&top_priv->last_vote[top_priv->last_counter], &agg_vote, - sizeof(struct cam_axi_vote)); - top_priv->last_counter = (top_priv->last_counter + 1) % - (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - - if ((agg_vote.num_paths != top_priv->applied_axi_vote.num_paths) || - (total_bw_new_vote != top_priv->total_bw_applied)) - bw_unchanged = false; - - CAM_DBG(CAM_PERF, - "ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d", - top_priv->common_data.hw_intf->hw_idx, - top_priv->total_bw_applied, total_bw_new_vote, - bw_unchanged, start_stop); - - if (bw_unchanged) { - CAM_DBG(CAM_ISP, "BW config unchanged"); - return 0; - } - - if (start_stop) { - /* need to vote current request immediately */ - to_be_applied_axi_vote = &agg_vote; - /* Reset everything, we can start afresh */ - memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * - (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); - top_priv->last_counter = 0; - top_priv->last_vote[top_priv->last_counter] = agg_vote; - top_priv->last_counter = (top_priv->last_counter + 1) % - (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - } else { - /* - * Find max bw request in last few frames. This will the bw - * that we want to vote to CPAS now. - */ - to_be_applied_axi_vote = - cam_vfe_top_delay_bw_reduction(top_priv, - &total_bw_new_vote); - if (!to_be_applied_axi_vote) { - CAM_ERR(CAM_ISP, "to_be_applied_axi_vote is NULL"); - return -EINVAL; - } - } - - for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) { - CAM_DBG(CAM_PERF, - "ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]", - top_priv->common_data.hw_intf->hw_idx, - cam_cpas_axi_util_path_type_to_string( - to_be_applied_axi_vote->axi_path[i].path_data_type), - cam_cpas_axi_util_trans_type_to_string( - to_be_applied_axi_vote->axi_path[i].transac_type), - to_be_applied_axi_vote->axi_path[i].camnoc_bw, - to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw, - to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw); - } - - if ((to_be_applied_axi_vote->num_paths != - top_priv->applied_axi_vote.num_paths) || - (total_bw_new_vote != top_priv->total_bw_applied)) - apply_bw_update = true; - - CAM_DBG(CAM_PERF, - "ife[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d", - top_priv->common_data.hw_intf->hw_idx, - top_priv->total_bw_applied, total_bw_new_vote, - apply_bw_update, start_stop); - - if (apply_bw_update) { - rc = cam_cpas_update_axi_vote(soc_private->cpas_handle, - to_be_applied_axi_vote); - if (!rc) { - memcpy(&top_priv->applied_axi_vote, - to_be_applied_axi_vote, - sizeof(struct cam_axi_vote)); - top_priv->total_bw_applied = total_bw_new_vote; - } else { - CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); - } - } + CAM_ERR(CAM_PERF, "Set Clock rate failed, rc=%d", rc); return rc; } @@ -331,7 +133,7 @@ static int cam_vfe_top_clock_update( res = clk_update->node_res; if (!res || !res->hw_intf->hw_priv) { - CAM_ERR(CAM_ISP, "Invalid input res %pK", res); + CAM_ERR(CAM_PERF, "Invalid input res %pK", res); return -EINVAL; } @@ -339,21 +141,21 @@ static int cam_vfe_top_clock_update( if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + CAM_ERR(CAM_PERF, "VFE:%d Invalid res_type:%d res id%d", res->hw_intf->hw_idx, res->res_type, res->res_id); return -EINVAL; } - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == res->res_id) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == res->res_id) { top_priv->req_clk_rate[i] = clk_update->clk_rate; break; } } if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "VFE:%d Not ready to set clocks yet :%d", res->hw_intf->hw_idx, hw_info->hw_state); @@ -363,193 +165,6 @@ static int cam_vfe_top_clock_update( return rc; } -static int cam_vfe_top_bw_update_v2( - struct cam_vfe_top_ver2_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_vfe_bw_update_args_v2 *bw_update = NULL; - struct cam_isp_resource_node *res = NULL; - struct cam_hw_info *hw_info = NULL; - int rc = 0; - int i; - - bw_update = (struct cam_vfe_bw_update_args_v2 *)cmd_args; - res = bw_update->node_res; - - if (!res || !res->hw_intf || !res->hw_intf->hw_priv) - return -EINVAL; - - hw_info = res->hw_intf->hw_priv; - - if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || - res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", - res->hw_intf->hw_idx, res->res_type, - res->res_id); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == res->res_id) { - memcpy(&top_priv->req_axi_vote[i], &bw_update->isp_vote, - sizeof(struct cam_axi_vote)); - top_priv->axi_vote_control[i] = - CAM_VFE_BW_CONTROL_INCLUDE; - break; - } - } - - if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "VFE:%d Not ready to set BW yet :%d", - res->hw_intf->hw_idx, - hw_info->hw_state); - } else { - rc = cam_vfe_top_set_axi_bw_vote(top_priv, false); - } - - return rc; -} - -static int cam_vfe_top_bw_update( - struct cam_vfe_top_ver2_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_vfe_bw_update_args *bw_update = NULL; - struct cam_isp_resource_node *res = NULL; - struct cam_hw_info *hw_info = NULL; - int rc = 0; - int i; - struct cam_axi_vote *mux_axi_vote; - bool vid_exists = false; - bool rdi_exists = false; - - bw_update = (struct cam_vfe_bw_update_args *)cmd_args; - res = bw_update->node_res; - - if (!res || !res->hw_intf || !res->hw_intf->hw_priv) - return -EINVAL; - - hw_info = res->hw_intf->hw_priv; - - CAM_DBG(CAM_ISP, "res_id=%d, BW=[%lld %lld]", - res->res_id, bw_update->camnoc_bw_bytes, - bw_update->external_bw_bytes); - - if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || - res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", - res->hw_intf->hw_idx, res->res_type, - res->res_id); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - mux_axi_vote = &top_priv->req_axi_vote[i]; - if (top_priv->mux_rsrc[i].res_id == res->res_id) { - mux_axi_vote->num_paths = 1; - if ((res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && - (res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) { - mux_axi_vote->axi_path[0].path_data_type = - CAM_AXI_PATH_DATA_IFE_RDI0 + - (res->res_id - CAM_ISP_HW_VFE_IN_RDI0); - } else { - /* - * Vote all bw into VIDEO path as we cannot - * differentiate to which path this has to go - */ - mux_axi_vote->axi_path[0].path_data_type = - CAM_AXI_PATH_DATA_IFE_VID; - } - - mux_axi_vote->axi_path[0].transac_type = - CAM_AXI_TRANSACTION_WRITE; - mux_axi_vote->axi_path[0].camnoc_bw = - bw_update->camnoc_bw_bytes; - mux_axi_vote->axi_path[0].mnoc_ab_bw = - bw_update->external_bw_bytes; - mux_axi_vote->axi_path[0].mnoc_ib_bw = - bw_update->external_bw_bytes; - /* Make ddr bw same as mnoc bw */ - mux_axi_vote->axi_path[0].ddr_ab_bw = - bw_update->external_bw_bytes; - mux_axi_vote->axi_path[0].ddr_ib_bw = - bw_update->external_bw_bytes; - - top_priv->axi_vote_control[i] = - CAM_VFE_BW_CONTROL_INCLUDE; - break; - } - - if (mux_axi_vote->num_paths == 1) { - if (mux_axi_vote->axi_path[0].path_data_type == - CAM_AXI_PATH_DATA_IFE_VID) - vid_exists = true; - else if ((mux_axi_vote->axi_path[0].path_data_type >= - CAM_AXI_PATH_DATA_IFE_RDI0) && - (mux_axi_vote->axi_path[0].path_data_type <= - CAM_AXI_PATH_DATA_IFE_RDI3)) - rdi_exists = true; - } - } - - if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "VFE:%d Not ready to set BW yet :%d", - res->hw_intf->hw_idx, - hw_info->hw_state); - } else { - rc = cam_vfe_top_set_axi_bw_vote(top_priv, false); - } - - return rc; -} - -static int cam_vfe_top_bw_control( - struct cam_vfe_top_ver2_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_vfe_bw_control_args *bw_ctrl = NULL; - struct cam_isp_resource_node *res = NULL; - struct cam_hw_info *hw_info = NULL; - int rc = 0; - int i; - - bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args; - res = bw_ctrl->node_res; - - if (!res || !res->hw_intf->hw_priv) - return -EINVAL; - - hw_info = res->hw_intf->hw_priv; - - if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || - res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", - res->hw_intf->hw_idx, res->res_type, - res->res_id); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == res->res_id) { - top_priv->axi_vote_control[i] = bw_ctrl->action; - break; - } - } - - if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "VFE:%d Not ready to set BW yet :%d", - res->hw_intf->hw_idx, - hw_info->hw_state); - } else { - rc = cam_vfe_top_set_axi_bw_vote(top_priv, true); - } - - return rc; -} - static int cam_vfe_top_mux_get_reg_update( struct cam_vfe_top_ver2_priv *top_priv, void *cmd_args, uint32_t arg_size) @@ -638,14 +253,15 @@ int cam_vfe_top_reserve(void *device_priv, acquire_args = &args->vfe_in; - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == acquire_args->res_id && - top_priv->mux_rsrc[i].res_state == + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + acquire_args->res_id && + top_priv->top_common.mux_rsrc[i].res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { rc = cam_vfe_camif_ver2_acquire_resource( - &top_priv->mux_rsrc[i], + &top_priv->top_common.mux_rsrc[i], args); if (rc) break; @@ -654,7 +270,7 @@ int cam_vfe_top_reserve(void *device_priv, if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_PDLIB) { rc = cam_vfe_camif_lite_ver2_acquire_resource( - &top_priv->mux_rsrc[i], + &top_priv->top_common.mux_rsrc[i], args); if (rc) break; @@ -662,18 +278,20 @@ int cam_vfe_top_reserve(void *device_priv, if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { rc = cam_vfe_fe_ver1_acquire_resource( - &top_priv->mux_rsrc[i], + &top_priv->top_common.mux_rsrc[i], args); if (rc) break; } - top_priv->mux_rsrc[i].cdm_ops = acquire_args->cdm_ops; - top_priv->mux_rsrc[i].tasklet_info = args->tasklet; - top_priv->mux_rsrc[i].res_state = + top_priv->top_common.mux_rsrc[i].cdm_ops = + acquire_args->cdm_ops; + top_priv->top_common.mux_rsrc[i].tasklet_info = + args->tasklet; + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_RESERVED; acquire_args->rsrc_node = - &top_priv->mux_rsrc[i]; + &top_priv->top_common.mux_rsrc[i]; rc = 0; break; @@ -715,6 +333,8 @@ int cam_vfe_top_start(void *device_priv, struct cam_vfe_top_ver2_priv *top_priv; struct cam_isp_resource_node *mux_res; struct cam_hw_info *hw_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; int rc = 0; if (!device_priv || !start_args) { @@ -723,6 +343,13 @@ int cam_vfe_top_start(void *device_priv, } top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + mux_res = (struct cam_isp_resource_node *)start_args; hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; @@ -734,7 +361,8 @@ int cam_vfe_top_start(void *device_priv, return rc; } - rc = cam_vfe_top_set_axi_bw_vote(top_priv, true); + rc = cam_vfe_top_set_axi_bw_vote(soc_private, + &top_priv->top_common, true); if (rc) { CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc); @@ -785,17 +413,18 @@ int cam_vfe_top_stop(void *device_priv, } if (!rc) { - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == mux_res->res_id) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + mux_res->res_id) { top_priv->req_clk_rate[i] = 0; top_priv->req_clk_rate[i] = 0; - top_priv->req_axi_vote[i].axi_path[0].camnoc_bw - = 0; - top_priv->req_axi_vote[i].axi_path[0].mnoc_ab_bw - = 0; - top_priv->req_axi_vote[i].axi_path[0].mnoc_ib_bw - = 0; - top_priv->axi_vote_control[i] = + top_priv->top_common.req_axi_vote[i] + .axi_path[0].camnoc_bw = 0; + top_priv->top_common.req_axi_vote[i] + .axi_path[0].mnoc_ab_bw = 0; + top_priv->top_common.req_axi_vote[i] + .axi_path[0].mnoc_ib_bw = 0; + top_priv->top_common.axi_vote_control[i] = CAM_VFE_BW_CONTROL_EXCLUDE; break; } @@ -822,12 +451,20 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, { int rc = 0; struct cam_vfe_top_ver2_priv *top_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; if (!device_priv || !cmd_args) { CAM_ERR(CAM_ISP, "Error! Invalid arguments"); return -EINVAL; } top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } switch (cmd_type) { case CAM_ISP_HW_CMD_GET_CHANGE_BASE: @@ -846,15 +483,16 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, arg_size); break; case CAM_ISP_HW_CMD_BW_UPDATE: - rc = cam_vfe_top_bw_update(top_priv, cmd_args, - arg_size); + rc = cam_vfe_top_bw_update(soc_private, &top_priv->top_common, + cmd_args, arg_size); break; case CAM_ISP_HW_CMD_BW_UPDATE_V2: - rc = cam_vfe_top_bw_update_v2(top_priv, cmd_args, - arg_size); + rc = cam_vfe_top_bw_update_v2(soc_private, + &top_priv->top_common, cmd_args, arg_size); break; case CAM_ISP_HW_CMD_BW_CONTROL: - rc = cam_vfe_top_bw_control(top_priv, cmd_args, arg_size); + rc = cam_vfe_top_bw_control(soc_private, &top_priv->top_common, + cmd_args, arg_size); break; default: rc = -EINVAL; @@ -891,56 +529,69 @@ int cam_vfe_top_ver2_init( rc = -ENOMEM; goto free_vfe_top; } + vfe_top->top_priv = top_priv; top_priv->hw_clk_rate = 0; + if (ver2_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) { + CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d", + ver2_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX); + rc = -EINVAL; + goto free_top_priv; + } + + top_priv->top_common.num_mux = ver2_hw_info->num_mux; - for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN; - top_priv->mux_rsrc[i].hw_intf = hw_intf; - top_priv->mux_rsrc[i].res_state = + for (i = 0, j = 0; i < top_priv->top_common.num_mux; i++) { + top_priv->top_common.mux_rsrc[i].res_type = + CAM_ISP_RESOURCE_VFE_IN; + top_priv->top_common.mux_rsrc[i].hw_intf = hw_intf; + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; top_priv->req_clk_rate[i] = 0; if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_CAMIF; rc = cam_vfe_camif_ver2_init(hw_intf, soc_info, &ver2_hw_info->camif_hw_info, - &top_priv->mux_rsrc[i], vfe_irq_controller); + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); if (rc) goto deinit_resources; } else if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_LITE_VER_2_0) { - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_PDLIB; rc = cam_vfe_camif_lite_ver2_init(hw_intf, soc_info, &ver2_hw_info->camif_lite_hw_info, - &top_priv->mux_rsrc[i], vfe_irq_controller); + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); if (rc) goto deinit_resources; } else if (ver2_hw_info->mux_type[i] == CAM_VFE_RDI_VER_1_0) { /* set the RDI resource id */ - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_RDI0 + j++; rc = cam_vfe_rdi_ver2_init(hw_intf, soc_info, &ver2_hw_info->rdi_hw_info, - &top_priv->mux_rsrc[i], vfe_irq_controller); + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); if (rc) goto deinit_resources; } else if (ver2_hw_info->mux_type[i] == CAM_VFE_IN_RD_VER_1_0) { /* set the RD resource id */ - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_RD; rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, &ver2_hw_info->fe_hw_info, - &top_priv->mux_rsrc[i]); + &top_priv->top_common.mux_rsrc[i]); if (rc) goto deinit_resources; } else { @@ -963,6 +614,7 @@ int cam_vfe_top_ver2_init( top_priv->common_data.soc_info = soc_info; top_priv->common_data.hw_intf = hw_intf; + top_priv->top_common.hw_idx = hw_intf->hw_idx; top_priv->common_data.common_reg = ver2_hw_info->common_reg; return rc; @@ -970,26 +622,30 @@ int cam_vfe_top_ver2_init( deinit_resources: for (--i; i >= 0; i--) { if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { - if (cam_vfe_camif_ver2_deinit(&top_priv->mux_rsrc[i])) + if (cam_vfe_camif_ver2_deinit( + &top_priv->top_common.mux_rsrc[i])) CAM_ERR(CAM_ISP, "Camif Deinit failed"); } else if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_LITE_VER_2_0) { if (cam_vfe_camif_lite_ver2_deinit( - &top_priv->mux_rsrc[i])) + &top_priv->top_common.mux_rsrc[i])) CAM_ERR(CAM_ISP, "Camif lite deinit failed"); } else if (ver2_hw_info->mux_type[i] == CAM_VFE_IN_RD_VER_1_0) { - if (cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i])) + if (cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i])) CAM_ERR(CAM_ISP, "VFE FE deinit failed"); } else { - if (cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i])) + if (cam_vfe_rdi_ver2_deinit( + &top_priv->top_common.mux_rsrc[i])) CAM_ERR(CAM_ISP, "RDI Deinit failed"); } - top_priv->mux_rsrc[i].res_state = + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; } - kfree(vfe_top->top_priv); +free_top_priv: + kfree(vfe_top->top_priv); free_vfe_top: kfree(vfe_top); end: @@ -1020,35 +676,39 @@ int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top_ptr) goto free_vfe_top; } - for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { - top_priv->mux_rsrc[i].res_state = + for (i = 0; i < top_priv->top_common.num_mux; i++) { + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; - if (top_priv->mux_rsrc[i].res_type == + if (top_priv->top_common.mux_rsrc[i].res_type == CAM_VFE_CAMIF_VER_2_0) { - rc = cam_vfe_camif_ver2_deinit(&top_priv->mux_rsrc[i]); + rc = cam_vfe_camif_ver2_deinit( + &top_priv->top_common.mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", rc); - } else if (top_priv->mux_rsrc[i].res_type == + } else if (top_priv->top_common.mux_rsrc[i].res_type == CAM_VFE_CAMIF_LITE_VER_2_0) { rc = cam_vfe_camif_lite_ver2_deinit( - &top_priv->mux_rsrc[i]); + &top_priv->top_common.mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "Camif lite deinit failed rc=%d", rc); - } else if (top_priv->mux_rsrc[i].res_type == + } else if (top_priv->top_common.mux_rsrc[i].res_type == CAM_VFE_RDI_VER_1_0) { - rc = cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i]); + rc = cam_vfe_rdi_ver2_deinit( + &top_priv->top_common.mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "RDI deinit failed rc=%d", rc); - } else if (top_priv->mux_rsrc[i].res_type == + } else if (top_priv->top_common.mux_rsrc[i].res_type == CAM_VFE_IN_RD_VER_1_0) { - rc = cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i]); + rc = cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", rc); } } + kfree(vfe_top->top_priv); free_vfe_top: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h index 82e30b4285a5..961bf954aaa1 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h @@ -10,8 +10,7 @@ #include "cam_vfe_camif_lite_ver2.h" #include "cam_vfe_rdi.h" #include "cam_vfe_fe_ver1.h" - -#define CAM_VFE_TOP_VER2_MUX_MAX 6 +#include "cam_vfe_top_common.h" enum cam_vfe_top_ver2_module_type { CAM_VFE_TOP_VER2_MODULE_LENS, @@ -50,7 +49,8 @@ struct cam_vfe_top_ver2_hw_info { struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; struct cam_vfe_fe_ver1_hw_info fe_hw_info; - uint32_t mux_type[CAM_VFE_TOP_VER2_MUX_MAX]; + uint32_t num_mux; + uint32_t mux_type[CAM_VFE_TOP_MUX_MAX]; }; int cam_vfe_top_ver2_init(struct cam_hw_soc_info *soc_info, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index 578b0771821f..a4fbe67aa955 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -10,14 +10,12 @@ #include "cam_vfe_top.h" #include "cam_vfe_top_ver3.h" #include "cam_debug_util.h" -#include "cam_cpas_api.h" #include "cam_vfe_soc.h" #define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00000003 #define CAM_VFE_HW_RESET_HW_VAL 0x007F0000 #define CAM_VFE_LITE_HW_RESET_AND_REG_VAL 0x00000002 #define CAM_VFE_LITE_HW_RESET_HW_VAL 0x0000003D -#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 3 struct cam_vfe_top_ver3_common_data { struct cam_hw_soc_info *soc_info; @@ -27,17 +25,10 @@ struct cam_vfe_top_ver3_common_data { struct cam_vfe_top_ver3_priv { struct cam_vfe_top_ver3_common_data common_data; - struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER3_MUX_MAX]; unsigned long hw_clk_rate; - struct cam_axi_vote applied_axi_vote; - struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER3_MUX_MAX]; - unsigned long req_clk_rate[CAM_VFE_TOP_VER3_MUX_MAX]; - struct cam_axi_vote last_vote[CAM_VFE_TOP_VER3_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; - uint32_t last_counter; - uint64_t total_bw_applied; - enum cam_vfe_bw_control_action - axi_vote_control[CAM_VFE_TOP_VER3_MUX_MAX]; + unsigned long req_clk_rate[ + CAM_VFE_TOP_MUX_MAX]; + struct cam_vfe_top_priv_common top_common; }; static int cam_vfe_top_ver3_mux_get_base(struct cam_vfe_top_ver3_priv *top_priv, @@ -96,14 +87,14 @@ static int cam_vfe_top_ver3_set_hw_clk_rate( soc_info = top_priv->common_data.soc_info; - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { if (top_priv->req_clk_rate[i] > max_clk_rate) max_clk_rate = top_priv->req_clk_rate[i]; } if (max_clk_rate == top_priv->hw_clk_rate) return 0; - CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%llu", + CAM_DBG(CAM_PERF, "VFE: Clock name=%s idx=%d clk=%llu", soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); @@ -112,196 +103,7 @@ static int cam_vfe_top_ver3_set_hw_clk_rate( if (!rc) top_priv->hw_clk_rate = max_clk_rate; else - CAM_ERR(CAM_ISP, "Set Clock rate failed, rc=%d", rc); - - return rc; -} - -static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction( - struct cam_vfe_top_ver3_priv *top_priv, - uint64_t *to_be_applied_bw) -{ - uint32_t i, j; - int vote_idx = -1; - uint64_t max_bw = 0; - uint64_t total_bw; - struct cam_axi_vote *curr_l_vote; - - for (i = 0; i < (CAM_VFE_TOP_VER3_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { - total_bw = 0; - curr_l_vote = &top_priv->last_vote[i]; - for (j = 0; j < curr_l_vote->num_paths; j++) { - if (total_bw > - (U64_MAX - - curr_l_vote->axi_path[j].camnoc_bw)) { - CAM_ERR(CAM_ISP, "Overflow at idx: %d", j); - return NULL; - } - - total_bw += curr_l_vote->axi_path[j].camnoc_bw; - } - - if (total_bw > max_bw) { - vote_idx = i; - max_bw = total_bw; - } - } - - if (vote_idx < 0) - return NULL; - - *to_be_applied_bw = max_bw; - - return &top_priv->last_vote[vote_idx]; -} - -static int cam_vfe_top_ver3_set_axi_bw_vote( - struct cam_vfe_top_ver3_priv *top_priv, - bool start_stop) -{ - struct cam_axi_vote agg_vote = {0}; - struct cam_axi_vote *to_be_applied_axi_vote = NULL; - int rc = 0; - uint32_t i; - uint32_t num_paths = 0; - uint64_t total_bw_new_vote = 0; - bool bw_unchanged = true; - struct cam_hw_soc_info *soc_info = - top_priv->common_data.soc_info; - struct cam_vfe_soc_private *soc_private = - soc_info->soc_private; - bool apply_bw_update = false; - - if (!soc_private) { - CAM_ERR(CAM_ISP, "Error soc_private NULL"); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - if (top_priv->axi_vote_control[i] == - CAM_VFE_BW_CONTROL_INCLUDE) { - if (num_paths + - top_priv->req_axi_vote[i].num_paths > - CAM_CPAS_MAX_PATHS_PER_CLIENT) { - CAM_ERR(CAM_ISP, - "Required paths(%d) more than max(%d)", - num_paths + - top_priv->req_axi_vote[i].num_paths, - CAM_CPAS_MAX_PATHS_PER_CLIENT); - return -EINVAL; - } - - memcpy(&agg_vote.axi_path[num_paths], - &top_priv->req_axi_vote[i].axi_path[0], - top_priv->req_axi_vote[i].num_paths * - sizeof( - struct cam_axi_per_path_bw_vote)); - num_paths += top_priv->req_axi_vote[i].num_paths; - } - } - - agg_vote.num_paths = num_paths; - - for (i = 0; i < agg_vote.num_paths; i++) { - CAM_DBG(CAM_PERF, - "ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]", - top_priv->common_data.hw_intf->hw_idx, - top_priv->last_counter, - cam_cpas_axi_util_path_type_to_string( - agg_vote.axi_path[i].path_data_type), - cam_cpas_axi_util_trans_type_to_string( - agg_vote.axi_path[i].transac_type), - agg_vote.axi_path[i].camnoc_bw, - agg_vote.axi_path[i].mnoc_ab_bw, - agg_vote.axi_path[i].mnoc_ib_bw); - - total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; - } - - memcpy(&top_priv->last_vote[top_priv->last_counter], &agg_vote, - sizeof(struct cam_axi_vote)); - top_priv->last_counter = (top_priv->last_counter + 1) % - (CAM_VFE_TOP_VER3_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - - if ((agg_vote.num_paths != top_priv->applied_axi_vote.num_paths) || - (total_bw_new_vote != top_priv->total_bw_applied)) - bw_unchanged = false; - - CAM_DBG(CAM_PERF, - "ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d", - top_priv->common_data.hw_intf->hw_idx, - top_priv->total_bw_applied, total_bw_new_vote, - bw_unchanged, start_stop); - - if (bw_unchanged) { - CAM_DBG(CAM_ISP, "BW config unchanged"); - return 0; - } - - if (start_stop) { - /* need to vote current request immediately */ - to_be_applied_axi_vote = &agg_vote; - /* Reset everything, we can start afresh */ - memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * - (CAM_VFE_TOP_VER3_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); - top_priv->last_counter = 0; - top_priv->last_vote[top_priv->last_counter] = agg_vote; - top_priv->last_counter = (top_priv->last_counter + 1) % - (CAM_VFE_TOP_VER3_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - } else { - /* - * Find max bw request in last few frames. This will the bw - * that we want to vote to CPAS now. - */ - to_be_applied_axi_vote = - cam_vfe_top_delay_bw_reduction(top_priv, - &total_bw_new_vote); - if (!to_be_applied_axi_vote) { - CAM_ERR(CAM_ISP, "to_be_applied_axi_vote is NULL"); - return -EINVAL; - } - } - - for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) { - CAM_DBG(CAM_PERF, - "ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]", - top_priv->common_data.hw_intf->hw_idx, - cam_cpas_axi_util_path_type_to_string( - to_be_applied_axi_vote->axi_path[i].path_data_type), - cam_cpas_axi_util_trans_type_to_string( - to_be_applied_axi_vote->axi_path[i].transac_type), - to_be_applied_axi_vote->axi_path[i].camnoc_bw, - to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw, - to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw); - } - - if ((to_be_applied_axi_vote->num_paths != - top_priv->applied_axi_vote.num_paths) || - (total_bw_new_vote != top_priv->total_bw_applied)) - apply_bw_update = true; - - CAM_DBG(CAM_PERF, - "ife[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d", - top_priv->common_data.hw_intf->hw_idx, - top_priv->total_bw_applied, total_bw_new_vote, - apply_bw_update, start_stop); - - if (apply_bw_update) { - rc = cam_cpas_update_axi_vote(soc_private->cpas_handle, - to_be_applied_axi_vote); - if (!rc) { - memcpy(&top_priv->applied_axi_vote, - to_be_applied_axi_vote, - sizeof(struct cam_axi_vote)); - top_priv->total_bw_applied = total_bw_new_vote; - } else { - CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); - } - } + CAM_ERR(CAM_PERF, "Set Clock rate failed, rc=%d", rc); return rc; } @@ -333,7 +135,7 @@ static int cam_vfe_top_ver3_clock_update( res = clk_update->node_res; if (!res || !res->hw_intf->hw_priv) { - CAM_ERR(CAM_ISP, "Invalid input res %pK", res); + CAM_ERR(CAM_PERF, "Invalid input res %pK", res); return -EINVAL; } @@ -341,21 +143,21 @@ static int cam_vfe_top_ver3_clock_update( if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + CAM_ERR(CAM_PERF, "VFE:%d Invalid res_type:%d res id%d", res->hw_intf->hw_idx, res->res_type, res->res_id); return -EINVAL; } - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == res->res_id) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == res->res_id) { top_priv->req_clk_rate[i] = clk_update->clk_rate; break; } } if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "VFE:%d Not ready to set clocks yet :%d", res->hw_intf->hw_idx, hw_info->hw_state); @@ -365,148 +167,6 @@ static int cam_vfe_top_ver3_clock_update( return rc; } -static int cam_vfe_top_ver3_bw_update_v2( - struct cam_vfe_top_ver3_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_vfe_bw_update_args_v2 *bw_update = NULL; - struct cam_isp_resource_node *res = NULL; - struct cam_hw_info *hw_info = NULL; - int rc = 0; - int i; - - bw_update = (struct cam_vfe_bw_update_args_v2 *)cmd_args; - res = bw_update->node_res; - - if (!res || !res->hw_intf || !res->hw_intf->hw_priv) - return -EINVAL; - - hw_info = res->hw_intf->hw_priv; - - if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || - res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", - res->hw_intf->hw_idx, res->res_type, - res->res_id); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == res->res_id) { - memcpy(&top_priv->req_axi_vote[i], &bw_update->isp_vote, - sizeof(struct cam_axi_vote)); - top_priv->axi_vote_control[i] = - CAM_VFE_BW_CONTROL_INCLUDE; - break; - } - } - - if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "VFE:%d Not ready to set BW yet :%d", - res->hw_intf->hw_idx, - hw_info->hw_state); - } else { - rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, false); - } - - return rc; -} - -static int cam_vfe_top_ver3_bw_update( - struct cam_vfe_top_ver3_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_vfe_bw_update_args *bw_update = NULL; - struct cam_isp_resource_node *res = NULL; - struct cam_hw_info *hw_info = NULL; - int rc = 0; - int i; - struct cam_axi_vote *mux_axi_vote; - bool vid_exists = false; - bool rdi_exists = false; - - bw_update = (struct cam_vfe_bw_update_args *)cmd_args; - res = bw_update->node_res; - - if (!res || !res->hw_intf || !res->hw_intf->hw_priv) - return -EINVAL; - - hw_info = res->hw_intf->hw_priv; - - CAM_DBG(CAM_ISP, "res_id=%d, BW=[%lld %lld]", - res->res_id, bw_update->camnoc_bw_bytes, - bw_update->external_bw_bytes); - - if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || - res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", - res->hw_intf->hw_idx, res->res_type, - res->res_id); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - mux_axi_vote = &top_priv->req_axi_vote[i]; - if (top_priv->mux_rsrc[i].res_id == res->res_id) { - mux_axi_vote->num_paths = 1; - if ((res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && - (res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) { - mux_axi_vote->axi_path[0].path_data_type = - CAM_AXI_PATH_DATA_IFE_RDI0 + - (res->res_id - CAM_ISP_HW_VFE_IN_RDI0); - } else { - /* - * Vote all bw into VIDEO path as we cannot - * differentiate to which path this has to go - */ - mux_axi_vote->axi_path[0].path_data_type = - CAM_AXI_PATH_DATA_IFE_VID; - } - - mux_axi_vote->axi_path[0].transac_type = - CAM_AXI_TRANSACTION_WRITE; - mux_axi_vote->axi_path[0].camnoc_bw = - bw_update->camnoc_bw_bytes; - mux_axi_vote->axi_path[0].mnoc_ab_bw = - bw_update->external_bw_bytes; - mux_axi_vote->axi_path[0].mnoc_ib_bw = - bw_update->external_bw_bytes; - /* Make ddr bw same as mnoc bw */ - mux_axi_vote->axi_path[0].ddr_ab_bw = - bw_update->external_bw_bytes; - mux_axi_vote->axi_path[0].ddr_ib_bw = - bw_update->external_bw_bytes; - - top_priv->axi_vote_control[i] = - CAM_VFE_BW_CONTROL_INCLUDE; - break; - } - - if (mux_axi_vote->num_paths == 1) { - if (mux_axi_vote->axi_path[0].path_data_type == - CAM_AXI_PATH_DATA_IFE_VID) - vid_exists = true; - else if ((mux_axi_vote->axi_path[0].path_data_type >= - CAM_AXI_PATH_DATA_IFE_RDI0) && - (mux_axi_vote->axi_path[0].path_data_type <= - CAM_AXI_PATH_DATA_IFE_RDI3)) - rdi_exists = true; - } - } - - if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "VFE:%d Not ready to set BW yet :%d", - res->hw_intf->hw_idx, - hw_info->hw_state); - } else { - rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, false); - } - - return rc; -} - static int cam_vfe_core_config_control( struct cam_vfe_top_ver3_priv *top_priv, void *cmd_args, uint32_t arg_size) @@ -520,51 +180,6 @@ static int cam_vfe_core_config_control( return -EINVAL; } -static int cam_vfe_top_ver3_bw_control( - struct cam_vfe_top_ver3_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_vfe_bw_control_args *bw_ctrl = NULL; - struct cam_isp_resource_node *res = NULL; - struct cam_hw_info *hw_info = NULL; - int rc = 0; - int i; - - bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args; - res = bw_ctrl->node_res; - - if (!res || !res->hw_intf->hw_priv) - return -EINVAL; - - hw_info = res->hw_intf->hw_priv; - - if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || - res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { - CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", - res->hw_intf->hw_idx, res->res_type, - res->res_id); - return -EINVAL; - } - - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == res->res_id) { - top_priv->axi_vote_control[i] = bw_ctrl->action; - break; - } - } - - if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { - CAM_ERR_RATE_LIMIT(CAM_ISP, - "VFE:%d Not ready to set BW yet :%d", - res->hw_intf->hw_idx, - hw_info->hw_state); - } else { - rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, true); - } - - return rc; -} - static int cam_vfe_top_ver3_mux_get_reg_update( struct cam_vfe_top_ver3_priv *top_priv, void *cmd_args, uint32_t arg_size) @@ -680,14 +295,15 @@ int cam_vfe_top_ver3_reserve(void *device_priv, CAM_DBG(CAM_ISP, "res id %d", acquire_args->res_id); - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == acquire_args->res_id && - top_priv->mux_rsrc[i].res_state == + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + acquire_args->res_id && + top_priv->top_common.mux_rsrc[i].res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { rc = cam_vfe_camif_ver3_acquire_resource( - &top_priv->mux_rsrc[i], + &top_priv->top_common.mux_rsrc[i], args); if (rc) break; @@ -696,7 +312,7 @@ int cam_vfe_top_ver3_reserve(void *device_priv, if (acquire_args->res_id >= CAM_ISP_HW_VFE_IN_RDI0 && acquire_args->res_id < CAM_ISP_HW_VFE_IN_MAX) { rc = cam_vfe_camif_lite_ver3_acquire_resource( - &top_priv->mux_rsrc[i], + &top_priv->top_common.mux_rsrc[i], args); if (rc) break; @@ -704,18 +320,20 @@ int cam_vfe_top_ver3_reserve(void *device_priv, if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { rc = cam_vfe_fe_ver1_acquire_resource( - &top_priv->mux_rsrc[i], + &top_priv->top_common.mux_rsrc[i], args); if (rc) break; } - top_priv->mux_rsrc[i].cdm_ops = acquire_args->cdm_ops; - top_priv->mux_rsrc[i].tasklet_info = args->tasklet; - top_priv->mux_rsrc[i].res_state = + top_priv->top_common.mux_rsrc[i].cdm_ops = + acquire_args->cdm_ops; + top_priv->top_common.mux_rsrc[i].tasklet_info = + args->tasklet; + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_RESERVED; acquire_args->rsrc_node = - &top_priv->mux_rsrc[i]; + &top_priv->top_common.mux_rsrc[i]; rc = 0; break; @@ -757,6 +375,8 @@ int cam_vfe_top_ver3_start(void *device_priv, struct cam_vfe_top_ver3_priv *top_priv; struct cam_isp_resource_node *mux_res; struct cam_hw_info *hw_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; int rc = 0; if (!device_priv || !start_args) { @@ -765,6 +385,13 @@ int cam_vfe_top_ver3_start(void *device_priv, } top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + mux_res = (struct cam_isp_resource_node *)start_args; hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; @@ -776,7 +403,8 @@ int cam_vfe_top_ver3_start(void *device_priv, return rc; } - rc = cam_vfe_top_ver3_set_axi_bw_vote(top_priv, true); + rc = cam_vfe_top_set_axi_bw_vote(soc_private, + &top_priv->top_common, true); if (rc) { CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc); @@ -823,12 +451,13 @@ int cam_vfe_top_ver3_stop(void *device_priv, } if (!rc) { - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - if (top_priv->mux_rsrc[i].res_id == mux_res->res_id) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + mux_res->res_id) { top_priv->req_clk_rate[i] = 0; - memset(&top_priv->req_axi_vote[i], 0, - sizeof(struct cam_axi_vote)); - top_priv->axi_vote_control[i] = + memset(&top_priv->top_common.req_axi_vote[i], + 0, sizeof(struct cam_axi_vote)); + top_priv->top_common.axi_vote_control[i] = CAM_VFE_BW_CONTROL_EXCLUDE; break; } @@ -855,12 +484,21 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, { int rc = 0; struct cam_vfe_top_ver3_priv *top_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; if (!device_priv || !cmd_args) { CAM_ERR(CAM_ISP, "Error, Invalid arguments"); return -EINVAL; } + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } switch (cmd_type) { case CAM_ISP_HW_CMD_GET_CHANGE_BASE: @@ -880,15 +518,16 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, arg_size); break; case CAM_ISP_HW_CMD_BW_UPDATE: - rc = cam_vfe_top_ver3_bw_update(top_priv, cmd_args, - arg_size); + rc = cam_vfe_top_bw_update(soc_private, &top_priv->top_common, + cmd_args, arg_size); break; case CAM_ISP_HW_CMD_BW_UPDATE_V2: - rc = cam_vfe_top_ver3_bw_update_v2(top_priv, cmd_args, - arg_size); + rc = cam_vfe_top_bw_update_v2(soc_private, + &top_priv->top_common, cmd_args, arg_size); break; case CAM_ISP_HW_CMD_BW_CONTROL: - rc = cam_vfe_top_ver3_bw_control(top_priv, cmd_args, arg_size); + rc = cam_vfe_top_bw_control(soc_private, &top_priv->top_common, + cmd_args, arg_size); break; case CAM_ISP_HW_CMD_CORE_CONFIG: rc = cam_vfe_core_config_control(top_priv, cmd_args, arg_size); @@ -928,68 +567,82 @@ int cam_vfe_top_ver3_init( rc = -ENOMEM; goto free_vfe_top; } + vfe_top->top_priv = top_priv; top_priv->hw_clk_rate = 0; + if (ver3_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) { + CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d", + ver3_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX); + rc = -EINVAL; + goto free_top_priv; + } + + top_priv->top_common.num_mux = ver3_hw_info->num_mux; - for (i = 0, j = 0; i < CAM_VFE_TOP_VER3_MUX_MAX && + for (i = 0, j = 0; i < top_priv->top_common.num_mux && j < CAM_VFE_RDI_VER2_MAX; i++) { - top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN; - top_priv->mux_rsrc[i].hw_intf = hw_intf; - top_priv->mux_rsrc[i].res_state = + top_priv->top_common.mux_rsrc[i].res_type = + CAM_ISP_RESOURCE_VFE_IN; + top_priv->top_common.mux_rsrc[i].hw_intf = hw_intf; + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; top_priv->req_clk_rate[i] = 0; if (ver3_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_3_0) { - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_CAMIF; rc = cam_vfe_camif_ver3_init(hw_intf, soc_info, &ver3_hw_info->camif_hw_info, - &top_priv->mux_rsrc[i], vfe_irq_controller); + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); if (rc) goto deinit_resources; } else if (ver3_hw_info->mux_type[i] == CAM_VFE_PDLIB_VER_1_0) { /* set the PDLIB resource id */ - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_PDLIB; rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, &ver3_hw_info->pdlib_hw_info, - &top_priv->mux_rsrc[i], vfe_irq_controller); + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); if (rc) goto deinit_resources; } else if (ver3_hw_info->mux_type[i] == CAM_VFE_IN_RD_VER_1_0) { /* set the RD resource id */ - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_RD; rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, &ver3_hw_info->fe_hw_info, - &top_priv->mux_rsrc[i]); + &top_priv->top_common.mux_rsrc[i]); if (rc) goto deinit_resources; } else if (ver3_hw_info->mux_type[i] == CAM_VFE_RDI_VER_1_0) { /* set the RDI resource id */ - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_RDI0 + j; rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, ver3_hw_info->rdi_hw_info[j++], - &top_priv->mux_rsrc[i], vfe_irq_controller); + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); if (rc) goto deinit_resources; } else if (ver3_hw_info->mux_type[i] == CAM_VFE_LCR_VER_1_0) { /* set the LCR resource id */ - top_priv->mux_rsrc[i].res_id = + top_priv->top_common.mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_LCR; rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, &ver3_hw_info->lcr_hw_info, - &top_priv->mux_rsrc[i], vfe_irq_controller); + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); if (rc) goto deinit_resources; } else { @@ -1012,6 +665,7 @@ int cam_vfe_top_ver3_init( top_priv->common_data.soc_info = soc_info; top_priv->common_data.hw_intf = hw_intf; + top_priv->top_common.hw_idx = hw_intf->hw_idx; top_priv->common_data.common_reg = ver3_hw_info->common_reg; return rc; @@ -1019,22 +673,26 @@ int cam_vfe_top_ver3_init( deinit_resources: for (--i; i >= 0; i--) { if (ver3_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_3_0) { - if (cam_vfe_camif_ver3_deinit(&top_priv->mux_rsrc[i])) + if (cam_vfe_camif_ver3_deinit( + &top_priv->top_common.mux_rsrc[i])) CAM_ERR(CAM_ISP, "Camif Deinit failed"); } else if (ver3_hw_info->mux_type[i] == CAM_VFE_IN_RD_VER_1_0) { - if (cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i])) + if (cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i])) CAM_ERR(CAM_ISP, "Camif fe Deinit failed"); } else { if (cam_vfe_camif_lite_ver3_deinit( - &top_priv->mux_rsrc[i])) + &top_priv->top_common.mux_rsrc[i])) CAM_ERR(CAM_ISP, "Camif lite res id %d Deinit failed", - top_priv->mux_rsrc[i].res_id); + top_priv->top_common.mux_rsrc[i] + .res_id); } - top_priv->mux_rsrc[i].res_state = + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; } +free_top_priv: kfree(vfe_top->top_priv); free_vfe_top: kfree(vfe_top); @@ -1066,28 +724,31 @@ int cam_vfe_top_ver3_deinit(struct cam_vfe_top **vfe_top_ptr) goto free_vfe_top; } - for (i = 0; i < CAM_VFE_TOP_VER3_MUX_MAX; i++) { - top_priv->mux_rsrc[i].res_state = + for (i = 0; i < top_priv->top_common.num_mux; i++) { + top_priv->top_common.mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; - if (top_priv->mux_rsrc[i].res_type == + if (top_priv->top_common.mux_rsrc[i].res_type == CAM_VFE_CAMIF_VER_3_0) { - rc = cam_vfe_camif_ver3_deinit(&top_priv->mux_rsrc[i]); + rc = cam_vfe_camif_ver3_deinit( + &top_priv->top_common.mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", rc); - } else if (top_priv->mux_rsrc[i].res_type == + } else if (top_priv->top_common.mux_rsrc[i].res_type == CAM_VFE_IN_RD_VER_1_0) { - rc = cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i]); + rc = cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", rc); } else { rc = cam_vfe_camif_lite_ver3_deinit( - &top_priv->mux_rsrc[i]); + &top_priv->top_common.mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "Camif lite res id %d Deinit failed", - top_priv->mux_rsrc[i].res_id); + top_priv->top_common.mux_rsrc[i] + .res_id); } } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h index dd0bb94c42c7..14c96097cdf6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h @@ -9,8 +9,7 @@ #include "cam_vfe_camif_ver3.h" #include "cam_vfe_camif_lite_ver3.h" #include "cam_vfe_fe_ver1.h" - -#define CAM_VFE_TOP_VER3_MUX_MAX 6 +#include "cam_vfe_top_common.h" #define CAM_SHIFT_TOP_CORE_CFG_MUXSEL_PDAF 31 #define CAM_SHIFT_TOP_CORE_CFG_VID_DS16_R2PD 30 @@ -86,7 +85,8 @@ struct cam_vfe_top_ver3_hw_info { *rdi_hw_info[CAM_VFE_RDI_VER2_MAX]; struct cam_vfe_camif_lite_ver3_hw_info lcr_hw_info; struct cam_vfe_fe_ver1_hw_info fe_hw_info; - uint32_t mux_type[CAM_VFE_TOP_VER3_MUX_MAX]; + uint32_t num_mux; + uint32_t mux_type[CAM_VFE_TOP_MUX_MAX]; }; int cam_vfe_top_ver3_init(struct cam_hw_soc_info *soc_info, -- GitLab From 692d184a62181624590b3681de50e3bdc4ec65b7 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 12:04:10 -0700 Subject: [PATCH 028/410] msm: camera: icp: lock before updating clock status Clock status can be updated in two ways, either through timer or through the recovery. In case the clock is not available during the recovery then it would try to access registers which are unclocked. To prevent this before updating the clock status spinlock should be acquired. Change-Id: I16aea5e7dafacfe6b520699af195194d5d171c7c Signed-off-by: Tejas Prajapati Signed-off-by: Jigarkumar Zala --- drivers/cam_icp/icp_hw/bps_hw/bps_core.c | 5 +++++ drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c index 73075a4ec379..7deea1c94d84 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c @@ -306,6 +306,7 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, struct cam_bps_device_core_info *core_info = NULL; struct cam_bps_device_hw_info *hw_info = NULL; int rc = 0; + unsigned long flags; if (!device_priv) { CAM_ERR(CAM_ICP, "Invalid arguments"); @@ -395,12 +396,16 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, } break; case CAM_ICP_BPS_CMD_DISABLE_CLK: + spin_lock_irqsave(&bps_dev->hw_lock, flags); if (core_info->clk_enable == true) cam_bps_toggle_clk(soc_info, false); core_info->clk_enable = false; + spin_unlock_irqrestore(&bps_dev->hw_lock, flags); break; case CAM_ICP_BPS_CMD_RESET: + spin_lock_irqsave(&bps_dev->hw_lock, flags); rc = cam_bps_cmd_reset(soc_info, core_info); + spin_unlock_irqrestore(&bps_dev->hw_lock, flags); break; default: CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c index 82d0ebe54cc4..614c748f0d85 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -305,6 +305,7 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, struct cam_ipe_device_core_info *core_info = NULL; struct cam_ipe_device_hw_info *hw_info = NULL; int rc = 0; + unsigned long flags; if (!device_priv) { CAM_ERR(CAM_ICP, "Invalid arguments"); @@ -389,12 +390,16 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, } break; case CAM_ICP_IPE_CMD_DISABLE_CLK: + spin_lock_irqsave(&ipe_dev->hw_lock, flags); if (core_info->clk_enable == true) cam_ipe_toggle_clk(soc_info, false); core_info->clk_enable = false; + spin_unlock_irqrestore(&ipe_dev->hw_lock, flags); break; case CAM_ICP_IPE_CMD_RESET: + spin_lock_irqsave(&ipe_dev->hw_lock, flags); rc = cam_ipe_cmd_reset(soc_info, core_info); + spin_unlock_irqrestore(&ipe_dev->hw_lock, flags); break; default: CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); -- GitLab From 55c3fecc4baa49418183eaae560eae901eae14eb Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 12:05:42 -0700 Subject: [PATCH 029/410] msm: camera: lrme : Fix for lrme_hw null dereference Fixes lrme_hw pointer when lrme_hw becomes null returns with -ENODEV. Change-Id: Ic2c15ebad868b056be4ce4ac28196960a1889292 Signed-off-by: Mangalaram ARCHANA Signed-off-by: Jigarkumar Zala --- drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index 20828f629b4d..4e2609648b30 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include @@ -237,8 +237,7 @@ static int cam_lrme_hw_dev_remove(struct platform_device *pdev) lrme_hw = platform_get_drvdata(pdev); if (!lrme_hw) { CAM_ERR(CAM_LRME, "Invalid lrme_hw from fd_hw_intf"); - rc = -ENODEV; - goto deinit_platform_res; + return -ENODEV; } lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; -- GitLab From 44abb0120ddbdd95e166e3993868704399d09bf0 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 12:22:39 -0700 Subject: [PATCH 030/410] msm: camera: cpas: Enable camnoc ubwc irqs for kona A notification is needed for camnoc ubwc encoder and decoder errors in kona which were previously disabled. Update camnoc irq register offsets and enable camnoc irq for ubwc. Change-Id: I74b7264c537122a7bda618e8be03c4ac97c23000 Signed-off-by: Mukund Madhusudan Atre Signed-off-by: Jigarkumar Zala --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 3 + drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 15 +++++ drivers/cam_cpas/cpas_top/cpastop_v480_100.h | 68 ++++++++++---------- drivers/cam_cpas/include/cam_cpas_api.h | 12 ++++ 4 files changed, 63 insertions(+), 35 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 57eb9de92be4..0a21693732a2 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -424,6 +424,7 @@ static void cam_cpastop_work(struct work_struct *work) cpas_core, soc_info, &irq_data.u.slave_err); break; + case CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: case CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR: case CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR: case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: @@ -431,6 +432,8 @@ static void cam_cpastop_work(struct work_struct *work) cpas_core, soc_info, i, &irq_data.u.enc_err); break; + case CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR: case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR: cam_cpastop_handle_ubwc_dec_err( cpas_core, soc_info, i, diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index 8a8c61a21914..bdcf00da90b7 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -17,12 +17,21 @@ * observed at any slave port is logged into * the error logger register and an IRQ is * triggered + * @CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: Triggered if any error + * detected in the IFE UBWC- + * Stats encoder instance * @CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error * detected in the IFE0 UBWC * encoder instance * @CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error * detected in the IFE1 or IFE3 * UBWC encoder instance + * @CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR: Triggered if any error + * detected in the IPE1/BPS read + * path decoder instance + * @CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR : Triggered if any error detected + * in the IPE0 read path decoder + * instance * @CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR: Triggered if any error * detected in the IPE/BPS * UBWC decoder instance @@ -43,6 +52,8 @@ enum cam_camnoc_hw_irq_type { CAM_CAMNOC_HW_IRQ_SLAVE_ERROR = CAM_CAMNOC_IRQ_SLAVE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR = CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR = @@ -51,6 +62,10 @@ enum cam_camnoc_hw_irq_type { CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR = CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR = + CAM_CAMNOC_IRQ_IPE1_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR = + CAM_CAMNOC_IRQ_IPE0_UBWC_DECODE_ERROR, CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR = CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR, CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR = diff --git a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h index fcf25383ec66..510b97062fbc 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -11,28 +11,26 @@ static struct cam_camnoc_irq_sbm cam_cpas_v480_100_irq_sbm = { .sbm_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, - .enable = false, - .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ - .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ - 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + .enable = true, + .offset = 0x3840, /* SBM_FAULTINEN0_LOW */ + .value = 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ - 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ (TEST_IRQ_ENABLE ? - 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x40 : /* SBM_FAULTINEN0_LOW_PORT6_MASK */ 0x0), }, .sbm_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + .offset = 0x3848, /* SBM_FAULTINSTATUS0_LOW */ }, .sbm_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ - .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + .offset = 0x3880, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x5 : 0x1, } }; @@ -40,89 +38,89 @@ static struct cam_camnoc_irq_err cam_cpas_v480_100_irq_err[] = { { .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, - .enable = true, + .enable = false, .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .offset = 0x7008, /* ERL_MAINCTL_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .offset = 0x7010, /* ERL_ERRVLD_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .offset = 0x7018, /* ERL_ERRCLR_LOW */ .value = 1, }, }, { - .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .irq_type = CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, .enable = true, .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x5a0, /* IFE02_ENCERREN_LOW */ + .offset = 0x1BA0, /* IFE_UBWC_STATS_ENCERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x590, /* IFE02_ENCERRSTATUS_LOW */ + .offset = 0x1B90, /* IFE_UBWC_STATS_ENCERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x598, /* IFE02_ENCERRCLR_LOW */ + .offset = 0x1B98, /* IFE_UBWC_STATS_ENCERRCLR_LOW */ .value = 1, }, }, { - .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .irq_type = CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR, .enable = true, .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x9a0, /* IFE13_ENCERREN_LOW */ + .offset = 0x2520, /* IPE1_BPS_RD_DECERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x990, /* IFE13_ENCERRSTATUS_LOW */ + .offset = 0x2510, /* IPE1_BPS_RD_DECERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x998, /* IFE13_ENCERRCLR_LOW */ + .offset = 0x2518, /* IPE1_BPS_RD_DECERRCLR_LOW */ .value = 1, }, }, { - .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .irq_type = CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR, .enable = true, .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0xd20, /* IBL_RD_DECERREN_LOW */ + .offset = 0x1F20, /* IPE0_RD_DECERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0xd10, /* IBL_RD_DECERRSTATUS_LOW */ + .offset = 0x1F10, /* IPE0_RD_DECERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0xd18, /* IBL_RD_DECERRCLR_LOW */ + .offset = 0x1F18, /* IPE0_RD_DECERRCLR_LOW */ .value = 1, }, }, @@ -133,36 +131,36 @@ static struct cam_camnoc_irq_err .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x11a0, /* IBL_WR_ENCERREN_LOW */ + .offset = 0x29A0, /* IPE_BPS_WR_ENCERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x1190, - /* IBL_WR_ENCERRSTATUS_LOW */ + .offset = 0x2990, + /* IPE_BPS_WR_ENCERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x1198, /* IBL_WR_ENCERRCLR_LOW */ + .offset = 0x2998, /* IPE_BPS_WR_ENCERRCLR_LOW */ .value = 1, }, }, { .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, - .enable = true, + .enable = false, .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .offset = 0x3888, /* SBM_FLAGOUTSET0_LOW */ .value = 0x1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + .offset = 0x3890, /* SBM_FLAGOUTSTATUS0_LOW */ }, .err_clear = { .enable = false, @@ -179,17 +177,17 @@ static struct cam_camnoc_irq_err { .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, .enable = TEST_IRQ_ENABLE ? true : false, - .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .sbm_port = 0x40, /* SBM_FAULTINSTATUS0_LOW_PORT6_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .offset = 0x3888, /* SBM_FLAGOUTSET0_LOW */ .value = 0x5, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + .offset = 0x3890, /* SBM_FLAGOUTSTATUS0_LOW */ }, .err_clear = { .enable = false, diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 932f4b2abf88..1126053e2b33 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -57,6 +57,9 @@ enum cam_cpas_hw_version { * observed at any slave port is logged into * the error logger register and an IRQ is * triggered + * @CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: Triggered if any error detected + * in the IFE UBWC-Stats encoder + * instance * @CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error detected * in the IFE0 UBWC encoder instance * @CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error detected @@ -67,6 +70,12 @@ enum cam_cpas_hw_version { * @CAM_CAMNOC_IRQ_IFE1_WR_UBWC_ENCODE_ERROR : Triggered if any error detected * in the IFE1 UBWC encoder * instance + * @CAM_CAMNOC_IRQ_IPE1_BPS_UBWC_DECODE_ERROR: Triggered if any error detected + * in the IPE1/BPS read path decoder + * instance + * @CAM_CAMNOC_IRQ_IPE0_UBWC_DECODE_ERROR : Triggered if any error detected + * in the IPE0 read path decoder + * instance * @CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR: Triggered if any error detected * in the IPE/BPS UBWC decoder * instance @@ -78,10 +87,13 @@ enum cam_cpas_hw_version { */ enum cam_camnoc_irq_type { CAM_CAMNOC_IRQ_SLAVE_ERROR, + CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IPE1_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_IRQ_IPE0_UBWC_DECODE_ERROR, CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR, CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_AHB_TIMEOUT, -- GitLab From 87c82dcf6a5a12715dfaa3354462b2121f8d9eb5 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 12:23:14 -0700 Subject: [PATCH 031/410] msm: camera: smmu: Set the segment size for the context banks Set the right segment size in the driver for dma_map_sg to allow for partial cache maintanence. Change-Id: I6c439f23e957eb667bf959c830b120c0390e41b1 Signed-off-by: Karthik Anantha Ram Signed-off-by: Jigarkumar Zala --- drivers/cam_smmu/cam_smmu_api.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 7084f38daaaa..a60e02492a4c 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -3474,9 +3474,24 @@ static int cam_populate_smmu_context_banks(struct device *dev, iommu_set_fault_handler(cb->domain, cam_smmu_iommu_fault_handler, (void *)cb->name); + + if (!dev->dma_parms) + dev->dma_parms = devm_kzalloc(dev, + sizeof(*dev->dma_parms), GFP_KERNEL); + + if (!dev->dma_parms) { + CAM_WARN(CAM_SMMU, + "Failed to allocate dma_params"); + dev->dma_parms = NULL; + goto end; + } + + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(dev, DMA_BIT_MASK(64)); + +end: /* increment count to next bank */ iommu_cb_set.cb_init_count++; - CAM_DBG(CAM_SMMU, "X: cb init count :%d", iommu_cb_set.cb_init_count); cb_init_fail: @@ -3488,6 +3503,7 @@ static int cam_smmu_probe(struct platform_device *pdev) int rc = 0; struct device *dev = &pdev->dev; + dev->dma_parms = NULL; if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) { rc = cam_alloc_smmu_context_banks(dev); if (rc < 0) { @@ -3536,8 +3552,15 @@ static int cam_smmu_probe(struct platform_device *pdev) static int cam_smmu_remove(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + /* release all the context banks and memory allocated */ cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT); + if (dev && dev->dma_parms) { + devm_kfree(dev, dev->dma_parms); + dev->dma_parms = NULL; + } + if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu")) cam_smmu_release_cb(pdev); return 0; -- GitLab From 4a8af1ed194f3289a78b657946f07b4a073a7169 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 12:23:53 -0700 Subject: [PATCH 032/410] msm: camera: isp: Fix rdi only usecase Initialize common_reg data for rdi. Adds acquire handling for RDI usecase. Change-Id: I06cc9bf86af834ceeb145e9b49586c97b6f1a461 Signed-off-by: Trishansh Bhardwaj Signed-off-by: Jigarkumar Zala --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h | 8 ++++++++ .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 4 +++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 11 +++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h index f356d6c24b20..aab38c791637 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h @@ -56,6 +56,13 @@ static struct cam_vfe_rdi_ver2_reg vfe17x_rdi_reg = { .reg_update_cmd = 0x000004AC, }; +static struct cam_vfe_rdi_common_reg_data vfe17x_rdi_reg_data = { + .subscribe_irq_mask0 = 0x780001E0, + .subscribe_irq_mask1 = 0x0, + .error_irq_mask0 = 0x0, + .error_irq_mask1 = 0x3C, +}; + static struct cam_vfe_rdi_reg_data vfe17x_rdi_0_data = { .reg_update_cmd_data = 0x2, .sof_irq_mask = 0x8000000, @@ -90,6 +97,7 @@ static struct cam_vfe_top_ver2_hw_info vfe17x_top_hw_info = { .rdi_hw_info = { .common_reg = &vfe17x_top_common_reg, .rdi_reg = &vfe17x_rdi_reg, + .common_reg_data = &vfe17x_rdi_reg_data, .reg_data = { &vfe17x_rdi_0_data, &vfe17x_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 0b230ce19621..3cc92551b79c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -413,7 +413,9 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); ret = CAM_VFE_IRQ_STATUS_SUCCESS; - } else if (irq_status0 & rdi_priv->reg_data->reg_update_irq_mask) { + } + + if (irq_status0 & rdi_priv->reg_data->reg_update_irq_mask) { CAM_DBG(CAM_ISP, "Received REG UPDATE"); if (rdi_priv->event_cb) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index e057b15aee43..c5225c540722 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -276,6 +276,17 @@ int cam_vfe_top_reserve(void *device_priv, break; } + if ((acquire_args->res_id >= + CAM_ISP_HW_VFE_IN_RDI0) && + (acquire_args->res_id <= + CAM_ISP_HW_VFE_IN_RDI3)) { + rc = cam_vfe_rdi_ver2_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { rc = cam_vfe_fe_ver1_acquire_resource( &top_priv->top_common.mux_rsrc[i], -- GitLab From 4767766efb1c98a667936410af2f3425faa330b8 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 12:24:35 -0700 Subject: [PATCH 033/410] msm: camera: Fix usage of invalid array index Fix array index validation number of axi ports while setup/cleanup axi related settings. Also validate the array index for slot index for CRM and updates operation accordingly. Change-Id: Ic42939b7c59a5602b82a19f558030552bf3c0b72 Signed-off-by: Jigarkumar Zala --- drivers/cam_cpas/cam_cpas_hw.c | 12 ++++++++++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 1 + 2 files changed, 13 insertions(+) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index d180b4ecf9aa..1a7a5e2b053e 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -236,6 +236,12 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, { int i = 0; + if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", + cpas_core->num_axi_ports); + return -EINVAL; + } + for (i = 0; i < cpas_core->num_axi_ports; i++) { cam_cpas_util_unregister_bus_client( &cpas_core->axi_port[i].bus_client); @@ -252,6 +258,12 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, int i = 0, rc = 0; struct device_node *axi_port_mnoc_node = NULL; + if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", + cpas_core->num_axi_ports); + return -EINVAL; + } + for (i = 0; i < cpas_core->num_axi_ports; i++) { axi_port_mnoc_node = cpas_core->axi_port[i].axi_port_node; rc = cam_cpas_util_register_bus_client(soc_info, diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index e6c9d97b1c97..6e660a393824 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -979,6 +979,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", req_id, sync_link->link_hdl); sync_ready = false; + return -EAGAIN; } sync_rd_idx = sync_link->req.in_q->rd_idx; -- GitLab From 6761503d24604eb8f518fa1d415ae6a60d97668f Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 13:21:20 -0700 Subject: [PATCH 034/410] msm: camera: crm: Increase the device handles to 128 Increasing the device handles to 128 to support more pipelines. Change-Id: Id0322cba095091e6168d8541d432628d8422a641 Signed-off-by: Mangalaram ARCHANA Signed-off-by: Jigarkumar Zala --- drivers/cam_req_mgr/cam_req_mgr_core.c | 160 +++++++++++++++++++++---- drivers/cam_req_mgr/cam_req_mgr_core.h | 7 +- drivers/cam_req_mgr/cam_req_mgr_dev.c | 37 ++++-- include/uapi/media/cam_req_mgr.h | 18 ++- 4 files changed, 192 insertions(+), 30 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 6e660a393824..f4867d5d828e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2438,7 +2438,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { * */ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, - struct cam_req_mgr_link_info *link_info) + struct cam_req_mgr_ver_info *link_info) { int rc = 0, i = 0; struct cam_req_mgr_core_dev_link_setup link_data; @@ -2446,10 +2446,16 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, struct cam_req_mgr_req_tbl *pd_tbl; enum cam_pipeline_delay max_delay; uint32_t subscribe_event = 0; - - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) - return -EPERM; - + if (link_info->version == VERSION_1) { + if (link_info->u.link_info_v1.num_devices > + CAM_REQ_MGR_MAX_HANDLES) + return -EPERM; + } + else if (link_info->version == VERSION_2) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) + return -EPERM; + } mutex_init(&link->req.lock); CAM_DBG(CAM_CRM, "LOCK_DBG in_q lock %pK", &link->req.lock); link->req.num_tbl = 0; @@ -2459,11 +2465,12 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, return rc; max_delay = CAM_PIPELINE_DELAY_0; - for (i = 0; i < link_info->num_devices; i++) { + for (i = 0; i < link_info->u.link_info_v1.num_devices; i++) { dev = &link->l_dev[i]; /* Using dev hdl, get ops ptr to communicate with device */ dev->ops = (struct cam_req_mgr_kmd_ops *) - cam_get_device_ops(link_info->dev_hdls[i]); + cam_get_device_ops( + link_info->u.link_info_v1.dev_hdls[i]); if (!dev->ops || !dev->ops->get_dev_info || !dev->ops->link_setup) { @@ -2471,7 +2478,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, rc = -ENXIO; goto error; } - dev->dev_hdl = link_info->dev_hdls[i]; + dev->dev_hdl = link_info->u.link_info_v1.dev_hdls[i]; dev->parent = (void *)link; dev->dev_info.dev_hdl = dev->dev_hdl; rc = dev->ops->get_dev_info(&dev->dev_info); @@ -2480,7 +2487,8 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, CAM_DBG(CAM_CRM, "%x: connected: %s, id %d, delay %d, trigger %x", - link_info->session_hdl, dev->dev_info.name, + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, dev->dev_info.dev_id, dev->dev_info.p_delay, dev->dev_info.trigger); if (rc < 0 || @@ -2492,7 +2500,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, goto error; } else { CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", - link_info->session_hdl, + link_info->u.link_info_v1.session_hdl, dev->dev_info.name, dev->dev_info.p_delay); if (dev->dev_info.p_delay > max_delay) @@ -2509,7 +2517,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, link_data.max_delay = max_delay; link_data.subscribe_event = subscribe_event; - for (i = 0; i < link_info->num_devices; i++) { + for (i = 0; i < link_info->u.link_info_v1.num_devices; i++) { dev = &link->l_dev[i]; link_data.dev_hdl = dev->dev_hdl; @@ -2552,7 +2560,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, if (link->max_delay < dev->dev_info.p_delay) link->max_delay = dev->dev_info.p_delay; } - link->num_devs = link_info->num_devices; + link->num_devs = link_info->u.link_info_v1.num_devices; /* Assign id for pd tables */ __cam_req_mgr_tbl_set_id(link->req.l_tbl, &link->req); @@ -2710,7 +2718,115 @@ int cam_req_mgr_destroy_session( return rc; } -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) +{ + int rc = 0; + int wq_flag = 0; + char buf[128]; + struct cam_create_dev_hdl root_dev; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!link_info) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + if (link_info->u.link_info_v1.num_devices > CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->u.link_info_v1.num_devices); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->u.link_info_v1.session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* Allocate link struct and map it with session's request queue */ + link = __cam_req_mgr_reserve_link(cam_session); + if (!link) { + CAM_ERR(CAM_CRM, "failed to reserve new link"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); + + memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); + root_dev.session_hdl = link_info->u.link_info_v1.session_hdl; + root_dev.priv = (void *)link; + + mutex_lock(&link->lock); + /* Create unique dev handle for link */ + link->link_hdl = cam_create_device_hdl(&root_dev); + if (link->link_hdl < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new device handle"); + rc = link->link_hdl; + goto link_hdl_fail; + } + link_info->u.link_info_v1.link_hdl = link->link_hdl; + link->last_flush_id = 0; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->u.link_info_v1.num_devices); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new crm subdevs"); + goto create_subdev_failed; + } + + /* Using device ops query connected devs, prepare request tables */ + rc = __cam_req_mgr_setup_link_info(link, link_info); + if (rc < 0) + goto setup_failed; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); + + /* Create worker for current link */ + snprintf(buf, sizeof(buf), "%x-%x", + link_info->u.link_info_v1.session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + if (rc < 0) { + CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); + __cam_req_mgr_destroy_link_info(link); + goto setup_failed; + } + + /* Assign payload to workqueue tasks */ + rc = __cam_req_mgr_setup_payload(link->workq); + if (rc < 0) { + __cam_req_mgr_destroy_link_info(link); + cam_req_mgr_workq_destroy(&link->workq); + goto setup_failed; + } + + mutex_unlock(&link->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +setup_failed: + __cam_req_mgr_destroy_subdev(link->l_dev); +create_subdev_failed: + cam_destroy_device_hdl(link->link_hdl); + link_info->u.link_info_v1.link_hdl = -1; +link_hdl_fail: + mutex_unlock(&link->lock); + __cam_req_mgr_unreserve_link(cam_session, link); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) { int rc = 0; int wq_flag = 0; @@ -2723,9 +2839,10 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "NULL pointer"); return -EINVAL; } - if (link_info->num_devices > CAM_REQ_MGR_MAX_HANDLES) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) { CAM_ERR(CAM_CRM, "Invalid num devices %d", - link_info->num_devices); + link_info->u.link_info_v2.num_devices); return -EINVAL; } @@ -2733,7 +2850,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) - cam_get_device_priv(link_info->session_hdl); + cam_get_device_priv(link_info->u.link_info_v2.session_hdl); if (!cam_session) { CAM_DBG(CAM_CRM, "NULL pointer"); mutex_unlock(&g_crm_core_dev->crm_lock); @@ -2750,7 +2867,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); - root_dev.session_hdl = link_info->session_hdl; + root_dev.session_hdl = link_info->u.link_info_v2.session_hdl; root_dev.priv = (void *)link; mutex_lock(&link->lock); @@ -2762,12 +2879,12 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) rc = link->link_hdl; goto link_hdl_fail; } - link_info->link_hdl = link->link_hdl; + link_info->u.link_info_v2.link_hdl = link->link_hdl; link->last_flush_id = 0; /* Allocate memory to hold data of all linked devs */ rc = __cam_req_mgr_create_subdevs(&link->l_dev, - link_info->num_devices); + link_info->u.link_info_v2.num_devices); if (rc < 0) { CAM_ERR(CAM_CRM, "Insufficient memory to create new crm subdevs"); @@ -2785,7 +2902,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* Create worker for current link */ snprintf(buf, sizeof(buf), "%x-%x", - link_info->session_hdl, link->link_hdl); + link_info->u.link_info_v2.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); @@ -2810,7 +2927,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) __cam_req_mgr_destroy_subdev(link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); - link_info->link_hdl = -1; + link_info->u.link_info_v2.link_hdl = -1; link_hdl_fail: mutex_unlock(&link->lock); __cam_req_mgr_unreserve_link(cam_session, link); @@ -2818,6 +2935,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) return rc; } + int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) { int rc = 0; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 9a6acbc2c43e..8eb15bec802d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -31,6 +31,9 @@ #define MAXIMUM_RETRY_ATTEMPTS 3 +#define VERSION_1 1 +#define VERSION_2 2 + /** * enum crm_workq_task_type * @codes: to identify which type of task is present @@ -408,7 +411,9 @@ int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info); * a unique link handle for the link and is specific to a * session. Returns link handle */ -int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info); +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info); +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info); + /** * cam_req_mgr_unlink() diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 74d5cfff8d60..b1a05cc14b9a 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include @@ -261,27 +261,50 @@ static long cam_private_ioctl(struct file *file, void *fh, break; case CAM_REQ_MGR_LINK: { - struct cam_req_mgr_link_info link_info; + struct cam_req_mgr_ver_info ver_info; - if (k_ioctl->size != sizeof(link_info)) + if (k_ioctl->size != sizeof(ver_info.u.link_info_v1)) return -EINVAL; - if (copy_from_user(&link_info, + if (copy_from_user(&ver_info.u.link_info_v1, u64_to_user_ptr(k_ioctl->handle), sizeof(struct cam_req_mgr_link_info))) { return -EFAULT; } - - rc = cam_req_mgr_link(&link_info); + ver_info.version = VERSION_1; + rc = cam_req_mgr_link(&ver_info); if (!rc) if (copy_to_user( u64_to_user_ptr(k_ioctl->handle), - &link_info, + &ver_info.u.link_info_v1, sizeof(struct cam_req_mgr_link_info))) rc = -EFAULT; } break; + case CAM_REQ_MGR_LINK_V2: { + struct cam_req_mgr_ver_info ver_info; + + if (k_ioctl->size != sizeof(ver_info.u.link_info_v2)) + return -EINVAL; + + if (copy_from_user(&ver_info.u.link_info_v2, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_info_v2))) { + return -EFAULT; + } + + ver_info.version = VERSION_2; + rc = cam_req_mgr_link_v2(&ver_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ver_info.u.link_info_v2, + sizeof(struct cam_req_mgr_link_info_v2))) + rc = -EFAULT; + } + break; + case CAM_REQ_MGR_UNLINK: { struct cam_req_mgr_unlink_info unlink_info; diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index f495eb883fcd..a8c12e2d7c0d 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_LINUX_CAM_REQ_MGR_H @@ -40,6 +40,7 @@ * It includes both session and device handles */ #define CAM_REQ_MGR_MAX_HANDLES 64 +#define CAM_REQ_MGR_MAX_HANDLES_V2 128 #define MAX_LINKS_PER_SESSION 2 /* V4L event type which user space will subscribe to */ @@ -126,6 +127,20 @@ struct cam_req_mgr_link_info { int32_t link_hdl; }; +struct cam_req_mgr_link_info_v2 { + int32_t session_hdl; + uint32_t num_devices; + int32_t dev_hdls[CAM_REQ_MGR_MAX_HANDLES_V2]; + int32_t link_hdl; +}; + +struct cam_req_mgr_ver_info { + uint32_t version; + union { + struct cam_req_mgr_link_info link_info_v1; + struct cam_req_mgr_link_info_v2 link_info_v2; + } u; +}; /** * struct cam_req_mgr_unlink_info * @session_hdl: input param - session handle @@ -235,6 +250,7 @@ struct cam_req_mgr_link_control { #define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11) #define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) #define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) +#define CAM_REQ_MGR_LINK_V2 (CAM_COMMON_OPCODE_MAX + 14) /* end of cam_req_mgr opcodes */ #define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) -- GitLab From aa0f96d02cdf7dbc41b3346fa8312cad23b9f2a6 Mon Sep 17 00:00:00 2001 From: Mangalaram ARCHANA Date: Fri, 31 May 2019 12:01:37 +0530 Subject: [PATCH 035/410] msm: camera: crm: Handle link setup based on version With the increase in the device handles, the corresponding link info structure is changed. Handle setting up link based on the right structure version. Change-Id: I0d21866ba0bc4abfe78941e191688773441ce03f Signed-off-by: Mangalaram ARCHANA Signed-off-by: Jigarkumar Zala --- drivers/cam_req_mgr/cam_req_mgr_core.c | 65 ++++++++++++++++++-------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index f4867d5d828e..a9edecc44ab4 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2440,7 +2440,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, struct cam_req_mgr_ver_info *link_info) { - int rc = 0, i = 0; + int rc = 0, i = 0, num_devices = 0; struct cam_req_mgr_core_dev_link_setup link_data; struct cam_req_mgr_connected_device *dev; struct cam_req_mgr_req_tbl *pd_tbl; @@ -2465,12 +2465,21 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, return rc; max_delay = CAM_PIPELINE_DELAY_0; - for (i = 0; i < link_info->u.link_info_v1.num_devices; i++) { + if (link_info->version == VERSION_1) + num_devices = link_info->u.link_info_v1.num_devices; + else if (link_info->version == VERSION_2) + num_devices = link_info->u.link_info_v2.num_devices; + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; /* Using dev hdl, get ops ptr to communicate with device */ - dev->ops = (struct cam_req_mgr_kmd_ops *) - cam_get_device_ops( - link_info->u.link_info_v1.dev_hdls[i]); + if (link_info->version == VERSION_1) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v1.dev_hdls[i]); + else if (link_info->version == VERSION_2) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v2.dev_hdls[i]); if (!dev->ops || !dev->ops->get_dev_info || !dev->ops->link_setup) { @@ -2478,19 +2487,29 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, rc = -ENXIO; goto error; } - dev->dev_hdl = link_info->u.link_info_v1.dev_hdls[i]; + if (link_info->version == VERSION_1) + dev->dev_hdl = link_info->u.link_info_v1.dev_hdls[i]; + else if (link_info->version == VERSION_2) + dev->dev_hdl = link_info->u.link_info_v2.dev_hdls[i]; dev->parent = (void *)link; dev->dev_info.dev_hdl = dev->dev_hdl; rc = dev->ops->get_dev_info(&dev->dev_info); trace_cam_req_mgr_connect_device(link, &dev->dev_info); - - CAM_DBG(CAM_CRM, - "%x: connected: %s, id %d, delay %d, trigger %x", - link_info->u.link_info_v1.session_hdl, - dev->dev_info.name, - dev->dev_info.dev_id, dev->dev_info.p_delay, - dev->dev_info.trigger); + if (link_info->version == VERSION_1) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); + else if (link_info->version == VERSION_2) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); if (rc < 0 || dev->dev_info.p_delay >= CAM_PIPELINE_DELAY_MAX || @@ -2499,10 +2518,18 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, CAM_ERR(CAM_CRM, "get device info failed"); goto error; } else { - CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", - link_info->u.link_info_v1.session_hdl, - dev->dev_info.name, - dev->dev_info.p_delay); + if (link_info->version == VERSION_1) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } + else if (link_info->version == VERSION_2) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } if (dev->dev_info.p_delay > max_delay) max_delay = dev->dev_info.p_delay; @@ -2517,7 +2544,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, link_data.max_delay = max_delay; link_data.subscribe_event = subscribe_event; - for (i = 0; i < link_info->u.link_info_v1.num_devices; i++) { + for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; link_data.dev_hdl = dev->dev_hdl; @@ -2560,7 +2587,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, if (link->max_delay < dev->dev_info.p_delay) link->max_delay = dev->dev_info.p_delay; } - link->num_devs = link_info->u.link_info_v1.num_devices; + link->num_devs = num_devices; /* Assign id for pd tables */ __cam_req_mgr_tbl_set_id(link->req.l_tbl, &link->req); -- GitLab From a89607a875135eec2c179dbc094b7fd444d9b574 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 11 Jul 2019 20:15:40 +0800 Subject: [PATCH 036/410] Camera: sensor: Power off the sensor if no gpios Power off the sensor if no gpios at the time of power on, since some regulator and clk need to be released. Change-Id: Ie200459276b5327a1627e8839ec404c3c26f4205 Signed-off-by: Depeng Shao Signed-off-by: Jigarkumar Zala --- drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 4a2a2a8855b2..f5ea2dc04a3d 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1658,7 +1658,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, case SENSOR_CUSTOM_GPIO2: if (no_gpio) { CAM_ERR(CAM_SENSOR, "request gpio failed"); - return no_gpio; + goto power_up_failed; } if (!gpio_num_info) { CAM_ERR(CAM_SENSOR, "Invalid gpio_num_info"); -- GitLab From f458d1d231787b9ec53a1c8551d098d9b9cbe7d5 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 6 Aug 2019 10:46:50 -0700 Subject: [PATCH 037/410] msm: camera: isp: Add support for QCFA CSID binning Add support to configure CSID binning for QCFA. Change-Id: I9e2673d89f521a4b4fddc41ad1217ffe229d8b01 Signed-off-by: Tejas Prajapati Signed-off-by: Trishansh Bhardwaj Signed-off-by: Jigarkumar Zala --- drivers/cam_cpas/cam_cpas_intf.c | 27 ++++++++ drivers/cam_cpas/cam_cpas_soc.c | 42 ++++++++++++ drivers/cam_cpas/cam_cpas_soc.h | 2 + drivers/cam_cpas/include/cam_cpas_api.h | 13 ++++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 68 +++++++++++++++++++ .../isp_hw/ife_csid_hw/cam_ife_csid175_200.h | 3 +- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 29 ++++++++ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 4 ++ .../isp_hw/include/cam_ife_csid_hw_intf.h | 9 +++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + 10 files changed, 197 insertions(+), 1 deletion(-) diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index e43d9f01ec2c..d1b32a0d916a 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -12,9 +12,11 @@ #include #include #include +#include #include "cam_subdev.h" #include "cam_cpas_hw_intf.h" +#include "cam_cpas_soc.h" #define CAM_CPAS_DEV_NAME "cam-cpas" #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done) @@ -104,6 +106,31 @@ const char *cam_cpas_axi_util_trans_type_to_string( } EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string); +int cam_cpas_is_feature_supported(uint32_t flag) +{ + struct cam_hw_info *cpas_hw = NULL; + struct cam_cpas_private_soc *soc_private = NULL; + uint32_t feature_mask; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv; + soc_private = + (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private; + feature_mask = soc_private->feature_mask; + + if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) { + CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag); + return -EINVAL; + } + + return feature_mask & flag ? 1 : 0; +} +EXPORT_SYMBOL(cam_cpas_is_feature_supported); + int cam_cpas_get_cpas_hw_version(uint32_t *hw_version) { struct cam_hw_info *cpas_hw = NULL; diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index 6c34dd0687e6..c86753dd24d9 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -349,6 +349,45 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, return 0; } + +int cam_cpas_get_hw_features(struct platform_device *pdev, + struct cam_cpas_private_soc *soc_private) +{ + struct device_node *of_node; + void *fuse; + uint32_t fuse_addr, fuse_bit; + uint32_t fuse_val = 0, feature_bit_pos; + int count = 0, i = 0; + + of_node = pdev->dev.of_node; + count = of_property_count_u32_elems(of_node, "cam_hw_fuse"); + + for (i = 0; (i + 3) <= count; i = i + 3) { + of_property_read_u32_index(of_node, "cam_hw_fuse", i, + &feature_bit_pos); + of_property_read_u32_index(of_node, "cam_hw_fuse", i + 1, + &fuse_addr); + of_property_read_u32_index(of_node, "cam_hw_fuse", i + 2, + &fuse_bit); + CAM_INFO(CAM_CPAS, "feature_bit 0x%x addr 0x%x, bit %d", + feature_bit_pos, fuse_addr, fuse_bit); + + fuse = ioremap(fuse_addr, 4); + if (fuse) { + fuse_val = cam_io_r(fuse); + if (fuse_val & BIT(fuse_bit)) + soc_private->feature_mask |= feature_bit_pos; + else + soc_private->feature_mask &= ~feature_bit_pos; + } + CAM_INFO(CAM_CPAS, "fuse %pK, fuse_val %x, feature_mask %x", + fuse, fuse_val, soc_private->feature_mask); + + } + + return 0; +} + int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, struct platform_device *pdev, struct cam_cpas_private_soc *soc_private) { @@ -363,6 +402,7 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, } of_node = pdev->dev.of_node; + soc_private->feature_mask = 0xFFFFFFFF; rc = of_property_read_string(of_node, "arch-compat", &soc_private->arch_compat); @@ -372,6 +412,8 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, return rc; } + cam_cpas_get_hw_features(pdev, soc_private); + soc_private->camnoc_axi_min_ib_bw = 0; rc = of_property_read_u64(of_node, "camnoc-axi-min-ib-bw", diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index 7921cd4b956e..fea9c3c97593 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -87,6 +87,7 @@ struct cam_cpas_tree_node { * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating * camnoc axi clock * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target + * @feature_mask: feature mask value for hw supported features * */ struct cam_cpas_private_soc { @@ -103,6 +104,7 @@ struct cam_cpas_private_soc { uint32_t camnoc_bus_width; uint32_t camnoc_axi_clk_bw_margin; uint64_t camnoc_axi_min_ib_bw; + uint32_t feature_mask; }; void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 1126053e2b33..7c551dfcf8a5 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -525,6 +525,19 @@ int cam_cpas_get_hw_info( int cam_cpas_get_cpas_hw_version( uint32_t *hw_version); +/** + * cam_cpas_is_feature_supported() + * + * @brief: API to get camera features + * + * @flag : Camera hw features to check + * + * @return 1 if feature is supported + * + */ +int cam_cpas_is_feature_supported( + uint32_t flag); + /** * cam_cpas_axi_util_path_type_to_string() * diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 75f157f0d5b8..e58a965492da 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -4236,6 +4236,54 @@ static int cam_isp_blob_csid_clock_update( return rc; } +static int cam_isp_blob_csid_qcfa_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_csid_qcfa_config *qcfa_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_csid_qcfa_update_args csid_qcfa_upd_args; + int rc = -EINVAL; + uint32_t i; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_ISP, + "csid binning=%d", qcfa_config->csid_binning); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + + if (!hw_mgr_res->hw_res[i] || + hw_mgr_res->res_id != CAM_IFE_PIX_PATH_RES_IPP) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + csid_qcfa_upd_args.qcfa_binning = + qcfa_config->csid_binning; + CAM_DBG(CAM_ISP, "i= %d QCFA binning=%d\n", + i, csid_qcfa_upd_args.qcfa_binning); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, + &csid_qcfa_upd_args, + sizeof( + struct cam_ife_csid_qcfa_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "QCFA Update failed"); + } else + CAM_ERR(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + static int cam_isp_blob_core_cfg_update( uint32_t blob_type, struct cam_isp_generic_blob_info *blob_info, @@ -4848,6 +4896,26 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, clock_config, prepare); if (rc) CAM_ERR(CAM_ISP, "Clock Update Failed"); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG: { + struct cam_isp_csid_qcfa_config *qcfa_config; + + if (blob_size < sizeof(struct cam_isp_csid_qcfa_config)) { + CAM_ERR(CAM_ISP, + "Invalid qcfa blob size %u expected %u", + blob_size, + sizeof(struct cam_isp_csid_qcfa_config)); + return -EINVAL; + } + + qcfa_config = (struct cam_isp_csid_qcfa_config *)blob_data; + + rc = cam_isp_blob_csid_qcfa_update(blob_type, blob_info, + qcfa_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "QCFA Update Failed rc: %d", rc); + } break; case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h index 7d47da31e4a8..869fd8cd61c9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_175_200_H_ @@ -47,6 +47,7 @@ static struct cam_ife_csid_pxl_reg_offset /* configurations */ .pix_store_en_shift_val = 7, .early_eof_en_shift_val = 29, + .quad_cfa_bin_en_shift_val = 30, .ccif_violation_en = 1, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 252c1a5aa36a..9503f204d410 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -8,6 +8,8 @@ #include #include +#include + #include "cam_ife_csid_core.h" #include "cam_isp_hw.h" #include "cam_soc_util.h" @@ -1611,6 +1613,10 @@ static int cam_ife_csid_init_config_pxl_path( val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val); } + if (is_ipp && csid_hw->binning_supported && + csid_hw->binning_enable) + val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val); + val |= (1 << pxl_reg->pix_store_en_shift_val); cam_io_w_mb(val, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_cfg0_addr); @@ -3124,6 +3130,23 @@ static int cam_ife_csid_set_csid_clock( return 0; } +static int cam_ife_csid_set_csid_qcfa( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_ife_csid_qcfa_update_args *qcfa_update = NULL; + + if (!csid_hw) + return -EINVAL; + + qcfa_update = + (struct cam_ife_csid_qcfa_update_args *)cmd_args; + + csid_hw->binning_supported = qcfa_update->qcfa_binning; + CAM_DBG(CAM_ISP, "CSID QCFA binning %d", csid_hw->binning_supported); + + return 0; +} + static int cam_ife_csid_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -3158,6 +3181,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED: + rc = cam_ife_csid_set_csid_qcfa(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); @@ -3601,6 +3627,9 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, goto err; } + if (cam_cpas_is_feature_supported(CAM_CPAS_QCFA_BINNING_ENABLE) == 1) + ife_csid_hw->binning_enable = 1; + ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps; ife_csid_hw->hw_intf->hw_ops.init = cam_ife_csid_init_hw; ife_csid_hw->hw_intf->hw_ops.deinit = cam_ife_csid_deinit_hw; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 3e998858b596..d4a3a840d969 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -482,6 +482,8 @@ struct cam_ife_csid_path_cfg { * @irq_debug_cnt: Counter to track sof irq's when above flag is set. * @error_irq_count Error IRQ count, if continuous error irq comes * need to stop the CSID and mask interrupts. + * @binning_enable Flag is set if hardware supports QCFA binning + * @binning_supported Flag is set if sensor supports QCFA binning * */ struct cam_ife_csid_hw { @@ -510,6 +512,8 @@ struct cam_ife_csid_hw { uint32_t error_irq_count; uint32_t device_enabled; spinlock_t lock_state; + uint32_t binning_enable; + uint32_t binning_supported; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index d8ba811c7ad5..e31cddc91b11 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -222,5 +222,14 @@ struct cam_ife_csid_clock_update_args { uint64_t clk_rate; }; +/* + * struct cam_ife_csid_qcfa_update_args: + * + * @qcfa_binning: QCFA binning supported + */ +struct cam_ife_csid_qcfa_update_args { + uint32_t qcfa_binning; +}; + #endif /* _CAM_CSID_HW_INTF_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 33254c1610ae..1e556137996d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -100,6 +100,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_UBWC_UPDATE_V2, CAM_ISP_HW_CMD_CORE_CONFIG, CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, + CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, CAM_ISP_HW_CMD_MAX, }; -- GitLab From 45125cf020684446ee66753750ce138e3dee581b Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Fri, 19 Jul 2019 18:26:35 +0530 Subject: [PATCH 038/410] msm: camera: Fuse base secure camera enablement Query secure camera capability from fuse, and enable only if supported. Change-Id: I4ff3c5afbf7c924368c95af5517a047149124c3e Signed-off-by: Trishansh Bhardwaj Signed-off-by: Jigarkumar Zala --- .../cam_sensor_module/cam_csiphy/cam_csiphy_core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index adf9ef82ee45..f4bdfff2cb97 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -10,9 +10,11 @@ #include "cam_common_util.h" #include "cam_packet_util.h" +#include #include #include +#include #define SCM_SVC_CAMERASS 0x18 #define SECURE_SYSCALL_ID 0x6 @@ -914,6 +916,15 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, } if (csiphy_dev->csiphy_info.secure_mode[offset] == 1) { + if (cam_cpas_is_feature_supported( + CAM_CPAS_SECURE_CAMERA_ENABLE) != 1) { + CAM_ERR(CAM_CSIPHY, + "sec_cam: camera fuse bit not set"); + cam_cpas_stop(csiphy_dev->cpas_handle); + rc = -1; + goto release_mutex; + } + rc = cam_csiphy_notify_secure_mode( csiphy_dev, CAM_SECURE_MODE_SECURE, offset); -- GitLab From a6efb05c3ffe97f2bd234f695870a5525249bb2d Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 17 Jul 2019 17:24:18 -0700 Subject: [PATCH 039/410] msm: camera: isp: Move req out of pending list before start This change moves init request out of pending list before starting hardware. Currently if we receive the first SOF and RUP IRQs before start_dev routine has completed, we miss pushing out the init request to free list on the first RUP as wait list will be empty. Change-Id: Icd53e0ebe0d12e264172058d836e6ccfcb7df0c2 Signed-off-by: Venkat Chinta Signed-off-by: Jigarkumar Zala --- drivers/cam_isp/cam_isp_context.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 84f5e4937a9e..9c0d4d6c2817 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3368,6 +3368,21 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, goto end; } + /* + * In case of CSID TPG we might receive SOF and RUP IRQs + * before hw_mgr_intf->hw_start has returned. So move + * req out of pending list before hw_start and add it + * back to pending list if hw_start fails. + */ + list_del_init(&req->list); + + if (req_isp->num_fence_map_out) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + } else { + list_add_tail(&req->list, &ctx->wait_req_list); + } + start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; start_isp.hw_config.request_id = req->request_id; start_isp.hw_config.hw_update_entries = req_isp->cfg; @@ -3401,18 +3416,12 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, CAM_ERR(CAM_ISP, "Start HW failed"); ctx->state = CAM_CTX_READY; trace_cam_context_state("ISP", ctx); + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); goto end; } CAM_DBG(CAM_ISP, "start device success ctx %u", ctx->ctx_id); - list_del_init(&req->list); - - if (req_isp->num_fence_map_out) { - list_add_tail(&req->list, &ctx->active_req_list); - ctx_isp->active_req_cnt++; - } else { - list_add_tail(&req->list, &ctx->wait_req_list); - } end: return rc; } -- GitLab From 306cc41267d5d5373fc3900df936f1daabd8010a Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 9 Jul 2019 16:44:28 -0700 Subject: [PATCH 040/410] msm: camera: Dynamic update of scalable clock This change updates the scalable clock based on hw src clock. Also, removed cam_soc_util_get_vote_level() as it is duplicating the functionality with cam_soc_util_get_clk_level() api. Change-Id: I001264d150849770ef664ecc206a66f8a4f54412 Signed-off-by: Jigarkumar Zala --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 18 ++- drivers/cam_utils/cam_soc_util.c | 153 +++++++++++++----- drivers/cam_utils/cam_soc_util.h | 8 +- 3 files changed, 133 insertions(+), 46 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 9503f204d410..c48d320d0945 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1084,9 +1084,10 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) { int rc = 0; - const struct cam_ife_csid_reg_offset *csid_reg; - struct cam_hw_soc_info *soc_info; - uint32_t i, val, clk_lvl; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t i, val; + int clk_lvl; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -1108,8 +1109,15 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d init CSID HW", csid_hw->hw_intf->hw_idx); - clk_lvl = cam_soc_util_get_vote_level(soc_info, csid_hw->clk_rate); - CAM_DBG(CAM_ISP, "CSID clock lvl %u", clk_lvl); + rc = cam_soc_util_get_clk_level(soc_info, csid_hw->clk_rate, + soc_info->src_clk_idx, &clk_lvl); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get clk level for rate %d", + csid_hw->clk_rate); + goto err; + } + + CAM_DBG(CAM_ISP, "CSID clock lvl %d", clk_lvl); rc = cam_ife_csid_enable_soc_resources(soc_info, clk_lvl); if (rc) { diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 4f031ee720b0..e32a6ab21665 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -15,30 +15,41 @@ static char supported_clk_info[256]; static char debugfs_dir_name[64]; -static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t src_clk_idx, int32_t clk_rate) +int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, + int32_t clk_rate, int clk_idx, int32_t *clk_lvl) { int i; long clk_rate_round; - clk_rate_round = clk_round_rate(soc_info->clk[src_clk_idx], clk_rate); + if (!soc_info || (clk_idx < 0) || (clk_idx >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid src_clk_idx: %d", clk_idx); + *clk_lvl = -1; + return -EINVAL; + } + + clk_rate_round = clk_round_rate(soc_info->clk[clk_idx], clk_rate); if (clk_rate_round < 0) { CAM_ERR(CAM_UTIL, "round failed rc = %ld", clk_rate_round); + *clk_lvl = -1; return -EINVAL; } for (i = 0; i < CAM_MAX_VOTE; i++) { - if (soc_info->clk_rate[i][src_clk_idx] >= clk_rate_round) { + if ((soc_info->clk_level_valid[i]) && + (soc_info->clk_rate[i][clk_idx] >= + clk_rate_round)) { CAM_DBG(CAM_UTIL, "soc = %d round rate = %ld actual = %d", - soc_info->clk_rate[i][src_clk_idx], + soc_info->clk_rate[i][clk_idx], clk_rate_round, clk_rate); - return i; + *clk_lvl = i; + return 0; } } CAM_WARN(CAM_UTIL, "Invalid clock rate %ld", clk_rate_round); + *clk_lvl = -1; return -EINVAL; } @@ -426,13 +437,20 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, int32_t clk_rate) { + int rc = 0; + int i = 0; int32_t src_clk_idx; + int32_t scl_clk_idx; struct clk *clk = NULL; int32_t apply_level; uint32_t clk_level_override = 0; - if (!soc_info || (soc_info->src_clk_idx < 0)) + if (!soc_info || (soc_info->src_clk_idx < 0) || + (soc_info->src_clk_idx >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid src_clk_idx: %d", + soc_info ? soc_info->src_clk_idx : -1); return -EINVAL; + } src_clk_idx = soc_info->src_clk_idx; clk_level_override = soc_info->clk_level_override; @@ -441,21 +459,57 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, soc_info->clk_rate[clk_level_override][src_clk_idx]; clk = soc_info->clk[src_clk_idx]; - - if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { - apply_level = cam_soc_util_get_clk_level(soc_info, src_clk_idx, - clk_rate); - CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s\n" - "apply level = %d", + rc = cam_soc_util_get_clk_level(soc_info, clk_rate, src_clk_idx, + &apply_level); + if (rc || (apply_level < 0) || (apply_level >= CAM_MAX_VOTE)) { + CAM_ERR(CAM_UTIL, + "set %s, rate %d dev_name = %s apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); - if (apply_level >= 0) - cam_cx_ipeak_update_vote_cx_ipeak(soc_info, - apply_level); + return -EINVAL; } - return cam_soc_util_set_clk_rate(clk, + + CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s apply level = %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, apply_level); + + if ((soc_info->cam_cx_ipeak_enable) && (clk_rate >= 0)) { + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, + apply_level); + } + + rc = cam_soc_util_set_clk_rate(clk, soc_info->clk_name[src_clk_idx], clk_rate); + if (rc) { + CAM_ERR(CAM_UTIL, + "SET_RATE Failed: src clk: %s, rate %d, dev_name = %s rc: %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, rc); + return rc; + } + + /* set clk rate for scalable clk if available */ + for (i = 0; i < soc_info->scl_clk_count; i++) { + scl_clk_idx = soc_info->scl_clk_idx[i]; + if (scl_clk_idx < 0) { + CAM_DBG(CAM_UTIL, "Scl clk index invalid"); + continue; + } + clk = soc_info->clk[scl_clk_idx]; + rc = cam_soc_util_set_clk_rate(clk, + soc_info->clk_name[scl_clk_idx], + soc_info->clk_rate[apply_level][scl_clk_idx]); + if (rc) { + CAM_WARN(CAM_UTIL, + "SET_RATE Failed: scl clk: %s, rate %d dev_name = %s, rc: %d", + soc_info->clk_name[scl_clk_idx], + soc_info->clk_rate[apply_level][scl_clk_idx], + soc_info->dev_name, rc); + } + } + + return 0; } int cam_soc_util_clk_put(struct clk **clk) @@ -686,6 +740,7 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) int i, j, rc; int32_t num_clk_level_strings; const char *src_clk_str = NULL; + const char *scl_clk_str = NULL; const char *clk_control_debugfs = NULL; const char *clk_cntl_lvl_string = NULL; enum cam_vote_level level; @@ -813,6 +868,48 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) } } + /* scalable clk info parsing */ + soc_info->scl_clk_count = 0; + soc_info->scl_clk_count = of_property_count_strings(of_node, + "scl-clk-names"); + if ((soc_info->scl_clk_count <= 0) || + (soc_info->scl_clk_count > CAM_SOC_MAX_CLK)) { + if (soc_info->scl_clk_count == -EINVAL) { + CAM_DBG(CAM_UTIL, "scl_clk_name prop not avialable"); + } else if ((soc_info->scl_clk_count == -ENODATA) || + (soc_info->scl_clk_count > CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid scl_clk_count: %d", + soc_info->scl_clk_count); + return -EINVAL; + } + CAM_DBG(CAM_UTIL, "Invalid scl_clk count: %d", + soc_info->scl_clk_count); + soc_info->scl_clk_count = -1; + } else { + CAM_DBG(CAM_UTIL, "No of scalable clocks: %d", + soc_info->scl_clk_count); + for (i = 0; i < soc_info->scl_clk_count; i++) { + rc = of_property_read_string_index(of_node, + "scl-clk-names", i, + (const char **)&scl_clk_str); + if (rc || !scl_clk_str) { + CAM_WARN(CAM_UTIL, "scl_clk_str is NULL"); + soc_info->scl_clk_idx[i] = -1; + continue; + } + for (j = 0; j < soc_info->num_clk; j++) { + if (strnstr(scl_clk_str, soc_info->clk_name[j], + strlen(scl_clk_str))) { + soc_info->scl_clk_idx[i] = j; + CAM_DBG(CAM_UTIL, + "scl clock = %s, index = %d", + scl_clk_str, j); + break; + } + } + } + } + rc = of_property_read_string_index(of_node, "clock-control-debugfs", 0, &clk_control_debugfs); if (rc || !clk_control_debugfs) { @@ -1728,25 +1825,3 @@ int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, return 0; } - -uint32_t cam_soc_util_get_vote_level(struct cam_hw_soc_info *soc_info, - uint64_t clock_rate) -{ - int i = 0; - - if (!clock_rate) - return CAM_SVS_VOTE; - - for (i = 0; i < CAM_MAX_VOTE; i++) { - if (soc_info->clk_level_valid[i] && - soc_info->clk_rate[i][soc_info->src_clk_idx] >= - clock_rate) { - CAM_DBG(CAM_UTIL, - "Clock rate %lld, selected clock level %d", - clock_rate, i); - return i; - } - } - - return CAM_TURBO_VOTE; -} diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index bfa6183bf739..2ddd4de2d86c 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -152,6 +152,8 @@ struct cam_soc_gpio_data { * @prev_clk_level Last vote level * @src_clk_idx: Source clock index that is rate-controllable * @clk_level_valid: Indicates whether corresponding level is valid + * @scl_clk_count: Number of scalable clocks present + * @scl_clk_idx: Index of scalable clocks * @gpio_data: Pointer to gpio info * @pinctrl_info: Pointer to pinctrl info * @dentry: Debugfs entry @@ -198,6 +200,8 @@ struct cam_hw_soc_info { int32_t prev_clk_level; int32_t src_clk_idx; bool clk_level_valid[CAM_MAX_VOTE]; + int32_t scl_clk_count; + int32_t scl_clk_idx[CAM_SOC_MAX_CLK]; struct cam_soc_gpio_data *gpio_data; struct cam_soc_pinctrl_info pinctrl_info; @@ -632,7 +636,7 @@ void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info); int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level); -uint32_t cam_soc_util_get_vote_level(struct cam_hw_soc_info *soc_info, - uint64_t clock_rate); +int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, + int32_t clk_rate, int clk_idx, int32_t *clk_lvl); #endif /* _CAM_SOC_UTIL_H_ */ -- GitLab From 82ee45360e1de6d7dccb81fa8a03a135d9b5a3cc Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Tue, 30 Jul 2019 04:11:17 -0700 Subject: [PATCH 041/410] Revert "msm: camera: icp: lock before updating clock status" This reverts commit 6094f6654bd6ddc7f6df54b19cb8e6697bf3111c. The change introduces a lock around a code that can cause sleep. It results in abnormal operation of camera functionality. Reverting this change will lead to original problem of stability. That need to be addressed. Change-Id: I3899d6992350bc466e89ee1ca1834a8a7fbd0269 Signed-off-by: Alok Pandey --- drivers/cam_icp/icp_hw/bps_hw/bps_core.c | 5 ----- drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c | 5 ----- 2 files changed, 10 deletions(-) diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c index 7deea1c94d84..73075a4ec379 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c @@ -306,7 +306,6 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, struct cam_bps_device_core_info *core_info = NULL; struct cam_bps_device_hw_info *hw_info = NULL; int rc = 0; - unsigned long flags; if (!device_priv) { CAM_ERR(CAM_ICP, "Invalid arguments"); @@ -396,16 +395,12 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, } break; case CAM_ICP_BPS_CMD_DISABLE_CLK: - spin_lock_irqsave(&bps_dev->hw_lock, flags); if (core_info->clk_enable == true) cam_bps_toggle_clk(soc_info, false); core_info->clk_enable = false; - spin_unlock_irqrestore(&bps_dev->hw_lock, flags); break; case CAM_ICP_BPS_CMD_RESET: - spin_lock_irqsave(&bps_dev->hw_lock, flags); rc = cam_bps_cmd_reset(soc_info, core_info); - spin_unlock_irqrestore(&bps_dev->hw_lock, flags); break; default: CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c index 614c748f0d85..82d0ebe54cc4 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -305,7 +305,6 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, struct cam_ipe_device_core_info *core_info = NULL; struct cam_ipe_device_hw_info *hw_info = NULL; int rc = 0; - unsigned long flags; if (!device_priv) { CAM_ERR(CAM_ICP, "Invalid arguments"); @@ -390,16 +389,12 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, } break; case CAM_ICP_IPE_CMD_DISABLE_CLK: - spin_lock_irqsave(&ipe_dev->hw_lock, flags); if (core_info->clk_enable == true) cam_ipe_toggle_clk(soc_info, false); core_info->clk_enable = false; - spin_unlock_irqrestore(&ipe_dev->hw_lock, flags); break; case CAM_ICP_IPE_CMD_RESET: - spin_lock_irqsave(&ipe_dev->hw_lock, flags); rc = cam_ipe_cmd_reset(soc_info, core_info); - spin_unlock_irqrestore(&ipe_dev->hw_lock, flags); break; default: CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); -- GitLab From 21c100461f35784510b2700fa0401017c893070f Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 6 Aug 2019 11:24:02 -0700 Subject: [PATCH 042/410] Camera: uapi: add uapi csiphy4 and csiphy5 support Add Uapi csiphy4 and csiphy5 support. Change-Id: Ie5d78a389f0cbc454fa261182a3d04030d13d307 Signed-off-by: Jigarkumar Zala --- include/uapi/media/cam_isp_ife.h | 6 ++++-- include/uapi/media/cam_isp_vfe.h | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/uapi/media/cam_isp_ife.h b/include/uapi/media/cam_isp_ife.h index 7ce826d94a78..34c1b3bd2bfe 100644 --- a/include/uapi/media/cam_isp_ife.h +++ b/include/uapi/media/cam_isp_ife.h @@ -46,7 +46,9 @@ #define CAM_ISP_IFE_IN_RES_PHY_1 (CAM_ISP_IFE_IN_RES_BASE + 2) #define CAM_ISP_IFE_IN_RES_PHY_2 (CAM_ISP_IFE_IN_RES_BASE + 3) #define CAM_ISP_IFE_IN_RES_PHY_3 (CAM_ISP_IFE_IN_RES_BASE + 4) -#define CAM_ISP_IFE_IN_RES_RD (CAM_ISP_IFE_IN_RES_BASE + 5) -#define CAM_ISP_IFE_IN_RES_MAX (CAM_ISP_IFE_IN_RES_BASE + 6) +#define CAM_ISP_IFE_IN_RES_PHY_4 (CAM_ISP_IFE_IN_RES_BASE + 5) +#define CAM_ISP_IFE_IN_RES_PHY_5 (CAM_ISP_IFE_IN_RES_BASE + 6) +#define CAM_ISP_IFE_IN_RES_RD (CAM_ISP_IFE_IN_RES_BASE + 7) +#define CAM_ISP_IFE_IN_RES_MAX (CAM_ISP_IFE_IN_RES_BASE + 8) #endif /* __UAPI_CAM_ISP_IFE_H__ */ diff --git a/include/uapi/media/cam_isp_vfe.h b/include/uapi/media/cam_isp_vfe.h index 5f9ce7a49108..497093902ba3 100644 --- a/include/uapi/media/cam_isp_vfe.h +++ b/include/uapi/media/cam_isp_vfe.h @@ -43,7 +43,9 @@ #define CAM_ISP_VFE_IN_RES_PHY_1 (CAM_ISP_VFE_IN_RES_BASE + 2) #define CAM_ISP_VFE_IN_RES_PHY_2 (CAM_ISP_VFE_IN_RES_BASE + 3) #define CAM_ISP_VFE_IN_RES_PHY_3 (CAM_ISP_VFE_IN_RES_BASE + 4) -#define CAM_ISP_VFE_IN_RES_FE (CAM_ISP_VFE_IN_RES_BASE + 5) -#define CAM_ISP_VFE_IN_RES_MAX (CAM_ISP_VFE_IN_RES_BASE + 6) +#define CAM_ISP_VFE_IN_RES_PHY_4 (CAM_ISP_VFE_IN_RES_BASE + 5) +#define CAM_ISP_VFE_IN_RES_PHY_5 (CAM_ISP_VFE_IN_RES_BASE + 6) +#define CAM_ISP_VFE_IN_RES_FE (CAM_ISP_VFE_IN_RES_BASE + 7) +#define CAM_ISP_VFE_IN_RES_MAX (CAM_ISP_VFE_IN_RES_BASE + 8) #endif /* __UAPI_CAM_ISP_VFE_H__ */ -- GitLab From 47f89a6efa85ab36e3c52ae05c185d8a6cdb2ab0 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 2 Apr 2019 15:54:37 -0700 Subject: [PATCH 043/410] camera: uapi: Add uapi support for semi real time device types Add uapi support for IPE/BPS semi real time device types. Change-Id: I12c733f51afdd70159f22f23be5967fc852549ca Signed-off-by: Jigarkumar Zala --- include/uapi/media/cam_icp.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h index 969de271e054..ac683bffa4ce 100644 --- a/include/uapi/media/cam_icp.h +++ b/include/uapi/media/cam_icp.h @@ -18,10 +18,13 @@ #define CAM_ICP_DEV_TYPE_MAX 5 /* definitions needed for icp aquire device */ -#define CAM_ICP_RES_TYPE_BPS 1 -#define CAM_ICP_RES_TYPE_IPE_RT 2 -#define CAM_ICP_RES_TYPE_IPE 3 -#define CAM_ICP_RES_TYPE_MAX 4 +#define CAM_ICP_RES_TYPE_BPS 1 +#define CAM_ICP_RES_TYPE_IPE_RT 2 +#define CAM_ICP_RES_TYPE_IPE 3 +#define CAM_ICP_RES_TYPE_IPE_SEMI_RT 4 +#define CAM_ICP_RES_TYPE_BPS_RT 5 +#define CAM_ICP_RES_TYPE_BPS_SEMI_RT 6 +#define CAM_ICP_RES_TYPE_MAX 7 /* packet opcode types */ #define CAM_ICP_OPCODE_IPE_UPDATE 0 -- GitLab From d31033b31fd92f6e7abc549d8c7b33151808a921 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 4 Jul 2019 15:03:06 +0530 Subject: [PATCH 044/410] Camera: uapi: Add uapi support for QCFA CSID binning Add uapi support to configure CSID binning for QCFA. Change-Id: Ic992c11d04319b6e8329963c032501b07002b484 Signed-off-by: Tejas Prajapati Signed-off-by: Trishansh Bhardwaj Signed-off-by: Jigarkumar Zala --- include/uapi/media/cam_isp.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 0191d2ced633..ee6440a90023 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -99,6 +99,7 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG 7 #define CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG 8 #define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 9 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG 12 #define CAM_ISP_VC_DT_CFG 4 @@ -491,6 +492,15 @@ struct cam_isp_csid_clock_config { uint64_t csid_clock; } __attribute__((packed)); +/** + * struct cam_isp_csid_qcfa_config - CSID qcfa binning support configuration + * + * @csid_binning CSID binning + */ +struct cam_isp_csid_qcfa_config { + uint32_t csid_binning; +} __attribute__((packed)); + /** * struct cam_isp_bw_vote - Bandwidth vote information * -- GitLab From ce61a07996fa8083d957c3214b0bdaf5e8325452 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 29 Jul 2019 14:02:31 -0700 Subject: [PATCH 045/410] msm: camera: Update uapi structure for OIS Userspace is sending slave address as 32bit, and in order to parse the correct data kernel space needs to match this bit pattern. This change updates the structure to accommodate it. Change-Id: Ib136bbd1656dba9da75d3b07c494caeebf03dfcb Signed-off-by: Jigarkumar Zala --- include/uapi/media/cam_sensor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h index 57a5c4674ca2..5e1918a9a116 100644 --- a/include/uapi/media/cam_sensor.h +++ b/include/uapi/media/cam_sensor.h @@ -132,7 +132,7 @@ struct cam_ois_opcode { * @opcode : opcode */ struct cam_cmd_ois_info { - uint16_t slave_addr; + uint32_t slave_addr; uint8_t i2c_freq_mode; uint8_t cmd_type; uint8_t ois_fw_flag; -- GitLab From 05b312bca9b6bc5fe32b6fcb47122dbec09f6f4c Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 9 Jul 2019 17:09:33 -0700 Subject: [PATCH 046/410] Camera: Add support for LITO target This change add config support for LITO target. Change-Id: Ia4a191c862f9886bb35fbd792ae786d027d5cc7e Signed-off-by: Jigarkumar Zala --- Makefile | 26 +++++++++++++++++++------- config/konacameraconf.h | 16 ++++++++-------- config/litocamera.conf | 4 ++++ config/litocameraconf.h | 7 +++++++ 4 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 config/litocamera.conf create mode 100644 config/litocameraconf.h diff --git a/Makefile b/Makefile index f844d98cbdc6..b7c0d7853cc7 100644 --- a/Makefile +++ b/Makefile @@ -5,19 +5,31 @@ ifeq ($(CONFIG_ARCH_KONA), y) include $(srctree)/techpack/camera/config/konacamera.conf endif +ifeq ($(CONFIG_ARCH_LITO), y) +include $(srctree)/techpack/camera/config/litocamera.conf +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/konacameraconf.h +endif + +ifeq ($(CONFIG_ARCH_LITO), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/litocameraconf.h +endif + +ifdef CONFIG_SPECTRA_CAMERA # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE += \ - -I$(srctree)/techpack/camera/include/uapi + -I$(srctree)/techpack/camera/include/uapi # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option LINUXINCLUDE += \ -I$(srctree)/techpack/camera/include/uapi \ -I$(srctree)/techpack/camera/include - -ifeq ($(CONFIG_ARCH_KONA), y) -LINUXINCLUDE += \ - -include $(srctree)/techpack/camera/config/konacameraconf.h -endif - obj-y += drivers/ +else +$(info Target not found) +endif diff --git a/config/konacameraconf.h b/config/konacameraconf.h index e0cf514fe3cf..875b95587ab6 100644 --- a/config/konacameraconf.h +++ b/config/konacameraconf.h @@ -1,8 +1,8 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. - */ - - -#define CONFIG_SPECTRA_CAMERA 1 - +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#define CONFIG_SPECTRA_CAMERA 1 + diff --git a/config/litocamera.conf b/config/litocamera.conf new file mode 100644 index 000000000000..451723eebce3 --- /dev/null +++ b/config/litocamera.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2019, The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA=y diff --git a/config/litocameraconf.h b/config/litocameraconf.h new file mode 100644 index 000000000000..1a7714018004 --- /dev/null +++ b/config/litocameraconf.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 + -- GitLab From b2bd543adf23a2a9dbae9e0b91afb3209b527820 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Wed, 31 Jul 2019 15:29:13 -0700 Subject: [PATCH 047/410] msm: camera: isp: Dump page fault info for pending request If bubble report is set from usersapce we move the active request back to pending request list while handling error. We need to iterate through pending request list as well when dumping page fault info for erroneous request. Change-Id: I2458313affbae6cb161f077eef7bdd0263c43ae2 Signed-off-by: Vishalsingh Hajeri Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_isp/cam_isp_context.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 9c0d4d6c2817..d88adebea4f7 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3876,6 +3876,36 @@ static int cam_isp_context_dump_active_request(void *data, unsigned long iova, req->request_id, rc); } + /* + * In certain scenarios we observe both overflow and SMMU pagefault + * for a particular request. If overflow is handled before page fault + * we need to traverse through pending request list because if + * bubble recovery is enabled on any request we move that request + * and all the subsequent requests to the pending list while handling + * overflow error. + */ + + CAM_INFO(CAM_ISP, + "Iterating over pending req list of isp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->pending_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + hw_update_data = &req_isp->hw_update_data; + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ISP, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &mem_found); + if (rc) + CAM_ERR(CAM_ISP, "Failed to dump pf info"); + + if (mem_found) + CAM_ERR(CAM_ISP, "Found page fault in req %lld %d", + req->request_id, rc); + } + return rc; } -- GitLab From 632d56473bfa029f5c53b71fb402979333a4b884 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Mon, 22 Jul 2019 12:33:17 -0700 Subject: [PATCH 048/410] msm: camera: Add uapi definitions for camera reg dump For debugging, there are a set of register values that user space needs. Based on the offset and range given, values can be dumped into an out buffer to be further processed. Add uapi support for this reg dump. Change-Id: I6e6f89625a505158a6bf8932ebb9d0ae78bf0129 Signed-off-by: Mukund Madhusudan Atre --- include/uapi/media/cam_defs.h | 114 ++++++++++++++++++++++++++++++++++ include/uapi/media/cam_isp.h | 29 +++++---- 2 files changed, 130 insertions(+), 13 deletions(-) diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index 8bc561314027..ce73b79f9590 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -219,6 +219,18 @@ struct cam_iommu_handle { #define CAM_PACKET_DEV_LRME 17 #define CAM_PACKET_DEV_MAX 18 +/* Register base type */ +#define CAM_REG_DUMP_BASE_TYPE_ISP_LEFT 1 +#define CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT 2 +#define CAM_REG_DUMP_BASE_TYPE_CAMNOC 3 + +/* Register dump read type */ +#define CAM_REG_DUMP_READ_TYPE_CONT_RANGE 1 +#define CAM_REG_DUMP_READ_TYPE_DMI 2 + +/* Max number of config writes to read from DMI */ +#define CAM_REG_DUMP_DMI_CONFIG_MAX 5 + /* constants */ #define CAM_PACKET_MAX_PLANES 3 @@ -742,5 +754,107 @@ struct cam_cmd_mem_regions { struct cam_cmd_mem_region_info map_info_array[1]; }; +/** + * struct cam_reg_write_desc - Register write descriptor + * + * @offset : Register offset at which 'value' needs to written + * @value : Register value to write + */ +struct cam_reg_write_desc { + uint32_t offset; + uint32_t value; +}; + +/** + * struct cam_reg_range_read_desc - Descriptor to provide read info + * + * @offset : Register offset address to start with + * @num_values : Number of values to read + */ +struct cam_reg_range_read_desc { + uint32_t offset; + uint32_t num_values; +}; + +/** + * struct cam_dmi_read_desc - Descriptor to provide DMI read info + * + * @num_pre_writes : Number of registers to write before reading DMI data + * @num_post_writes : Number of registers to write after reading DMI data + * @pre_read_config : Registers to write before reading DMI data + * @dmi_data_read : DMI Register, number of values to read to dump + * DMI data + * @post_read_config : Registers to write after reading DMI data + */ +struct cam_dmi_read_desc { + uint32_t num_pre_writes; + uint32_t num_post_writes; + struct cam_reg_write_desc pre_read_config[ + CAM_REG_DUMP_DMI_CONFIG_MAX]; + struct cam_reg_range_read_desc dmi_data_read; + struct cam_reg_write_desc post_read_config[ + CAM_REG_DUMP_DMI_CONFIG_MAX]; +}; + +/** + * struct cam_reg_read_info - Register read info for both reg continuous read + * or DMI read + * + * @type : Whether Register range read or DMI read + * @reg_read : Range of registers to read + * @dmi_read : DMI data to read + */ +struct cam_reg_read_info { + uint32_t type; + uint32_t reserved; + union { + struct cam_reg_range_read_desc reg_read; + struct cam_dmi_read_desc dmi_read; + }; +}; + +/** + * struct cam_reg_dump_out_buffer -Buffer info for dump data to be provided + * + * @req_id : Request ID corresponding to reg dump data + * @bytes_written : Number of bytes written + * @dump_data : Register dump data + */ +struct cam_reg_dump_out_buffer { + uint64_t req_id; + uint32_t bytes_written; + uint32_t dump_data[1]; +}; + +/** + * struct cam_reg_dump_desc - Descriptor to provide dump info + * + * @reg_base_type : Register base type, e.g. ISP_LEFT, ISP_RIGHT, CAMNOC + * @dump_buffer_offset : Offset from base of mem_handle at which Register dump + * will be written for this set + * @dump_buffer_size : Available size in bytes for writing dump values + * @num_read_range : Number register range reads (Continuous + DMI) + * @read_range : Read range info + */ +struct cam_reg_dump_desc { + uint32_t reg_base_type; + uint32_t dump_buffer_offset; + uint32_t dump_buffer_size; + uint32_t num_read_range; + struct cam_reg_read_info read_range[1]; +}; + +/** + * struct cam_reg_dump_input_info - Info about required dump sets + * + * @num_dump_sets : Number of different dump sets (base types) given + * @dump_set_offsets : Points to the given dump description structures + * (cam_reg_dump_desc) + */ +struct cam_reg_dump_input_info { + uint32_t num_dump_sets; + uint32_t dump_set_offsets[1]; +}; + #endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index ee6440a90023..03767466094f 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -69,19 +69,22 @@ #define CAM_ISP_PACKET_OP_MAX 3 /* ISP packet meta_data type for command buffer */ -#define CAM_ISP_PACKET_META_BASE 0 -#define CAM_ISP_PACKET_META_LEFT 1 -#define CAM_ISP_PACKET_META_RIGHT 2 -#define CAM_ISP_PACKET_META_COMMON 3 -#define CAM_ISP_PACKET_META_DMI_LEFT 4 -#define CAM_ISP_PACKET_META_DMI_RIGHT 5 -#define CAM_ISP_PACKET_META_DMI_COMMON 6 -#define CAM_ISP_PACKET_META_CLOCK 7 -#define CAM_ISP_PACKET_META_CSID 8 -#define CAM_ISP_PACKET_META_DUAL_CONFIG 9 -#define CAM_ISP_PACKET_META_GENERIC_BLOB_LEFT 10 -#define CAM_ISP_PACKET_META_GENERIC_BLOB_RIGHT 11 -#define CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON 12 +#define CAM_ISP_PACKET_META_BASE 0 +#define CAM_ISP_PACKET_META_LEFT 1 +#define CAM_ISP_PACKET_META_RIGHT 2 +#define CAM_ISP_PACKET_META_COMMON 3 +#define CAM_ISP_PACKET_META_DMI_LEFT 4 +#define CAM_ISP_PACKET_META_DMI_RIGHT 5 +#define CAM_ISP_PACKET_META_DMI_COMMON 6 +#define CAM_ISP_PACKET_META_CLOCK 7 +#define CAM_ISP_PACKET_META_CSID 8 +#define CAM_ISP_PACKET_META_DUAL_CONFIG 9 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_LEFT 10 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_RIGHT 11 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON 12 +#define CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST 13 +#define CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH 14 +#define CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR 15 /* DSP mode */ #define CAM_ISP_DSP_MODE_NONE 0 -- GitLab From 827791eafa3c8db89f76490dd6eb31acfcdefd90 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Thu, 8 Aug 2019 15:46:47 -0700 Subject: [PATCH 049/410] msm: camera: Add support for reg dump to command buffers Certain register values are required by user space during flush to apply settings accordingly. Also, support for dumping registers at the time of error is needed for debugging. Add support for dumping register values in a range of offsets to given cmd buffer. Change-Id: I5912118809f7a7dd701a555639d1057ffe665ce1 Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_core/cam_hw_mgr_intf.h | 10 + drivers/cam_isp/cam_isp_context.c | 28 ++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 159 +++++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 11 + .../hw_utils/cam_isp_packet_parser.c | 20 ++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 6 + drivers/cam_utils/cam_soc_util.c | 275 ++++++++++++++++++ drivers/cam_utils/cam_soc_util.h | 24 ++ 9 files changed, 531 insertions(+), 3 deletions(-) diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 56138c33091d..b7b6ae1bb6b7 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -21,6 +21,9 @@ /* maximum buf done irqs */ #define CAM_NUM_OUT_PER_COMP_IRQ_MAX 12 +/* Maximum reg dump cmd buffer entries in a context */ +#define CAM_REG_DUMP_MAX_BUF_ENTRIES 10 + /* hardware event callback function type */ typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, void *evt_data); @@ -166,6 +169,8 @@ struct cam_hw_mgr_dump_pf_data { * @max_in_map_entries: Maximum input fence mapping supported * @in_map_entries: Actual input fence mapping list (returned) * @num_in_map_entries: Number of acutal input fence mapping (returned) + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc * @priv: Private pointer of hw update * @pf_data: Debug data for page fault * @@ -183,6 +188,9 @@ struct cam_hw_prepare_update_args { uint32_t max_in_map_entries; struct cam_hw_fence_map_entry *in_map_entries; uint32_t num_in_map_entries; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; void *priv; struct cam_hw_mgr_dump_pf_data *pf_data; }; @@ -266,6 +274,8 @@ struct cam_hw_dump_pf_args { enum cam_hw_mgr_command { CAM_HW_MGR_CMD_INTERNAL, CAM_HW_MGR_CMD_DUMP_PF_INFO, + CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH, + CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR, }; /** diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index d88adebea4f7..638478cb56e1 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1116,6 +1116,22 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW)) notify.error = CRM_KMD_ERR_OVERFLOW; + + if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) || + (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW) || + (error_type == CAM_ISP_HW_ERROR_VIOLATION)) { + struct cam_hw_cmd_args hw_cmd_args; + + memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); + hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Reg dump on error failed rc: %d", rc); + rc = 0; + } + } /* * The error is likely caused by first request on the active list. * If active list is empty check wait list (maybe error hit as soon @@ -1932,6 +1948,8 @@ static int __cam_isp_ctx_flush_req_in_top_state( { int rc = 0; struct cam_isp_context *ctx_isp; + struct cam_hw_cmd_args hw_cmd_args; + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { @@ -1945,6 +1963,16 @@ static int __cam_isp_ctx_flush_req_in_top_state( rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); + memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); + hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Reg dump on flush failed rc: %d", rc); + rc = 0; + } + atomic_set(&ctx_isp->process_bubble, 0); return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index faf2fb02e924..96a12a707dd3 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2077,7 +2077,7 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, ctx = userdata; if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { - complete(&ctx->config_done_complete); + complete_all(&ctx->config_done_complete); CAM_DBG(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", handle, userdata, status, cookie, ctx->ctx_index); @@ -3059,8 +3059,8 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, cdm_cmd->cmd[i].len = cmd->len; } - if (cfg->init_packet) - init_completion(&ctx->config_done_complete); + reinit_completion(&ctx->config_done_complete); + ctx->applied_req_id = cfg->request_id; CAM_DBG(CAM_ISP, "Submit to CDM"); rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); @@ -5058,6 +5058,7 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, prepare->num_hw_update_entries = 0; prepare->num_in_map_entries = 0; prepare->num_out_map_entries = 0; + prepare->num_reg_dump_buf = 0; memset(&prepare_hw_data->bw_config[0], 0x0, sizeof(prepare_hw_data->bw_config[0]) * @@ -5123,6 +5124,15 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, if (((prepare->packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_INIT_DEV) { prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV; + ctx->num_reg_dump_buf = prepare->num_reg_dump_buf; + if ((ctx->num_reg_dump_buf) && (ctx->num_reg_dump_buf < + CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + memcpy(ctx->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare->num_reg_dump_buf); + } + goto end; } else prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_UPDATE_DEV; @@ -5279,6 +5289,118 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, } } +static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, + void *hw_mgr_ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ife_hw_mgr_ctx *ctx = + (struct cam_ife_hw_mgr_ctx *) hw_mgr_ctx; + + *soc_info_ptr = NULL; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + continue; + + switch (reg_base_type) { + case CAM_REG_DUMP_BASE_TYPE_CAMNOC: + case CAM_REG_DUMP_BASE_TYPE_ISP_LEFT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_LEFT, rc); + return rc; + } + + if (reg_base_type == CAM_REG_DUMP_BASE_TYPE_ISP_LEFT) + *reg_base_idx = 0; + else + *reg_base_idx = 1; + + *soc_info_ptr = soc_info; + break; + case CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_RIGHT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_RIGHT, rc); + return rc; + } + + *reg_base_idx = 0; + *soc_info_ptr = soc_info; + break; + default: + CAM_ERR(CAM_ISP, + "Unrecognized reg base type: %d", + reg_base_type); + return -EINVAL; + } + } + + return rc; +} + +static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, + uint32_t meta_type) +{ + int rc, i; + + if (!ctx->num_reg_dump_buf) { + CAM_DBG(CAM_ISP, + "Zero command buffers for reg dump req_id: [%llu] ctx idx: [%llu] meta_type: %d", + ctx->applied_req_id, ctx->ctx_index, meta_type); + return 0; + } + + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(30)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, + "config done completion timeout rc=%d ctx_index %d", + rc, ctx->ctx_index); + rc = 0; + } + + for (i = 0; i < ctx->num_reg_dump_buf; i++) { + CAM_DBG(CAM_ISP, "Reg dump cmd meta data: %d req_type: %d", + ctx->reg_dump_buf_desc[i].meta_data, meta_type); + if (ctx->reg_dump_buf_desc[i].meta_data == meta_type) { + rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, + &ctx->reg_dump_buf_desc[i], + ctx->applied_req_id, + cam_ife_mgr_regspace_data_cb); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %d", + i, rc, ctx->applied_req_id, meta_type); + return -EINVAL; + } + } + } + + return 0; +} + static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -5342,6 +5464,37 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_cmd_args->u.pf_args.buf_info, hw_cmd_args->u.pf_args.mem_found); break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH: + if (ctx->last_dump_flush_req_id == ctx->applied_req_id) + return 0; + + ctx->last_dump_flush_req_id = ctx->applied_req_id; + + rc = cam_ife_mgr_handle_reg_dump(ctx, + CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on flush failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + + break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR: + if (ctx->last_dump_err_req_id == ctx->applied_req_id) + return 0; + + ctx->last_dump_err_req_id = ctx->applied_req_id; + rc = cam_ife_mgr_handle_reg_dump(ctx, + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on error failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + + break; default: CAM_ERR(CAM_ISP, "Invalid cmd"); } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 16143b014ebf..698b0c60ca9b 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -124,6 +124,11 @@ struct cam_ife_hw_mgr_debug { * context * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc + * @applied_req_id: Last request id to be applied + * @last_dump_flush_req_id Last req id for which reg dump on flush was called + * @last_dump_err_req_id Last req id for which reg dump on error was called * @init_done indicate whether init hw is done * @is_fe_enable indicate whether fetch engine\read path is enabled * @is_dual indicate whether context is in dual VFE mode @@ -161,6 +166,12 @@ struct cam_ife_hw_mgr_ctx { atomic_t overflow_pending; uint32_t is_rdi_only_context; struct completion config_done_complete; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; + uint64_t applied_req_id; + uint64_t last_dump_flush_req_id; + uint64_t last_dump_err_req_id; bool init_done; bool is_fe_enable; bool is_dual; diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index be098a619aaf..48928bccc472 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -420,6 +420,26 @@ int cam_isp_add_command_buffers( num_ent = prepare->num_hw_update_entries; } break; + case CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH: + case CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + if (prepare->num_reg_dump_buf >= + CAM_REG_DUMP_MAX_BUF_ENTRIES) { + CAM_ERR(CAM_ISP, + "Descriptor count out of bounds: %d", + prepare->num_reg_dump_buf); + return -EINVAL; + } + prepare->reg_dump_buf_desc[ + prepare->num_reg_dump_buf] = + cmd_desc[i]; + prepare->num_reg_dump_buf++; + CAM_DBG(CAM_ISP, + "Added command buffer: %d desc_count: %d", + cmd_desc[i].meta_data, + prepare->num_reg_dump_buf); + } + break; default: CAM_ERR(CAM_ISP, "invalid cdm command meta data %d", cmd_meta_data); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 1e556137996d..741b41d4cccf 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -101,6 +101,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_CORE_CONFIG, CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index bbc25bc96045..7e9aa91689c3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -735,6 +735,12 @@ static int cam_vfe_camif_ver3_process_cmd( rsrc_node->res_priv; camif_priv->camif_debug = *((uint32_t *)cmd_args); break; + case CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA: + camif_priv = (struct cam_vfe_mux_camif_ver3_data *) + rsrc_node->res_priv; + *((struct cam_hw_soc_info **)cmd_args) = camif_priv->soc_info; + rc = 0; + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index e32a6ab21665..99e349a66c61 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -11,6 +11,7 @@ #include "cam_soc_util.h" #include "cam_debug_util.h" #include "cam_cx_ipeak.h" +#include "cam_mem_mgr.h" static char supported_clk_info[256]; static char debugfs_dir_name[64]; @@ -1825,3 +1826,277 @@ int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, return 0; } + +static int cam_soc_util_dump_cont_reg_range( + struct cam_hw_soc_info *soc_info, + struct cam_reg_range_read_desc *reg_read, uint32_t base_idx, + struct cam_reg_dump_out_buffer *dump_out_buf, size_t max_out_size) +{ + int i = 0; + uint32_t write_idx = 0; + + if (!soc_info || !dump_out_buf) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK", + soc_info, dump_out_buf); + return -EINVAL; + } + + if (reg_read->num_values >= ((max_out_size - + (size_t)dump_out_buf->bytes_written) / sizeof(uint32_t))) { + CAM_ERR(CAM_UTIL, + "Invalid num values to read: %d max values: %d bytes written: %d", + reg_read->num_values, (max_out_size / + sizeof(uint32_t)), dump_out_buf->bytes_written); + return -EINVAL; + } + + write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); + for (i = 0; i < reg_read->num_values; i++) { + dump_out_buf->dump_data[write_idx++] = reg_read->offset + + (i * 4); + dump_out_buf->dump_data[write_idx++] = + cam_soc_util_r(soc_info, base_idx, + (reg_read->offset + (i * 4))); + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + return 0; +} + +static int cam_soc_util_dump_dmi_reg_range( + struct cam_hw_soc_info *soc_info, + struct cam_dmi_read_desc *dmi_read, uint32_t base_idx, + struct cam_reg_dump_out_buffer *dump_out_buf, size_t max_out_size) +{ + int i = 0; + uint32_t write_idx = 0; + + if (!soc_info || !dump_out_buf) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK", + soc_info, dump_out_buf); + return -EINVAL; + } + + if (dmi_read->num_pre_writes > CAM_REG_DUMP_DMI_CONFIG_MAX || + dmi_read->num_post_writes > CAM_REG_DUMP_DMI_CONFIG_MAX) { + CAM_ERR(CAM_UTIL, + "Invalid number of requested writes, pre: %d post: %d", + dmi_read->num_pre_writes, dmi_read->num_post_writes); + return -EINVAL; + } + + if (dmi_read->dmi_data_read.num_values >= ((max_out_size - + (size_t)dump_out_buf->bytes_written) / sizeof(uint32_t))) { + CAM_ERR(CAM_UTIL, + "Invalid num values to read: %d max values: %d bytes written: %d", + dmi_read->dmi_data_read.num_values, (max_out_size / + sizeof(uint32_t)), dump_out_buf->bytes_written); + return -EINVAL; + } + + write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); + for (i = 0; i < dmi_read->num_pre_writes; i++) { + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->pre_read_config[i].offset, + dmi_read->pre_read_config[i].value); + dump_out_buf->dump_data[write_idx++] = + dmi_read->pre_read_config[i].offset; + dump_out_buf->dump_data[write_idx++] = + dmi_read->pre_read_config[i].value; + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) { + dump_out_buf->dump_data[write_idx++] = + dmi_read->dmi_data_read.offset; + dump_out_buf->dump_data[write_idx++] = + cam_soc_util_r_mb(soc_info, base_idx, + dmi_read->dmi_data_read.offset); + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + for (i = 0; i < dmi_read->num_post_writes; i++) { + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->post_read_config[i].offset, + dmi_read->post_read_config[i].value); + } + + return 0; +} + +int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, + struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, + cam_soc_util_regspace_data_cb reg_data_cb) +{ + int rc = 0, i, j; + uintptr_t cpu_addr = 0; + uintptr_t cmd_buf_start = 0; + uintptr_t cmd_in_data_end = 0; + uintptr_t cmd_buf_end = 0; + uint32_t reg_base_type = 0; + size_t buf_size = 0, remain_len = 0; + size_t max_out_size = 0; + struct cam_reg_dump_input_info *reg_input_info = NULL; + struct cam_reg_dump_desc *reg_dump_desc = NULL; + struct cam_reg_dump_out_buffer *dump_out_buf = NULL; + struct cam_reg_read_info *reg_read_info = NULL; + struct cam_hw_soc_info *soc_info; + uint32_t reg_base_idx = 0; + + if (!ctx || !cmd_desc || !reg_data_cb) { + CAM_ERR(CAM_UTIL, "Invalid args to reg dump [%pK] [%pK]", + cmd_desc, reg_data_cb); + return -EINVAL; + } + + if (!cmd_desc->length || !cmd_desc->size) { + CAM_ERR(CAM_UTIL, "Invalid cmd buf size %d %d", + cmd_desc->length, cmd_desc->size); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, &cpu_addr, &buf_size); + if (rc || !cpu_addr || (buf_size == 0)) { + CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK", + rc, (void *)cpu_addr); + return rc; + } + + CAM_DBG(CAM_UTIL, "Get cpu buf success req_id: %llu buf_size: %zu", + req_id, buf_size); + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_desc->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_desc->offset); + return -EINVAL; + } + + remain_len = buf_size - (size_t)cmd_desc->offset; + if (remain_len < (size_t)cmd_desc->length) { + CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", + (size_t)cmd_desc->length); + return -EINVAL; + } + + cmd_buf_start = (uintptr_t)(((uint8_t *)cpu_addr) + cmd_desc->offset); + cmd_in_data_end = (uintptr_t)(((uint8_t *)cmd_buf_start) + + cmd_desc->length); + cmd_buf_end = (uintptr_t)(((uint8_t *)cmd_buf_start) + + cmd_desc->size); + if (cmd_buf_end < cmd_in_data_end) { + CAM_ERR(CAM_UTIL, + "Invalid length and size for cmd buf: [%zu] [%zu]", + (size_t)cmd_desc->length, (size_t)cmd_desc->size); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, + "Buffer params start [%pK] input_end [%pK] buf_end [%pK]", + cmd_buf_start, cmd_in_data_end, cmd_buf_end); + reg_input_info = (struct cam_reg_dump_input_info *) cmd_buf_start; + if (!reg_input_info->num_dump_sets) { + CAM_ERR(CAM_UTIL, "Zero dump sets found in input info"); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, + "reg_input_info req_id: %llu ctx %pK num_dump_sets: %d", + req_id, ctx, reg_input_info->num_dump_sets); + for (i = 0; i < reg_input_info->num_dump_sets; i++) { + if ((remain_len - sizeof(uint32_t)) <= + (size_t)reg_input_info->dump_set_offsets[i]) { + CAM_ERR(CAM_UTIL, + "Invalid dump set offset: [%zu], remain len: [%zu]", + (size_t)reg_input_info->dump_set_offsets[i], + remain_len); + return -EINVAL; + } + + reg_dump_desc = (struct cam_reg_dump_desc *) + ((uint8_t *)cmd_buf_start + + reg_input_info->dump_set_offsets[i]); + if (!reg_dump_desc->num_read_range) { + CAM_ERR(CAM_UTIL, "Zero ranges found in input info"); + return -EINVAL; + } + + if ((remain_len - sizeof(uint32_t)) + <= (size_t)reg_dump_desc->dump_buffer_offset) { + CAM_ERR(CAM_UTIL, + "Invalid out buffer offset: [%zu], remain len: [%zu]", + (size_t)reg_dump_desc->dump_buffer_offset, + remain_len); + return -EINVAL; + } + + dump_out_buf = (struct cam_reg_dump_out_buffer *) + ((uint8_t *)cmd_buf_start + + reg_dump_desc->dump_buffer_offset); + dump_out_buf->req_id = req_id; + dump_out_buf->bytes_written = 0; + max_out_size = (size_t)(cmd_desc->size - + reg_dump_desc->dump_buffer_offset); + + reg_base_type = reg_dump_desc->reg_base_type; + if (reg_base_type == 0 || reg_base_type > + CAM_REG_DUMP_BASE_TYPE_CAMNOC) { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump base type: %d", + reg_base_type); + return -EINVAL; + } + + rc = reg_data_cb(reg_base_type, ctx, &soc_info, ®_base_idx); + if (rc || !soc_info) { + CAM_ERR(CAM_UTIL, + "Reg space data callback failed rc: %d soc_info: [%pK]", + rc, soc_info); + return -EINVAL; + } + + if (reg_base_idx > soc_info->num_reg_map) { + CAM_ERR(CAM_UTIL, + "Invalid reg base idx: %d num reg map: %d", + reg_base_idx, soc_info->num_reg_map); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, + "Reg data callback success req_id: %llu base_type: %d base_idx: %d num_read_range: %d", + req_id, reg_base_type, reg_base_idx, + reg_dump_desc->num_read_range); + for (j = 0; j < reg_dump_desc->num_read_range; j++) { + CAM_DBG(CAM_UTIL, + "Number of bytes written to cmd buffer: %u req_id: %llu", + dump_out_buf->bytes_written, req_id); + reg_read_info = ®_dump_desc->read_range[j]; + if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_CONT_RANGE) { + rc = cam_soc_util_dump_cont_reg_range(soc_info, + ®_read_info->reg_read, reg_base_idx, + dump_out_buf, max_out_size); + } else if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_DMI) { + rc = cam_soc_util_dump_dmi_reg_range(soc_info, + ®_read_info->dmi_read, reg_base_idx, + dump_out_buf, max_out_size); + } else { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump read type: %d", + reg_read_info->type); + return -EINVAL; + } + + if (rc) { + CAM_ERR(CAM_UTIL, + "Reg range read failed rc: %d reg_base_idx: %d dump_out_buf: %pK", + rc, reg_base_idx, dump_out_buf); + return rc; + } + } + } + + return 0; +} diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 2ddd4de2d86c..ad2382b835ef 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -18,6 +18,7 @@ #include #include "cam_io_util.h" +#include #define NO_SET_RATE -1 #define INIT_RATE -2 @@ -639,4 +640,27 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, int32_t clk_rate, int clk_idx, int32_t *clk_lvl); +/* Callback to get reg space data for specific HW */ +typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type, + void *ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx); + +/** + * cam_soc_util_reg_dump_to_cmd_buf() + * + * @brief: Camera SOC util for dumping sets of register ranges to + * to command buffer + * + * @ctx: Context info from specific hardware manager + * @cmd_desc: Command buffer descriptor + * @req_id: Last applied req id for which reg dump is required + * @reg_data_cb: Callback function to get reg space info based on type + * in command buffer + * + * @return: Success or Failure + */ +int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, + struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, + cam_soc_util_regspace_data_cb reg_data_cb); + #endif /* _CAM_SOC_UTIL_H_ */ -- GitLab From 519d453d0d4daaeadbd27f683e5391b6575adf3f Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 12 Jul 2019 11:07:34 -0700 Subject: [PATCH 050/410] msm: camera: icp: Update A5 clock per frame A5 (ICP) clock corners IPE clock source. This change updates ICP clock based on the rate updated for IPE. Change-Id: I2c0b711d34ea8ab8ccf458ecb77402ecf6bf967e Signed-off-by: Karthik Anantha Ram Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 19 ++++++++ drivers/cam_icp/icp_hw/a5_hw/a5_soc.c | 44 +++++++++++++++++++ drivers/cam_icp/icp_hw/a5_hw/a5_soc.h | 2 + .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 16 ++++++- .../icp_hw_mgr/include/cam_a5_hw_intf.h | 3 +- .../icp_hw_mgr/include/cam_icp_hw_intf.h | 5 +++ drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c | 10 ++++- 7 files changed, 95 insertions(+), 4 deletions(-) diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index f7d94b2ce679..d6e2970b09ee 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -519,6 +519,25 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, break; } + case CAM_ICP_A5_CMD_CLK_UPDATE: { + int32_t clk_level = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "Invalid args"); + return -EINVAL; + } + + clk_level = *((int32_t *)cmd_args); + CAM_DBG(CAM_ICP, + "Update ICP clock to level [%d]", clk_level); + rc = cam_a5_update_clk_rate(soc_info, clk_level); + if (rc) + CAM_ERR(CAM_ICP, + "Failed to update clk to level: %d rc: %d", + clk_level, rc); + + break; + } default: break; } diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c index 62a88ac87f67..d0629612193a 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c @@ -196,3 +196,47 @@ int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info) return rc; } + +int cam_a5_update_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_level) +{ + int32_t src_clk_idx = 0; + int32_t clk_rate = 0; + + if (!soc_info) { + CAM_ERR(CAM_ICP, "Invalid args"); + return -EINVAL; + } + + if ((clk_level < 0) || (clk_level >= CAM_MAX_VOTE)) { + CAM_ERR(CAM_ICP, "clock level %d is not valid", + clk_level); + return -EINVAL; + } + + if (!soc_info->clk_level_valid[clk_level]) { + CAM_ERR(CAM_ICP, + "Clock level %d not supported", + clk_level); + return -EINVAL; + } + + src_clk_idx = soc_info->src_clk_idx; + if ((src_clk_idx < 0) || (src_clk_idx >= CAM_SOC_MAX_CLK)) { + CAM_WARN(CAM_ICP, "src_clk not defined for %s", + soc_info->dev_name); + return -EINVAL; + } + + clk_rate = soc_info->clk_rate[clk_level][src_clk_idx]; + if ((soc_info->clk_level_valid[CAM_TURBO_VOTE]) && + (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && + (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { + CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + clk_rate, + soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); + clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; + } + + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); +} diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h index c44bcde120fb..480364df1fd6 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h @@ -34,4 +34,6 @@ int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info); int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info); +int cam_a5_update_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_level); #endif 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 57a88f5a3070..fc7942bc42bf 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 @@ -1320,12 +1320,14 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, struct cam_hw_intf *ipe0_dev_intf = NULL; struct cam_hw_intf *ipe1_dev_intf = NULL; struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *a5_dev_intf = NULL; struct cam_hw_intf *dev_intf = NULL; struct cam_a5_clk_update_cmd clk_upd_cmd; ipe0_dev_intf = hw_mgr->ipe0_dev_intf; ipe1_dev_intf = hw_mgr->ipe1_dev_intf; bps_dev_intf = hw_mgr->bps_dev_intf; + a5_dev_intf = hw_mgr->a5_dev_intf; if ((!ipe0_dev_intf) || (!bps_dev_intf)) { @@ -1347,16 +1349,26 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, ctx_data->icp_dev_acquire_info->dev_type); clk_upd_cmd.curr_clk_rate = curr_clk_rate; clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; + clk_upd_cmd.clk_level = -1; dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd)); - if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS) - if (ipe1_dev_intf) + if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS) { + if (ipe1_dev_intf) { ipe1_dev_intf->hw_ops.process_cmd( ipe1_dev_intf->hw_priv, id, &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd)); + } + + /* update a5 clock */ + CAM_DBG(CAM_ICP, "Update ICP clk to level [%d]", + clk_upd_cmd.clk_level); + a5_dev_intf->hw_ops.process_cmd(a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_CLK_UPDATE, &clk_upd_cmd.clk_level, + sizeof(clk_upd_cmd.clk_level)); + } return 0; } diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h index 397592a4410c..5d4371483acc 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef CAM_A5_HW_INTF_H @@ -26,6 +26,7 @@ enum cam_icp_a5_cmd_type { CAM_ICP_A5_CMD_CPAS_STOP, CAM_ICP_A5_CMD_UBWC_CFG, CAM_ICP_A5_CMD_PC_PREP, + CAM_ICP_A5_CMD_CLK_UPDATE, CAM_ICP_A5_CMD_MAX, }; diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h index aadf27fef485..80a724b53d94 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h @@ -25,9 +25,14 @@ enum cam_a5_hw_type { * * @curr_clk_rate: clk rate to HW * @ipe_bps_pc_enable power collpase enable flag + * @clk_level: clk level corresponding to the clk rate + * populated as output while the clk is being + * updated to the given rate */ struct cam_a5_clk_update_cmd { uint32_t curr_clk_rate; bool ipe_bps_pc_enable; + int32_t clk_level; }; + #endif diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c index 82d0ebe54cc4..9ea8f51bb914 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -361,6 +361,7 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, struct cam_a5_clk_update_cmd *clk_upd_cmd = (struct cam_a5_clk_update_cmd *)cmd_args; uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + int32_t clk_level = 0, err = 0; CAM_DBG(CAM_ICP, "ipe_src_clk rate = %d", (int)clk_rate); if (!core_info->clk_enable) { @@ -386,8 +387,15 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_ipe_update_clk_rate(soc_info, clk_rate); if (rc) CAM_ERR(CAM_ICP, "Failed to update clk"); - } + + err = cam_soc_util_get_clk_level(soc_info, + clk_rate, soc_info->src_clk_idx, + &clk_level); + if (err == 0) + clk_upd_cmd->clk_level = clk_level; + break; + } case CAM_ICP_IPE_CMD_DISABLE_CLK: if (core_info->clk_enable == true) cam_ipe_toggle_clk(soc_info, false); -- GitLab From 360454feef09207fdbbfba03f91c1d96c026a1b4 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 21 May 2019 16:37:46 -0700 Subject: [PATCH 051/410] msm: camera: icp: Avoid accessing frame process data in the kernel IPE/BPS frame process data keeps changing one needs to update the kernel hfi header accordingly everytime. This change avoids accessing those structs in the kernel. Userspace will ensure resetting the struct to a default value. Change-Id: If224befa89643f44997bb6e826f8dfcfac5d08d1 Signed-off-by: Karthik Anantha Ram Signed-off-by: Mukund Madhusudan Atre --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 49 +------------------ 1 file changed, 1 insertion(+), 48 deletions(-) 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 fc7942bc42bf..84ea1ac6323f 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 @@ -3836,16 +3836,12 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, uint32_t *fw_cmd_buf_iova_addr) { int rc = 0; - int i, j, k; + int i; int num_cmd_buf = 0; uint64_t addr; size_t len; struct cam_cmd_buf_desc *cmd_desc = NULL; uintptr_t cpu_addr = 0; - struct ipe_frame_process_data *frame_process_data = NULL; - struct bps_frame_process_data *bps_frame_process_data = NULL; - struct frame_set *ipe_set = NULL; - struct frame_buffer *bps_bufs = NULL; cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); @@ -3893,49 +3889,6 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, return -EINVAL; } - if (ctx_data->icp_dev_acquire_info->dev_type != - CAM_ICP_RES_TYPE_BPS) { - CAM_DBG(CAM_ICP, "cpu addr = %zx", cpu_addr); - frame_process_data = (struct ipe_frame_process_data *)cpu_addr; - CAM_DBG(CAM_ICP, "%u %u %u", frame_process_data->max_num_cores, - frame_process_data->target_time, - frame_process_data->frames_in_batch); - frame_process_data->strip_lib_out_addr = 0; - frame_process_data->iq_settings_addr = 0; - frame_process_data->scratch_buffer_addr = 0; - frame_process_data->ubwc_stats_buffer_addr = 0; - frame_process_data->cdm_buffer_addr = 0; - frame_process_data->cdm_prog_base = 0; - for (i = 0; i < frame_process_data->frames_in_batch; i++) { - ipe_set = &frame_process_data->framesets[i]; - for (j = 0; j < IPE_IO_IMAGES_MAX; j++) { - for (k = 0; k < MAX_NUM_OF_IMAGE_PLANES; k++) { - ipe_set->buffers[j].buf_ptr[k] = 0; - ipe_set->buffers[j].meta_buf_ptr[k] = 0; - } - } - } - } else { - CAM_DBG(CAM_ICP, "cpu addr = %zx", cpu_addr); - bps_frame_process_data = - (struct bps_frame_process_data *)cpu_addr; - CAM_DBG(CAM_ICP, "%u %u", - bps_frame_process_data->max_num_cores, - bps_frame_process_data->target_time); - bps_frame_process_data->ubwc_stats_buffer_addr = 0; - bps_frame_process_data->cdm_buffer_addr = 0; - bps_frame_process_data->iq_settings_addr = 0; - bps_frame_process_data->strip_lib_out_addr = 0; - bps_frame_process_data->cdm_prog_addr = 0; - for (i = 0; i < BPS_IO_IMAGES_MAX; i++) { - bps_bufs = &bps_frame_process_data->buffers[i]; - for (j = 0; j < MAX_NUM_OF_IMAGE_PLANES; j++) { - bps_bufs->buf_ptr[j] = 0; - bps_bufs->meta_buf_ptr[j] = 0; - } - } - } - return rc; } -- GitLab From f2a0cc111f44f0ffb625ffcddb3155c0b1afa07a Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 18 Jul 2019 15:03:05 -0700 Subject: [PATCH 052/410] msm: camera: reqmgr: Dump device name as part of frame skip log Currently we can infer only the pd of the device whose request was not available on time leading to a frame skip. This change identifies and logs the device name to ease debugging. Change-Id: I49a3cd84611b21626c68395b11f0ef52bffb62db Signed-off-by: Karthik Anantha Ram Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_req_mgr/cam_req_mgr_core.c | 60 +++++++++++++++++++++++--- drivers/cam_req_mgr/cam_req_mgr_core.h | 29 ++++++++++--- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index a9edecc44ab4..3147eeab0a7b 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -167,6 +167,40 @@ static int __cam_req_mgr_inject_delay( return rc; } +/** + * __cam_req_mgr_find_dev_name() + * + * @brief : Find the dev name whose req is not ready + * @link : link info + * @req_id : req_id which is not ready + * @pd : pipeline delay + * @masked_val : masked value holds the bit for all devices + * that don't have the req_id ready for a given + * pipeline delay + * @pd : pipeline delay + * + */ +static void __cam_req_mgr_find_dev_name( + struct cam_req_mgr_core_link *link, + int64_t req_id, uint32_t pd, uint32_t masked_val) +{ + int i = 0; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev->dev_info.p_delay == pd) { + if (masked_val & (1 << dev->dev_bit)) + continue; + + CAM_INFO(CAM_CRM, + "Skip Frame: req: %lld not ready on link: 0x%x for pd: %d dev: %s open_req count: %d", + req_id, link->link_hdl, pd, dev->dev_info.name, + link->open_req_cnt); + } + } +} + /** * __cam_req_mgr_notify_error_on_link() * @@ -296,14 +330,15 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) } } else { /* This pd table is not ready to proceed with asked idx */ - CAM_INFO(CAM_CRM, - "Skip Frame: req: %lld not ready pd: %d open_req count: %d", - CRM_GET_REQ_ID(traverse_data->in_q, curr_idx), - tbl->pd, - traverse_data->open_req_cnt); + traverse_data->result_data.req_id = + CRM_GET_REQ_ID(traverse_data->in_q, curr_idx); + traverse_data->result_data.pd = tbl->pd; + traverse_data->result_data.masked_value = + (tbl->dev_mask & slot->req_ready_map); SET_FAILURE_BIT(traverse_data->result, tbl->pd); return -EAGAIN; } + return 0; } @@ -650,6 +685,9 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, traverse_data.tbl = link->req.l_tbl; traverse_data.in_q = in_q; traverse_data.result = 0; + traverse_data.result_data.masked_value = 0; + traverse_data.result_data.pd = 0; + traverse_data.result_data.req_id = 0; traverse_data.validate_only = validate_only; traverse_data.open_req_cnt = link->open_req_cnt; @@ -669,8 +707,13 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, apply_data[2].req_id, apply_data[1].req_id, apply_data[0].req_id); - } else + } else { rc = -EAGAIN; + __cam_req_mgr_find_dev_name(link, + traverse_data.result_data.req_id, + traverse_data.result_data.pd, + traverse_data.result_data.masked_value); + } return rc; } @@ -2104,6 +2147,7 @@ int cam_req_mgr_process_error(void *priv, void *data) spin_lock_bh(&link->link_state_spin_lock); link->state = CAM_CRM_LINK_STATE_ERR; spin_unlock_bh(&link->link_state_spin_lock); + link->open_req_cnt++; } } mutex_unlock(&link->req.lock); @@ -2580,7 +2624,9 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, dev->dev_bit = pd_tbl->dev_count++; dev->pd_tbl = pd_tbl; pd_tbl->dev_mask |= (1 << dev->dev_bit); - + CAM_DBG(CAM_CRM, "dev_bit %u name %s pd %u mask %d", + dev->dev_bit, dev->dev_info.name, pd_tbl->pd, + pd_tbl->dev_mask); /* Communicate with dev to establish the link */ dev->ops->link_setup(&link_data); diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 8eb15bec802d..aeede7a87166 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -125,10 +125,24 @@ enum cam_req_mgr_link_state { CAM_CRM_LINK_STATE_MAX, }; +/** + * struct cam_req_mgr_traverse_result + * @req_id : Req id that is not ready + * @pd : pipeline delay + * @masked_value : Holds the dev bit for devices not ready + * for the given request + */ +struct cam_req_mgr_traverse_result { + int64_t req_id; + uint32_t pd; + uint32_t masked_value; +}; + /** * struct cam_req_mgr_traverse * @idx : slot index * @result : contains which all tables were able to apply successfully + * @result_data : holds the result of traverse in case it fails * @tbl : pointer of pipeline delay based request table * @apply_data : pointer which various tables will update during traverse * @in_q : input request queue pointer @@ -136,13 +150,14 @@ enum cam_req_mgr_link_state { * @open_req_cnt : Count of open requests yet to be serviced in the kernel. */ struct cam_req_mgr_traverse { - int32_t idx; - uint32_t result; - struct cam_req_mgr_req_tbl *tbl; - struct cam_req_mgr_apply *apply_data; - struct cam_req_mgr_req_queue *in_q; - bool validate_only; - int32_t open_req_cnt; + int32_t idx; + uint32_t result; + struct cam_req_mgr_traverse_result result_data; + struct cam_req_mgr_req_tbl *tbl; + struct cam_req_mgr_apply *apply_data; + struct cam_req_mgr_req_queue *in_q; + bool validate_only; + int32_t open_req_cnt; }; /** -- GitLab From 5b016ad22077f42e852f86663f080ea6cb7f3bef Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Fri, 9 Aug 2019 12:56:12 -0700 Subject: [PATCH 053/410] Camera: Correct makefiles for correct header inclusion Correct some Makefiles and drivers header inclusion. Change-Id: Iec3e6e0333ae55e8f1cff9780723e0dad954ff83 Signed-off-by: Jigarkumar Zala --- drivers/Makefile | 26 +++++++++---------- drivers/cam_cdm/Makefile | 4 +-- drivers/cam_cdm/cam_cdm_hw_core.c | 2 +- drivers/cam_core/Makefile | 2 +- drivers/cam_core/cam_context_utils.c | 4 +-- drivers/cam_cpas/Makefile | 2 +- drivers/cam_cpas/cam_cpas_intf.c | 4 +-- drivers/cam_cpas/camss_top/Makefile | 2 +- drivers/cam_cpas/cpas_top/Makefile | 2 +- drivers/cam_fd/Makefile | 2 +- drivers/cam_fd/fd_hw_mgr/Makefile | 2 +- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 4 +-- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h | 2 +- drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile | 2 +- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h | 4 +-- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 6 ++--- drivers/cam_icp/Makefile | 2 +- drivers/cam_icp/cam_icp_context.c | 6 ++--- drivers/cam_icp/cam_icp_subdev.c | 6 ++--- drivers/cam_icp/hfi.c | 2 +- drivers/cam_icp/icp_hw/Makefile | 2 +- drivers/cam_icp/icp_hw/a5_hw/Makefile | 2 +- drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 2 +- drivers/cam_icp/icp_hw/bps_hw/Makefile | 2 +- drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile | 2 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 6 ++--- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 2 +- .../icp_hw_mgr/include/cam_a5_hw_intf.h | 4 +-- .../icp_hw_mgr/include/cam_bps_hw_intf.h | 4 +-- .../icp_hw_mgr/include/cam_ipe_hw_intf.h | 4 +-- .../icp_hw/include/cam_icp_hw_mgr_intf.h | 4 +-- drivers/cam_icp/icp_hw/ipe_hw/Makefile | 2 +- drivers/cam_isp/Makefile | 2 +- drivers/cam_isp/cam_isp_context.h | 4 +-- drivers/cam_isp/cam_isp_dev.c | 2 +- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile | 2 +- .../vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c | 2 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 2 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 2 +- drivers/cam_jpeg/Makefile | 2 +- drivers/cam_jpeg/cam_jpeg_context.h | 2 +- drivers/cam_lrme/Makefile | 2 +- drivers/cam_req_mgr/Makefile | 6 ++--- drivers/cam_req_mgr/cam_mem_mgr_api.h | 2 +- drivers/cam_req_mgr/cam_req_mgr_dev.c | 4 +-- drivers/cam_req_mgr/cam_req_mgr_util.c | 2 +- .../cam_sensor_module/cam_actuator/Makefile | 4 ++- drivers/cam_sensor_module/cam_cci/Makefile | 5 ++-- .../cam_sensor_module/cam_cci/cam_cci_core.h | 2 +- .../cam_sensor_module/cam_cci/cam_cci_dev.c | 2 +- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 4 +-- drivers/cam_sensor_module/cam_csiphy/Makefile | 2 +- .../cam_csiphy/cam_csiphy_dev.c | 2 +- .../cam_csiphy/cam_csiphy_dev.h | 2 +- drivers/cam_sensor_module/cam_eeprom/Makefile | 2 +- .../cam_eeprom/cam_eeprom_core.c | 2 +- .../cam_eeprom/cam_eeprom_dev.h | 2 +- drivers/cam_sensor_module/cam_flash/Makefile | 5 ++-- .../cam_flash/cam_flash_core.h | 2 +- .../cam_flash/cam_flash_dev.h | 4 +-- drivers/cam_sensor_module/cam_ois/Makefile | 3 ++- .../cam_sensor_module/cam_ois/cam_ois_dev.h | 2 +- .../cam_sensor_module/cam_res_mgr/Makefile | 2 +- drivers/cam_sensor_module/cam_sensor/Makefile | 2 +- .../cam_sensor_module/cam_sensor_io/Makefile | 2 +- .../cam_sensor_io/cam_sensor_i2c.h | 2 +- .../cam_sensor_io/cam_sensor_io.h | 2 +- .../cam_sensor_io/cam_sensor_spi.h | 2 +- .../cam_sensor_utils/Makefile | 2 +- .../cam_sensor_utils/cam_sensor_cmn_header.h | 4 +-- .../cam_sensor_utils/cam_sensor_util.c | 2 +- .../cam_sensor_utils/cam_sensor_util.h | 6 ++--- drivers/cam_smmu/Makefile | 2 +- drivers/cam_smmu/cam_smmu_api.c | 2 +- drivers/cam_sync/Makefile | 2 +- drivers/cam_utils/Makefile | 2 +- drivers/cam_utils/cam_trace.c | 2 +- drivers/cam_utils/cam_trace.h | 2 +- include/uapi/media/cam_cpas.h | 2 +- include/uapi/media/cam_fd.h | 4 +-- include/uapi/media/cam_icp.h | 4 +-- include/uapi/media/cam_isp.h | 8 +++--- include/uapi/media/cam_jpeg.h | 4 +-- include/uapi/media/cam_lrme.h | 4 +-- include/uapi/media/cam_req_mgr.h | 2 +- include/uapi/media/cam_sensor.h | 2 +- 86 files changed, 138 insertions(+), 133 deletions(-) diff --git a/drivers/Makefile b/drivers/Makefile index 28d4762a55df..9e0aee9f69e3 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,13 +1,13 @@ -obj-y += cam_req_mgr/ -obj-y += cam_utils/ -obj-y += cam_core/ -obj-y += cam_sync/ -obj-y += cam_smmu/ -obj-y += cam_cpas/ -obj-y += cam_cdm/ -obj-y += cam_isp/ -obj-y += cam_sensor_module/ -obj-y += cam_icp/ -obj-y += cam_jpeg/ -obj-y += cam_fd/ -obj-y += cam_lrme/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/ diff --git a/drivers/cam_cdm/Makefile b/drivers/cam_cdm/Makefile index 2b5b712cbbb3..323a523011a2 100644 --- a/drivers/cam_cdm/Makefile +++ b/drivers/cam_cdm/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr -obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm_util.o cam_cdm_intf.o cam_cdm_soc.o\ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm_soc.o cam_cdm_util.o cam_cdm_intf.o\ cam_cdm_core_common.o cam_cdm_virtual_core.o \ cam_cdm_hw_core.o diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 40dba7352f32..bf251a823819 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include "cam_soc_util.h" #include "cam_smmu_api.h" #include "cam_cdm_intf_api.h" diff --git a/drivers/cam_core/Makefile b/drivers/cam_core/Makefile index 986b65f0ecd4..e117039fc3ab 100644 --- a/drivers/cam_core/Makefile +++ b/drivers/cam_core/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 6b6b17743d1b..34dc7b81d454 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include "cam_context.h" #include "cam_context_utils.h" diff --git a/drivers/cam_cpas/Makefile b/drivers/cam_cpas/Makefile index e0af486932f1..6fc8f9830cec 100644 --- a/drivers/cam_cpas/Makefile +++ b/drivers/cam_cpas/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index d1b32a0d916a..a1d8b4026059 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -10,8 +10,8 @@ #include #include #include -#include -#include +#include +#include #include #include "cam_subdev.h" diff --git a/drivers/cam_cpas/camss_top/Makefile b/drivers/cam_cpas/camss_top/Makefile index 902e74e20607..de11b7136563 100644 --- a/drivers/cam_cpas/camss_top/Makefile +++ b/drivers/cam_cpas/camss_top/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include diff --git a/drivers/cam_cpas/cpas_top/Makefile b/drivers/cam_cpas/cpas_top/Makefile index 2db4c393c65d..0306b14ef14a 100644 --- a/drivers/cam_cpas/cpas_top/Makefile +++ b/drivers/cam_cpas/cpas_top/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include diff --git a/drivers/cam_fd/Makefile b/drivers/cam_fd/Makefile index 20fd941327ed..92356a35d8c8 100644 --- a/drivers/cam_fd/Makefile +++ b/drivers/cam_fd/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_fd/fd_hw_mgr/Makefile b/drivers/cam_fd/fd_hw_mgr/Makefile index cc15876c9602..8db8097679b5 100644 --- a/drivers/cam_fd/fd_hw_mgr/Makefile +++ b/drivers/cam_fd/fd_hw_mgr/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 0d7e709ad38f..fad7caff6437 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -5,8 +5,8 @@ #include #include -#include -#include +#include +#include #include "cam_io_util.h" #include "cam_soc_util.h" diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h index 351cae971a42..49bc5bbc1b07 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include "cam_hw.h" #include "cam_hw_intf.h" #include "cam_cpas_api.h" diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile b/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile index fd43ca7a4546..6a53cc67f7e6 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h index 22f9130d9cd1..1f8815e72f20 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include #include "cam_common_util.h" #include "cam_debug_util.h" diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h index 040bd161e006..e35e5e520b7b 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -9,9 +9,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "cam_io_util.h" #include "cam_soc_util.h" diff --git a/drivers/cam_icp/Makefile b/drivers/cam_icp/Makefile index b41c6cf1fb65..aec65fc06f4b 100644 --- a/drivers/cam_icp/Makefile +++ b/drivers/cam_icp/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 6e043fd95c63..ec23a6ee9d96 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -7,9 +7,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "cam_node.h" #include "cam_context.h" #include "cam_context_utils.h" diff --git a/drivers/cam_icp/cam_icp_subdev.c b/drivers/cam_icp/cam_icp_subdev.c index f6dbaec5f133..bdb2ed5f900b 100644 --- a/drivers/cam_icp/cam_icp_subdev.c +++ b/drivers/cam_icp/cam_icp_subdev.c @@ -17,9 +17,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "cam_req_mgr_dev.h" #include "cam_subdev.h" #include "cam_node.h" diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index 06ad9de00eac..783b5c3723be 100644 --- a/drivers/cam_icp/hfi.c +++ b/drivers/cam_icp/hfi.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/cam_icp/icp_hw/Makefile b/drivers/cam_icp/icp_hw/Makefile index e07836a01f12..68b36f706604 100644 --- a/drivers/cam_icp/icp_hw/Makefile +++ b/drivers/cam_icp/icp_hw/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_icp/icp_hw/a5_hw/Makefile b/drivers/cam_icp/icp_hw/a5_hw/Makefile index db80567488a0..9c3aac09a137 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/Makefile +++ b/drivers/cam_icp/icp_hw/a5_hw/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index f7d94b2ce679..5a2b7868fb4c 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "cam_io_util.h" #include "cam_a5_hw_intf.h" #include "cam_hw.h" diff --git a/drivers/cam_icp/icp_hw/bps_hw/Makefile b/drivers/cam_icp/icp_hw/bps_hw/Makefile index 2abf88310cbd..491e6a16492b 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/Makefile +++ b/drivers/cam_icp/icp_hw/bps_hw/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile b/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile index 2d06413e74ca..b87d5dba817a 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/hw_utils/include 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 57a88f5a3070..17c26a654eb2 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 @@ -16,9 +16,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "cam_sync_api.h" #include "cam_packet_util.h" diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 3fa1ee0e0f8f..fb7fff082114 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include "cam_icp_hw_intf.h" #include "cam_hw_mgr_intf.h" #include "cam_hw_intf.h" diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h index 397592a4410c..eaa56a48802e 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h @@ -7,8 +7,8 @@ #define CAM_A5_HW_INTF_H #include -#include -#include +#include +#include #include "cam_hw_mgr_intf.h" #include "cam_icp_hw_intf.h" diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h index e02022435d8b..f2628e41640b 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h @@ -6,8 +6,8 @@ #ifndef CAM_BPS_HW_INTF_H #define CAM_BPS_HW_INTF_H -#include -#include +#include +#include #include "cam_hw_mgr_intf.h" #include "cam_icp_hw_intf.h" diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h index 836a56492447..ea14ee623fb3 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h @@ -6,8 +6,8 @@ #ifndef CAM_IPE_HW_INTF_H #define CAM_IPE_HW_INTF_H -#include -#include +#include +#include #include "cam_hw_mgr_intf.h" #include "cam_icp_hw_intf.h" diff --git a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index 25fbe2b8f6c5..d87c7ef238df 100644 --- a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -7,8 +7,8 @@ #define CAM_ICP_HW_MGR_INTF_H #include -#include -#include +#include +#include #include "cam_cpas_api.h" #define ICP_CLK_TURBO_HZ 600000000 diff --git a/drivers/cam_icp/icp_hw/ipe_hw/Makefile b/drivers/cam_icp/icp_hw/ipe_hw/Makefile index 5055e12dff2a..d57373c332e0 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/Makefile +++ b/drivers/cam_icp/icp_hw/ipe_hw/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core diff --git a/drivers/cam_isp/Makefile b/drivers/cam_isp/Makefile index 069350122c7b..86ad96d61cb7 100644 --- a/drivers/cam_isp/Makefile +++ b/drivers/cam_isp/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 1f5bd1048f5b..5aefa690697a 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -8,8 +8,8 @@ #include -#include -#include +#include +#include #include "cam_context.h" #include "cam_isp_hw_mgr_intf.h" diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c index b93ae3fd5b82..9c3f33181ae6 100644 --- a/drivers/cam_isp/cam_isp_dev.c +++ b/drivers/cam_isp/cam_isp_dev.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include "cam_isp_dev.h" #include "cam_hw_mgr_intf.h" #include "cam_isp_hw_mgr_intf.h" diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile index bdf6d3ee981b..d5ab83c81dd7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -3,7 +3,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ -ccflags-y += -I$(srctree)/techpack/camera/drivers/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c index ca2d443747f7..ebf8115723a5 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c @@ -10,7 +10,7 @@ #include "cam_debug_util.h" #include "cam_cdm_util.h" #include "cam_hw_intf.h" -#include "../../cam_ife_hw_mgr.h" +#include "cam_ife_hw_mgr.h" #include "cam_vfe_hw_intf.h" #include "cam_irq_controller.h" #include "cam_tasklet_util.h" diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 2a452c0d874d..990807b51acd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -10,7 +10,7 @@ #include "cam_debug_util.h" #include "cam_cdm_util.h" #include "cam_hw_intf.h" -#include "../../cam_ife_hw_mgr.h" +#include "cam_ife_hw_mgr.h" #include "cam_vfe_hw_intf.h" #include "cam_irq_controller.h" #include "cam_tasklet_util.h" diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index f0dea326a8b0..0ec5ba8c084f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -11,7 +11,7 @@ #include "cam_debug_util.h" #include "cam_cdm_util.h" #include "cam_hw_intf.h" -#include "../../cam_ife_hw_mgr.h" +#include "cam_ife_hw_mgr.h" #include "cam_vfe_hw_intf.h" #include "cam_irq_controller.h" #include "cam_tasklet_util.h" diff --git a/drivers/cam_jpeg/Makefile b/drivers/cam_jpeg/Makefile index 3b9bbdbedb7b..471f870e4c73 100644 --- a/drivers/cam_jpeg/Makefile +++ b/drivers/cam_jpeg/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync diff --git a/drivers/cam_jpeg/cam_jpeg_context.h b/drivers/cam_jpeg/cam_jpeg_context.h index 739dc6fd4525..3a11865a6051 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.h +++ b/drivers/cam_jpeg/cam_jpeg_context.h @@ -6,7 +6,7 @@ #ifndef _CAM_JPEG_CONTEXT_H_ #define _CAM_JPEG_CONTEXT_H_ -#include +#include #include "cam_context.h" #include "cam_jpeg_hw_mgr_intf.h" diff --git a/drivers/cam_lrme/Makefile b/drivers/cam_lrme/Makefile index afc585ebf374..72cdba4da04c 100644 --- a/drivers/cam_lrme/Makefile +++ b/drivers/cam_lrme/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync diff --git a/drivers/cam_req_mgr/Makefile b/drivers/cam_req_mgr/Makefile index 375d17133193..50599d879255 100644 --- a/drivers/cam_req_mgr/Makefile +++ b/drivers/cam_req_mgr/Makefile @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core -ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils -ccflags-y += -I$(srctree) +ccflags-y += -I$(src) obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_core.o\ cam_req_mgr_dev.o \ diff --git a/drivers/cam_req_mgr/cam_mem_mgr_api.h b/drivers/cam_req_mgr/cam_mem_mgr_api.h index 6141e7cc136b..0bbf094ee1e8 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr_api.h +++ b/drivers/cam_req_mgr/cam_mem_mgr_api.h @@ -7,7 +7,7 @@ #define _CAM_MEM_MGR_API_H_ #include -#include "../cam_smmu/cam_smmu_api.h" +#include "cam_smmu_api.h" /** * struct cam_mem_mgr_request_desc diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index b1a05cc14b9a..718942552bc7 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -10,8 +10,8 @@ #include #include #include -#include -#include +#include +#include #include "cam_req_mgr_dev.h" #include "cam_req_mgr_util.h" #include "cam_req_mgr_core.h" diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index 54ab1680b112..f833f667de97 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "cam_req_mgr_util.h" #include "cam_debug_util.h" diff --git a/drivers/cam_sensor_module/cam_actuator/Makefile b/drivers/cam_sensor_module/cam_actuator/Makefile index a51b8fea65bb..e61c6eeba3c0 100644 --- a/drivers/cam_sensor_module/cam_actuator/Makefile +++ b/drivers/cam_sensor_module/cam_actuator/Makefile @@ -1,12 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator_dev.o cam_actuator_core.o cam_actuator_soc.o diff --git a/drivers/cam_sensor_module/cam_cci/Makefile b/drivers/cam_sensor_module/cam_cci/Makefile index 82734cb81445..a1301bf41d5d 100644 --- a/drivers/cam_sensor_module/cam_cci/Makefile +++ b/drivers/cam_sensor_module/cam_cci/Makefile @@ -1,11 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media -ccflags-y += -I$(srctree)/techpack/camera/drivers/camera/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu ccflags-y += -I$(srctree) obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci_dev.o cam_cci_core.o cam_cci_soc.o diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.h b/drivers/cam_sensor_module/cam_cci/cam_cci_core.h index aeaee32502ec..739fd303b236 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.h @@ -6,7 +6,7 @@ #define _CAM_CCI_CORE_H_ #include -#include +#include #include "cam_cci_dev.h" #include "cam_cci_soc.h" diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 5f155df4dc44..e30574da5c0b 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -4,7 +4,7 @@ */ #include "cam_cci_dev.h" -#include "../../cam_req_mgr/cam_req_mgr_dev.h" +#include "cam_req_mgr_dev.h" #include "cam_cci_soc.h" #include "cam_cci_core.h" diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index 4bc1d34af3d2..439e3058a70b 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -18,14 +18,14 @@ #include #include #include -#include +#include #include #include #include #include #include #include -#include "../../cam_req_mgr/cam_subdev.h" +#include "cam_subdev.h" #include #include "cam_cci_hwreg.h" #include "cam_soc_util.h" diff --git a/drivers/cam_sensor_module/cam_csiphy/Makefile b/drivers/cam_sensor_module/cam_csiphy/Makefile index eb23b89c2108..d98b84574363 100644 --- a/drivers/cam_sensor_module/cam_csiphy/Makefile +++ b/drivers/cam_sensor_module/cam_csiphy/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index 3325071905ba..ba98d9adcc2d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -7,7 +7,7 @@ #include "cam_req_mgr_dev.h" #include "cam_csiphy_soc.h" #include "cam_csiphy_core.h" -#include +#include static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 2bae9a51529b..78c7a848cd81 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/cam_sensor_module/cam_eeprom/Makefile b/drivers/cam_sensor_module/cam_eeprom/Makefile index 850b16787c11..7a676c1135a0 100644 --- a/drivers/cam_sensor_module/cam_eeprom/Makefile +++ b/drivers/cam_sensor_module/cam_eeprom/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index c1320d97f644..6600c92d8132 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include "cam_eeprom_core.h" #include "cam_eeprom_soc.h" diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h index 41817e97eae1..66f8aaddc958 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "cam_soc_util.h" #include "cam_context.h" diff --git a/drivers/cam_sensor_module/cam_flash/Makefile b/drivers/cam_sensor_module/cam_flash/Makefile index dfc2bc2c8c8c..da9e9e1b19cb 100644 --- a/drivers/cam_sensor_module/cam_flash/Makefile +++ b/drivers/cam_sensor_module/cam_flash/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr @@ -9,6 +9,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash_dev.o cam_flash_core.o cam_flash_soc.o diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.h b/drivers/cam_sensor_module/cam_flash/cam_flash_core.h index 6cafe927cdbb..c382809dbb92 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.h @@ -6,7 +6,7 @@ #ifndef _CAM_FLASH_CORE_H_ #define _CAM_FLASH_CORE_H_ -#include +#include #include "cam_flash_dev.h" int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index 8bd5b9115f05..43ed13406e3d 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -17,8 +17,8 @@ #include #include #include -#include -#include +#include +#include #include "cam_req_mgr_util.h" #include "cam_req_mgr_interface.h" #include "cam_subdev.h" diff --git a/drivers/cam_sensor_module/cam_ois/Makefile b/drivers/cam_sensor_module/cam_ois/Makefile index 345203739517..fa7fabc0f055 100644 --- a/drivers/cam_sensor_module/cam_ois/Makefile +++ b/drivers/cam_sensor_module/cam_ois/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io @@ -8,6 +8,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois_dev.o cam_ois_core.o cam_ois_soc.o diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index 1808a2b2f0c6..788243ae9da0 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/cam_sensor_module/cam_res_mgr/Makefile b/drivers/cam_sensor_module/cam_res_mgr/Makefile index 5bc9889b40e9..1c8ccb0e3bf4 100644 --- a/drivers/cam_sensor_module/cam_res_mgr/Makefile +++ b/drivers/cam_sensor_module/cam_res_mgr/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -#ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +#ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr diff --git a/drivers/cam_sensor_module/cam_sensor/Makefile b/drivers/cam_sensor_module/cam_sensor/Makefile index 641b1c490329..d3a6fbb6c3e4 100644 --- a/drivers/cam_sensor_module/cam_sensor/Makefile +++ b/drivers/cam_sensor_module/cam_sensor/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr diff --git a/drivers/cam_sensor_module/cam_sensor_io/Makefile b/drivers/cam_sensor_module/cam_sensor_io/Makefile index 34ab4315aa92..5b11171fa087 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/Makefile +++ b/drivers/cam_sensor_module/cam_sensor_io/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h index 752b7fdd8a22..def8be55bc8b 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include "cam_cci_dev.h" #include "cam_sensor_io.h" diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h index 3c49212d2d6f..f70709997e69 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h @@ -6,7 +6,7 @@ #ifndef _CAM_SENSOR_IO_H_ #define _CAM_SENSOR_IO_H_ -#include +#include #include "cam_sensor_cmn_header.h" diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h index 7a9c44332c49..73d7ea9456ba 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include "cam_sensor_i2c.h" #define MAX_SPI_SIZE 110 diff --git a/drivers/cam_sensor_module/cam_sensor_utils/Makefile b/drivers/cam_sensor_module/cam_sensor_utils/Makefile index 4813d33a5bc5..d822b2a733cf 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/Makefile +++ b/drivers/cam_sensor_module/cam_sensor_utils/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index a5699342dce0..e43e8abe0809 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -13,8 +13,8 @@ #include #include #include -#include -#include +#include +#include #define MAX_REGULATOR 5 #define MAX_POWER_CONFIG 12 diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index f5ea2dc04a3d..0d82579e7999 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -5,7 +5,7 @@ #include #include "cam_sensor_util.h" -#include +#include "cam_mem_mgr.h" #include "cam_res_mgr_api.h" #define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h index 69679f8c76e7..c923efe61dc5 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -12,9 +12,9 @@ #include #include #include "cam_sensor_cmn_header.h" -#include "../../cam_req_mgr/cam_req_mgr_util.h" -#include "../../cam_req_mgr/cam_req_mgr_interface.h" -#include "../../cam_req_mgr/cam_mem_mgr.h" +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_interface.h" +#include #include "cam_soc_util.h" #include "cam_debug_util.h" #include "cam_sensor_io.h" diff --git a/drivers/cam_smmu/Makefile b/drivers/cam_smmu/Makefile index c82e3978d028..b674b48ceb2d 100644 --- a/drivers/cam_smmu/Makefile +++ b/drivers/cam_smmu/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index a60e02492a4c..478a00657f3b 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "cam_smmu_api.h" #include "cam_debug_util.h" diff --git a/drivers/cam_sync/Makefile b/drivers/cam_sync/Makefile index e15ed0ce8931..40efdf4dd794 100644 --- a/drivers/cam_sync/Makefile +++ b/drivers/cam_sync/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-$(CONFIG_MSM_GLOBAL_SYNX) += -I$(srctree)/drivers/media/platform/msm/synx ccflags-y += -I$(src) diff --git a/drivers/cam_utils/Makefile b/drivers/cam_utils/Makefile index fb8c48eeeb04..e17c2f50bb95 100644 --- a/drivers/cam_utils/Makefile +++ b/drivers/cam_utils/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(srctree)/techpack/camera/include/uapi/media +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ diff --git a/drivers/cam_utils/cam_trace.c b/drivers/cam_utils/cam_trace.c index d4a6c9279081..9b45091b4b85 100644 --- a/drivers/cam_utils/cam_trace.c +++ b/drivers/cam_utils/cam_trace.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ /* Instantiate tracepoints */ diff --git a/drivers/cam_utils/cam_trace.h b/drivers/cam_utils/cam_trace.h index 95bc95da9e75..838997590771 100644 --- a/drivers/cam_utils/cam_trace.h +++ b/drivers/cam_utils/cam_trace.h @@ -14,7 +14,7 @@ #define TRACE_INCLUDE_FILE ../../techpack/camera/drivers/cam_utils/cam_trace #include -#include +#include #include "cam_req_mgr_core.h" #include "cam_req_mgr_interface.h" #include "cam_context.h" diff --git a/include/uapi/media/cam_cpas.h b/include/uapi/media/cam_cpas.h index a3d3ca9d5a71..b85ab068f9e8 100644 --- a/include/uapi/media/cam_cpas.h +++ b/include/uapi/media/cam_cpas.h @@ -6,7 +6,7 @@ #ifndef __UAPI_CAM_CPAS_H__ #define __UAPI_CAM_CPAS_H__ -#include "cam_defs.h" +#include #define CAM_FAMILY_CAMERA_SS 1 #define CAM_FAMILY_CPAS_SS 2 diff --git a/include/uapi/media/cam_fd.h b/include/uapi/media/cam_fd.h index f456683b3779..126be4555f69 100644 --- a/include/uapi/media/cam_fd.h +++ b/include/uapi/media/cam_fd.h @@ -1,12 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_CAM_FD_H__ #define __UAPI_CAM_FD_H__ -#include "cam_defs.h" +#include #define CAM_FD_MAX_FACES 35 #define CAM_FD_RAW_RESULT_ENTRIES 512 diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h index ac683bffa4ce..4b5419d2f21d 100644 --- a/include/uapi/media/cam_icp.h +++ b/include/uapi/media/cam_icp.h @@ -6,8 +6,8 @@ #ifndef __UAPI_CAM_ICP_H__ #define __UAPI_CAM_ICP_H__ -#include "cam_defs.h" -#include "cam_cpas.h" +#include +#include /* icp, ipe, bps, cdm(ipe/bps) are used in querycap */ #define CAM_ICP_DEV_TYPE_A5 1 diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index ee6440a90023..956ad9880fee 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -6,10 +6,10 @@ #ifndef __UAPI_CAM_ISP_H__ #define __UAPI_CAM_ISP_H__ -#include "cam_defs.h" -#include "cam_isp_vfe.h" -#include "cam_isp_ife.h" -#include "cam_cpas.h" +#include +#include +#include +#include /* ISP driver name */ #define CAM_ISP_DEV_NAME "cam-isp" diff --git a/include/uapi/media/cam_jpeg.h b/include/uapi/media/cam_jpeg.h index 6513bbae740b..fd0ed2a2cfdb 100644 --- a/include/uapi/media/cam_jpeg.h +++ b/include/uapi/media/cam_jpeg.h @@ -1,12 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_CAM_JPEG_H__ #define __UAPI_CAM_JPEG_H__ -#include "cam_defs.h" +#include /* enc, dma, cdm(enc/dma) are used in querycap */ #define CAM_JPEG_DEV_TYPE_ENC 0 diff --git a/include/uapi/media/cam_lrme.h b/include/uapi/media/cam_lrme.h index 90e3e76e0624..e3bd9449f7ef 100644 --- a/include/uapi/media/cam_lrme.h +++ b/include/uapi/media/cam_lrme.h @@ -1,12 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_CAM_LRME_H__ #define __UAPI_CAM_LRME_H__ -#include "cam_defs.h" +#include /* LRME Resource Types */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index a8c12e2d7c0d..a1278dda9b09 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -10,7 +10,7 @@ #include #include #include -#include "cam_defs.h" +#include #define CAM_REQ_MGR_VNODE_NAME "cam-req-mgr-devnode" diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h index 5e1918a9a116..514e8bd946cd 100644 --- a/include/uapi/media/cam_sensor.h +++ b/include/uapi/media/cam_sensor.h @@ -8,7 +8,7 @@ #include #include -#include "cam_defs.h" +#include #define CAM_SENSOR_PROBE_CMD (CAM_COMMON_OPCODE_MAX + 1) #define CAM_FLASH_MAX_LED_TRIGGERS 3 -- GitLab From 3b1e74e59b958b943bba405f7b95ccd86a51daeb Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Tue, 23 Jul 2019 19:54:43 +0800 Subject: [PATCH 054/410] msm: camera: eeprom: Release the mutex even though got error Release the mutex even though got error. Change-Id: Iaeec418ce7db4623cede6c922869c6f8c69ab595 Signed-off-by: Depeng Shao Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 6600c92d8132..c50230309c57 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -1450,7 +1450,7 @@ int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) &eeprom_cap, sizeof(struct cam_eeprom_query_cap_t))) { CAM_ERR(CAM_EEPROM, "Failed Copy to User"); - return -EFAULT; + rc = -EFAULT; goto release_mutex; } CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info); -- GitLab From 54070a35f24367d5663490d7ae4ad1f1886e8b5d Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 30 Jul 2019 17:21:46 -0700 Subject: [PATCH 055/410] msm: camera: ife: Add new controller for RUP IRQ Currently EPOCH IRQ handling is at a higher priority compared to RUP IRQ as RUP is fired at bus level. If RUP IRQ is not scheduled for handling by the time we receive EPOCH IRQ, EPOCH IRQ will be processed first and this will lead to missed SOF notification as the active request list might be empty. This change sets priority of both IRQs to the same by utilizing a new IRQ controller that is tasked with handling RUP from BUS. BUF_DONE is also subscribed to the same VFE top level BUS_WR IRQ but with a lower priority. IRQs for CAMIF Lite and RDI are subscribed to only if the ctx is RDI only. Change-Id: Id844ffe291e21ecfc7f7ed6fc53baf7e79dd2184 Signed-off-by: Venkat Chinta Signed-off-by: Mukund Madhusudan Atre --- .../irq_controller/cam_irq_controller.c | 36 +++++-- .../irq_controller/cam_irq_controller.h | 6 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 3 +- .../vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c | 2 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 2 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 97 +++++++++++++++---- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c | 6 +- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 50 ++++++++-- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 4 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 50 ++++++++-- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 4 +- 11 files changed, 207 insertions(+), 53 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index 8ed8b9f8b1a8..cc1fe18e05fd 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include @@ -53,6 +53,8 @@ struct cam_irq_evt_handler { * @clear_reg_offset: Offset of IRQ CLEAR register * @status_reg_offset: Offset of IRQ STATUS register * @top_half_enable_mask: Array of enabled bit_mask sorted by priority + * @pclear_mask: Partial mask to be cleared in case entire status + * register is not to be cleared */ struct cam_irq_register_obj { uint32_t index; @@ -60,6 +62,7 @@ struct cam_irq_register_obj { uint32_t clear_reg_offset; uint32_t status_reg_offset; uint32_t top_half_enable_mask[CAM_IRQ_PRIORITY_MAX]; + uint32_t pclear_mask; }; /** @@ -84,6 +87,8 @@ struct cam_irq_register_obj { * @hdl_idx: Unique identity of handler assigned on Subscribe. * Used to Unsubscribe. * @lock: Lock for use by controller + * @clear_all: Flag to indicate whether to clear entire status + * register */ struct cam_irq_controller { const char *name; @@ -98,6 +103,7 @@ struct cam_irq_controller { uint32_t hdl_idx; spinlock_t lock; struct cam_irq_th_payload th_payload; + bool clear_all; }; int cam_irq_controller_deinit(void **irq_controller) @@ -125,7 +131,8 @@ int cam_irq_controller_deinit(void **irq_controller) int cam_irq_controller_init(const char *name, void __iomem *mem_base, struct cam_irq_controller_reg_info *register_info, - void **irq_controller) + void **irq_controller, + bool clear_all) { struct cam_irq_controller *controller = NULL; int i, rc = 0; @@ -194,6 +201,7 @@ int cam_irq_controller_init(const char *name, controller->global_clear_bitmask = register_info->global_clear_bitmask; controller->global_clear_offset = register_info->global_clear_offset; controller->mem_base = mem_base; + controller->clear_all = clear_all; CAM_DBG(CAM_IRQ_CTRL, "global_clear_bitmask: 0x%x", controller->global_clear_bitmask); @@ -321,6 +329,9 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, controller->irq_register_arr[i].top_half_enable_mask[priority] |= evt_bit_mask_arr[i]; + controller->irq_register_arr[i].pclear_mask + |= evt_bit_mask_arr[i]; + irq_mask = cam_io_r_mb(controller->mem_base + controller->irq_register_arr[i].mask_reg_offset); irq_mask |= evt_bit_mask_arr[i]; @@ -610,7 +621,8 @@ static void cam_irq_controller_th_processing( evt_handler->bottom_half, &bh_cmd); if (rc || !bh_cmd) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "No payload, IRQ handling frozen"); + "No payload, IRQ handling frozen for %s", + controller->name); continue; } } @@ -689,11 +701,19 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv) for (i = 0; i < controller->num_registers; i++) { irq_register = &controller->irq_register_arr[i]; controller->irq_status_arr[i] = cam_io_r_mb( - controller->mem_base + - controller->irq_register_arr[i].status_reg_offset); - cam_io_w_mb(controller->irq_status_arr[i], - controller->mem_base + - controller->irq_register_arr[i].clear_reg_offset); + controller->mem_base + irq_register->status_reg_offset); + + if (controller->clear_all) + cam_io_w_mb(controller->irq_status_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + else + cam_io_w_mb( + controller->irq_register_arr[i].pclear_mask & + controller->irq_status_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "Read irq status%d (0x%x) = 0x%x", i, controller->irq_register_arr[i].status_reg_offset, controller->irq_status_arr[i]); diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h index caf21c5caf12..8fa0e951b714 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IRQ_CONTROLLER_H_ @@ -131,6 +131,7 @@ struct cam_irq_bh_api { * @register_info: Register Info structure associated with this Controller * @irq_controller: Pointer to IRQ Controller that will be filled if * initialization is successful + * @clear_all: Flag to indicate whether to clear entire status register * * @return: 0: Success * Negative: Failure @@ -138,7 +139,8 @@ struct cam_irq_bh_api { int cam_irq_controller_init(const char *name, void __iomem *mem_base, struct cam_irq_controller_reg_info *register_info, - void **irq_controller); + void **irq_controller, + bool clear_all); /* * cam_irq_controller_subscribe_irq() diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 0fe3e9c79f35..0244e41d5a03 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -669,7 +669,8 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, rc = cam_irq_controller_init(drv_name, CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX), - vfe_hw_info->irq_reg_info, &core_info->vfe_irq_controller); + vfe_hw_info->irq_reg_info, &core_info->vfe_irq_controller, + true); if (rc) { CAM_ERR(CAM_ISP, "Error, cam_irq_controller_init failed rc = %d", rc); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c index ebf8115723a5..314ebff70fc0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c @@ -1107,7 +1107,7 @@ int cam_vfe_bus_rd_ver1_init( rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, &bus_rd_hw_info->common_reg.irq_reg_info, - &bus_priv->common_data.bus_irq_controller); + &bus_priv->common_data.bus_irq_controller, true); if (rc) { CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); goto free_bus_priv; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 990807b51acd..9094f1409a66 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -3622,7 +3622,7 @@ int cam_vfe_bus_ver2_init( rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, &ver2_hw_info->common_reg.irq_reg_info, - &bus_priv->common_data.bus_irq_controller); + &bus_priv->common_data.bus_irq_controller, true); if (rc) { CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); goto free_bus_priv; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 0ec5ba8c084f..16767270a272 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -66,6 +66,7 @@ struct cam_vfe_bus_ver3_common_data { void __iomem *mem_base; struct cam_hw_intf *hw_intf; void *bus_irq_controller; + void *rup_irq_controller; void *vfe_irq_controller; struct cam_vfe_bus_ver3_reg_offset_common *common_reg; uint32_t io_buf_update[ @@ -180,7 +181,8 @@ struct cam_vfe_bus_ver3_priv { struct list_head free_comp_grp; struct list_head used_comp_grp; - int irq_handle; + int bus_irq_handle; + int rup_irq_handle; int error_irq_handle; void *tasklet_info; }; @@ -2159,6 +2161,10 @@ static int cam_vfe_bus_ver3_start_vfe_out( return -EFAULT; } + if ((common_data->is_lite || source_group > CAM_VFE_BUS_VER3_SRC_GRP_0) + && !vfe_out->rdi_only_ctx) + goto end; + if (!common_data->rup_irq_handle[source_group]) { memset(rup_irq_reg_mask, 0, sizeof(rup_irq_reg_mask)); rup_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0] |= @@ -2171,8 +2177,8 @@ static int cam_vfe_bus_ver3_start_vfe_out( common_data->rup_irq_handle[source_group] = cam_irq_controller_subscribe_irq( - common_data->bus_irq_controller, - CAM_IRQ_PRIORITY_1, + common_data->rup_irq_controller, + CAM_IRQ_PRIORITY_0, rup_irq_reg_mask, vfe_out, cam_vfe_bus_ver3_handle_rup_top_half, @@ -2222,7 +2228,7 @@ static int cam_vfe_bus_ver3_stop_vfe_out( if (common_data->rup_irq_handle[rsrc_data->source_group]) { rc = cam_irq_controller_unsubscribe_irq( - common_data->bus_irq_controller, + common_data->rup_irq_controller, common_data->rup_irq_handle[rsrc_data->source_group]); common_data->rup_irq_handle[rsrc_data->source_group] = 0; } @@ -2460,19 +2466,32 @@ static void cam_vfe_bus_ver3_print_dimensions( wm_data->en_cfg); } -static int cam_vfe_bus_ver3_handle_irq(uint32_t evt_id, +static int cam_vfe_bus_ver3_handle_bus_irq(uint32_t evt_id, struct cam_irq_th_payload *th_payload) { struct cam_vfe_bus_ver3_priv *bus_priv; int rc = 0; - bus_priv = th_payload->handler_priv; + bus_priv = th_payload->handler_priv; CAM_DBG(CAM_ISP, "Enter"); rc = cam_irq_controller_handle_irq(evt_id, bus_priv->common_data.bus_irq_controller); return (rc == IRQ_HANDLED) ? 0 : -EINVAL; } +static int cam_vfe_bus_ver3_handle_rup_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + int rc = 0; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "Enter"); + rc = cam_irq_controller_handle_irq(evt_id, + bus_priv->common_data.rup_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; +} + static int cam_vfe_bus_ver3_err_irq_top_half(uint32_t evt_id, struct cam_irq_th_payload *th_payload) { @@ -3539,19 +3558,35 @@ static int cam_vfe_bus_ver3_init_hw(void *hw_priv, top_irq_reg_mask[0] = (1 << bus_priv->top_irq_shift); - bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->bus_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_4, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_ver3_handle_bus_irq, + NULL, + NULL, + NULL); + + if (bus_priv->bus_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS (buf_done) IRQ"); + bus_priv->bus_irq_handle = 0; + return -EFAULT; + } + + bus_priv->rup_irq_handle = cam_irq_controller_subscribe_irq( bus_priv->common_data.vfe_irq_controller, CAM_IRQ_PRIORITY_2, top_irq_reg_mask, bus_priv, - cam_vfe_bus_ver3_handle_irq, + cam_vfe_bus_ver3_handle_rup_irq, NULL, NULL, NULL); - if (bus_priv->irq_handle < 1) { - CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); - bus_priv->irq_handle = 0; + if (bus_priv->rup_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS (rup) IRQ"); + bus_priv->rup_irq_handle = 0; return -EFAULT; } @@ -3609,11 +3644,18 @@ static int cam_vfe_bus_ver3_deinit_hw(void *hw_priv, bus_priv->error_irq_handle = 0; } - if (bus_priv->irq_handle) { + if (bus_priv->bus_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->bus_irq_handle); + bus_priv->bus_irq_handle = 0; + } + + if (bus_priv->rup_irq_handle) { rc = cam_irq_controller_unsubscribe_irq( bus_priv->common_data.vfe_irq_controller, - bus_priv->irq_handle); - bus_priv->irq_handle = 0; + bus_priv->rup_irq_handle); + bus_priv->rup_irq_handle = 0; } spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); @@ -3698,6 +3740,7 @@ int cam_vfe_bus_ver3_init( struct cam_vfe_bus *vfe_bus_local; struct cam_vfe_bus_ver3_hw_info *ver3_hw_info = bus_hw_info; struct cam_vfe_soc_private *soc_private = NULL; + char rup_controller_name[12] = ""; CAM_DBG(CAM_ISP, "Enter"); @@ -3757,9 +3800,21 @@ int cam_vfe_bus_ver3_init( rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, &ver3_hw_info->common_reg.irq_reg_info, - &bus_priv->common_data.bus_irq_controller); + &bus_priv->common_data.bus_irq_controller, true); if (rc) { - CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + CAM_ERR(CAM_ISP, "Init bus_irq_controller failed"); + goto free_bus_priv; + } + + strlcat(rup_controller_name, drv_name, sizeof(rup_controller_name)); + strlcat(rup_controller_name, "_rup", sizeof(rup_controller_name)); + + rc = cam_irq_controller_init(rup_controller_name, + bus_priv->common_data.mem_base, + &ver3_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.rup_irq_controller, false); + if (rc) { + CAM_ERR(CAM_ISP, "Init rup_irq_controller failed"); goto free_bus_priv; } @@ -3812,7 +3867,7 @@ int cam_vfe_bus_ver3_init( vfe_bus_local->hw_ops.stop = cam_vfe_bus_ver3_stop_hw; vfe_bus_local->hw_ops.init = cam_vfe_bus_ver3_init_hw; vfe_bus_local->hw_ops.deinit = cam_vfe_bus_ver3_deinit_hw; - vfe_bus_local->top_half_handler = cam_vfe_bus_ver3_handle_irq; + vfe_bus_local->top_half_handler = NULL; vfe_bus_local->bottom_half_handler = NULL; vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_ver3_process_cmd; @@ -3910,7 +3965,13 @@ int cam_vfe_bus_ver3_deinit( &bus_priv->common_data.bus_irq_controller); if (rc) CAM_ERR(CAM_ISP, - "Deinit IRQ Controller failed rc=%d", rc); + "Deinit BUS IRQ Controller failed rc=%d", rc); + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.rup_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit RUP IRQ Controller failed rc=%d", rc); mutex_destroy(&bus_priv->common_data.bus_mutex); kfree(vfe_bus_local->bus_priv); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c index 0c1179c69776..9ea8d74a35ca 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -287,7 +287,7 @@ static int cam_vfe_camif_lite_resource_start( if (!rsrc_data->irq_err_handle) { rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_1, + CAM_IRQ_PRIORITY_0, err_irq_mask, camif_lite_res, cam_vfe_camif_lite_err_irq_top_half, @@ -448,13 +448,13 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( } if (irq_status0 & camif_lite_priv->reg_data->dual_pd_reg_upd_irq_mask) { - CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite hReceived REG_UPDATE_ACK", + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received REG_UPDATE_ACK", evt_info.hw_idx); ret = CAM_VFE_IRQ_STATUS_SUCCESS; } if (irq_status0 & camif_lite_priv->reg_data->lite_eof_irq_mask) { - CAM_DBG(CAM_ISP, "VF:%d CAMIF Lite Received EOF", + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received EOF", evt_info.hw_idx); ret = CAM_VFE_IRQ_STATUS_SUCCESS; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index e71754098e80..0fe61247055a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -33,6 +33,7 @@ struct cam_vfe_mux_camif_lite_data { void *priv; int irq_err_handle; int irq_handle; + int sof_irq_handle; void *vfe_irq_controller; struct list_head free_payload_list; spinlock_t spin_lock; @@ -312,17 +313,17 @@ static int cam_vfe_camif_lite_resource_start( cam_io_w_mb(rsrc_data->reg_data->top_debug_cfg_en, rsrc_data->mem_base + rsrc_data->common_reg->top_debug_cfg); - err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = - rsrc_data->reg_data->error_irq_mask0; - err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = - rsrc_data->reg_data->error_irq_mask2; + if (!camif_lite_res->rdi_only_ctx) + goto subscribe_err; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = - rsrc_data->reg_data->subscribe_irq_mask1; + rsrc_data->reg_data->epoch0_irq_mask | + rsrc_data->reg_data->eof_irq_mask; if (!rsrc_data->irq_handle) { rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_0, + CAM_IRQ_PRIORITY_3, irq_mask, camif_lite_res, camif_lite_res->top_half_handler, @@ -336,16 +337,44 @@ static int cam_vfe_camif_lite_resource_start( } } + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->sof_irq_mask; + + if (!rsrc_data->sof_irq_handle) { + rsrc_data->sof_irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + irq_mask, + camif_lite_res, + camif_lite_res->top_half_handler, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->sof_irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->sof_irq_handle = 0; + } + } + +subscribe_err: + + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = + rsrc_data->reg_data->error_irq_mask2; + if (!rsrc_data->irq_err_handle) { rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_1, + CAM_IRQ_PRIORITY_0, err_irq_mask, camif_lite_res, cam_vfe_camif_lite_err_irq_top_half, camif_lite_res->bottom_half_handler, camif_lite_res->tasklet_info, &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); rc = -ENOMEM; @@ -653,6 +682,13 @@ static int cam_vfe_camif_lite_resource_stop( rsrc_data->irq_handle = 0; } + if (rsrc_data->sof_irq_handle > 0) { + cam_irq_controller_unsubscribe_irq( + rsrc_data->vfe_irq_controller, + rsrc_data->sof_irq_handle); + rsrc_data->sof_irq_handle = 0; + } + if (rsrc_data->irq_err_handle > 0) { cam_irq_controller_unsubscribe_irq( rsrc_data->vfe_irq_controller, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index d641d647b65a..0ed1c6ede3ce 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -436,7 +436,7 @@ static int cam_vfe_camif_resource_start( if (!rsrc_data->irq_handle) { rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_0, + CAM_IRQ_PRIORITY_1, irq_mask, camif_res, camif_res->top_half_handler, @@ -453,7 +453,7 @@ static int cam_vfe_camif_resource_start( if (!rsrc_data->irq_err_handle) { rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_1, + CAM_IRQ_PRIORITY_0, err_irq_mask, camif_res, cam_vfe_camif_err_irq_top_half, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 7e9aa91689c3..8cf2fa9f7f93 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -34,6 +34,7 @@ struct cam_vfe_mux_camif_ver3_data { void *priv; int irq_err_handle; int irq_handle; + int sof_irq_handle; void *vfe_irq_controller; struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_EVT_MAX]; struct list_head free_payload_list; @@ -364,12 +365,6 @@ static int cam_vfe_camif_ver3_resource_start( memset(irq_mask, 0, sizeof(irq_mask)); rsrc_data = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; - err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = - rsrc_data->reg_data->error_irq_mask0; - err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = - rsrc_data->reg_data->error_irq_mask2; - irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = - rsrc_data->reg_data->subscribe_irq_mask1; soc_private = rsrc_data->soc_info->soc_private; @@ -488,16 +483,26 @@ static int cam_vfe_camif_ver3_resource_start( rsrc_data->common_reg->diag_config); } + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = + rsrc_data->reg_data->error_irq_mask2; + + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->epoch0_irq_mask | + rsrc_data->reg_data->eof_irq_mask; + if (!rsrc_data->irq_handle) { rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_0, + CAM_IRQ_PRIORITY_3, irq_mask, camif_res, camif_res->top_half_handler, camif_res->bottom_half_handler, camif_res->tasklet_info, &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); rc = -ENOMEM; @@ -505,16 +510,38 @@ static int cam_vfe_camif_ver3_resource_start( } } + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->sof_irq_mask; + + if (!rsrc_data->sof_irq_handle) { + rsrc_data->sof_irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + irq_mask, + camif_res, + camif_res->top_half_handler, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + + if (rsrc_data->sof_irq_handle < 1) { + CAM_ERR(CAM_ISP, "SOF IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->sof_irq_handle = 0; + } + } + if (!rsrc_data->irq_err_handle) { rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_1, + CAM_IRQ_PRIORITY_0, err_irq_mask, camif_res, cam_vfe_camif_ver3_err_irq_top_half, camif_res->bottom_half_handler, camif_res->tasklet_info, &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); rc = -ENOMEM; @@ -645,6 +672,13 @@ static int cam_vfe_camif_ver3_resource_stop( camif_priv->irq_handle = 0; } + if (camif_priv->sof_irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, + camif_priv->sof_irq_handle); + camif_priv->sof_irq_handle = 0; + } + if (camif_priv->irq_err_handle) { cam_irq_controller_unsubscribe_irq( camif_priv->vfe_irq_controller, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 3cc92551b79c..381de6b48fe9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -243,7 +243,7 @@ static int cam_vfe_rdi_resource_start( if (!rsrc_data->irq_err_handle) { rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_1, + CAM_IRQ_PRIORITY_0, err_irq_mask, rdi_res, cam_vfe_rdi_err_irq_top_half, @@ -263,7 +263,7 @@ static int cam_vfe_rdi_resource_start( if (!rsrc_data->irq_handle) { rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, - CAM_IRQ_PRIORITY_0, + CAM_IRQ_PRIORITY_1, irq_mask, rdi_res, rdi_res->top_half_handler, -- GitLab From e8ceba2d024cda1b635a75e3c793aac1f1311373 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 12 Aug 2019 16:59:32 -0700 Subject: [PATCH 056/410] msm: camera: isp: Send shutter notification Shutter notification must be sent when moving request to free list if it was not sent out earlier due to missed EPOCH IRQ or delayed EPOCH IRQ handling. Change-Id: I9b3b039827bea24814fbea34e61abfc938f6bf2d Signed-off-by: Venkat Chinta Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_isp/cam_isp_context.c | 119 ++++++++++++++++-------------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 638478cb56e1..9dfd4fb363f4 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -387,6 +387,63 @@ static uint64_t __cam_isp_ctx_get_event_ts(uint32_t evt_id, void *evt_data) return ts; } +static void __cam_isp_ctx_send_sof_boot_timestamp( + struct cam_isp_context *ctx_isp, uint64_t request_id, + uint32_t sof_event_status) +{ + struct cam_req_mgr_message req_msg; + + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; + req_msg.u.frame_msg.request_id = request_id; + req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp; + req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.frame_msg.sof_status = sof_event_status; + + CAM_DBG(CAM_ISP, + "request id:%lld frame number:%lld boot time stamp:0x%llx", + request_id, ctx_isp->frame_id, + ctx_isp->boot_timestamp); + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS, + V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the boot time for req id:%lld", + request_id); +} + + +static void __cam_isp_ctx_send_sof_timestamp( + struct cam_isp_context *ctx_isp, uint64_t request_id, + uint32_t sof_event_status) +{ + struct cam_req_mgr_message req_msg; + + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; + req_msg.u.frame_msg.request_id = request_id; + req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val; + req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.frame_msg.sof_status = sof_event_status; + + CAM_DBG(CAM_ISP, + "request id:%lld frame number:%lld SOF time stamp:0x%llx", + request_id, ctx_isp->frame_id, + ctx_isp->sof_timestamp_val); + CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status); + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the sof time for req id:%lld", + request_id); + + __cam_isp_ctx_send_sof_boot_timestamp(ctx_isp, + request_id, sof_event_status); + +} + static void __cam_isp_ctx_handle_buf_done_fail_log( uint64_t request_id, struct cam_isp_ctx_req *req_isp) { @@ -537,6 +594,11 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { + if (ctx_isp->reported_req_id < buf_done_req_id) { + ctx_isp->reported_req_id = buf_done_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); @@ -551,63 +613,6 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( return rc; } -static void __cam_isp_ctx_send_sof_boot_timestamp( - struct cam_isp_context *ctx_isp, uint64_t request_id, - uint32_t sof_event_status) -{ - struct cam_req_mgr_message req_msg; - - req_msg.session_hdl = ctx_isp->base->session_hdl; - req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; - req_msg.u.frame_msg.request_id = request_id; - req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp; - req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; - req_msg.u.frame_msg.sof_status = sof_event_status; - - CAM_DBG(CAM_ISP, - "request id:%lld frame number:%lld boot time stamp:0x%llx", - request_id, ctx_isp->frame_id, - ctx_isp->boot_timestamp); - - if (cam_req_mgr_notify_message(&req_msg, - V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS, - V4L_EVENT_CAM_REQ_MGR_EVENT)) - CAM_ERR(CAM_ISP, - "Error in notifying the boot time for req id:%lld", - request_id); -} - - -static void __cam_isp_ctx_send_sof_timestamp( - struct cam_isp_context *ctx_isp, uint64_t request_id, - uint32_t sof_event_status) -{ - struct cam_req_mgr_message req_msg; - - req_msg.session_hdl = ctx_isp->base->session_hdl; - req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; - req_msg.u.frame_msg.request_id = request_id; - req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val; - req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; - req_msg.u.frame_msg.sof_status = sof_event_status; - - CAM_DBG(CAM_ISP, - "request id:%lld frame number:%lld SOF time stamp:0x%llx", - request_id, ctx_isp->frame_id, - ctx_isp->sof_timestamp_val); - CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status); - - if (cam_req_mgr_notify_message(&req_msg, - V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT)) - CAM_ERR(CAM_ISP, - "Error in notifying the sof time for req id:%lld", - request_id); - - __cam_isp_ctx_send_sof_boot_timestamp(ctx_isp, - request_id, sof_event_status); - -} - static int __cam_isp_ctx_reg_upd_in_epoch_state( struct cam_isp_context *ctx_isp, void *evt_data) { -- GitLab From d7a8426091e2f3fed27803ac95e09d3cac6eb20d Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Sat, 10 Aug 2019 15:47:26 -0700 Subject: [PATCH 057/410] msm: camera: utils: Use pr_info for camera logs Use pr_info for camera warning and error logs to avoid sending to console (assuming info logs are disabled to console). All camera warning and error logs are anyway tagged with CAM_WARN and CAM_ERR, so using pr_info doesn't cause any information loss. Change-Id: Ib23fbad47c1dce4c45e3413d775303d681a1ff86 Signed-off-by: Pavan Kumar Chilamkurthi Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_utils/cam_debug_util.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 55f316b41da4..0491e6a214ac 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -75,7 +75,7 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_ERR(__module, fmt, args...) \ - pr_err("CAM_ERR: %s: %s: %d " fmt "\n", \ + pr_info("CAM_ERR: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) /* * CAM_WARN @@ -86,7 +86,7 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_WARN(__module, fmt, args...) \ - pr_warn("CAM_WARN: %s: %s: %d " fmt "\n", \ + pr_info("CAM_WARN: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) /* * CAM_INFO @@ -128,7 +128,7 @@ const char *cam_get_module_name(unsigned int module_id); * @brief : This Macro will print error print logs with ratelimit */ #define CAM_ERR_RATE_LIMIT(__module, fmt, args...) \ - pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ + pr_info_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) /* * CAM_WARN_RATE_LIMIT @@ -139,7 +139,7 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_WARN_RATE_LIMIT(__module, fmt, args...) \ - pr_warn_ratelimited("CAM_WARN: %s: %s: %d " fmt "\n", \ + pr_info_ratelimited("CAM_WARN: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) /* @@ -158,7 +158,7 @@ const char *cam_get_module_name(unsigned int module_id); (interval * HZ), \ burst); \ if (__ratelimit(&_rs)) \ - pr_warn( \ + pr_info( \ "CAM_WARN: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, \ __LINE__, ##args); \ @@ -202,7 +202,7 @@ const char *cam_get_module_name(unsigned int module_id); (interval * HZ), \ burst); \ if (__ratelimit(&_rs)) \ - pr_err( \ + pr_info( \ "CAM_ERR: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, \ __LINE__, ##args); \ -- GitLab From 6bf14f8fd417a345a9d488af9d358e28a841dac9 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Sat, 10 Aug 2019 02:56:50 -0700 Subject: [PATCH 058/410] msm: camera: isp: Look at next request for BUF_DONE event If the resource for which BUF_DONE event has come is already signalled in the oldest request, this BUF_DONE could be for the next request in the list. This can happen if the IRQ handling for BUF_DONE is delayed and by the time it is handled if the resources for the next request are already signalled along with other pending resources for the oldest request, we might handle resources which corresponds to next request first. If we do not look into next request and thus if we ignore these BUF_DONEs, we will never be done with the next request. Change-Id: I1b20aff0a68172bc8794d2c37f088ba2539d173d Signed-off-by: Pavan Kumar Chilamkurthi Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_isp/cam_isp_context.c | 166 +++++++++++++++++++++++------- 1 file changed, 129 insertions(+), 37 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 9dfd4fb363f4..c51b8e4a2e5e 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -456,48 +456,49 @@ static void __cam_isp_ctx_handle_buf_done_fail_log( return; } - CAM_ERR(CAM_ISP, + CAM_WARN(CAM_ISP, "Prev Req[%lld] : num_out=%d, num_acked=%d, bubble : report=%d, detected=%d", request_id, req_isp->num_fence_map_out, req_isp->num_acked, req_isp->bubble_report, req_isp->bubble_detected); - CAM_ERR(CAM_ISP, + CAM_WARN(CAM_ISP, "Resource Handles that fail to generate buf_done in prev frame"); for (i = 0; i < req_isp->num_fence_map_out; i++) { - if (req_isp->fence_map_out[i].sync_id != -1) - CAM_ERR(CAM_ISP, + if (req_isp->fence_map_out[i].sync_id != -1) { + CAM_WARN(CAM_ISP, "Resource_Handle: [%s][0x%x] Sync_ID: [0x%x]", __cam_isp_resource_handle_id_to_type( req_isp->fence_map_out[i].resource_handle), req_isp->fence_map_out[i].resource_handle, req_isp->fence_map_out[i].sync_id); + } } } -static int __cam_isp_ctx_handle_buf_done_in_activated_state( +static int __cam_isp_ctx_handle_buf_done_for_request( struct cam_isp_context *ctx_isp, + struct cam_ctx_request *req, struct cam_isp_hw_done_event_data *done, - uint32_t bubble_state) + uint32_t bubble_state, + struct cam_isp_hw_done_event_data *done_next_req) { int rc = 0; int i, j; - struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; uint64_t buf_done_req_id; - if (list_empty(&ctx->active_req_list)) { - CAM_DBG(CAM_ISP, "Buf done with no active request!"); - goto end; - } + trace_cam_buf_done("ISP", ctx, req); - CAM_DBG(CAM_ISP, "Enter with bubble_state %d", bubble_state); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; - req = list_first_entry(&ctx->active_req_list, - struct cam_ctx_request, list); + CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", + bubble_state, req_isp->bubble_detected); - trace_cam_buf_done("ISP", ctx, req); + if (done_next_req) { + done_next_req->num_handles = 0; + done_next_req->timestamp = done->timestamp; + } - req_isp = (struct cam_isp_ctx_req *) req->req_priv; for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { if (done->resource_handle[i] == @@ -514,8 +515,18 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( } if (req_isp->fence_map_out[j].sync_id == -1) { - __cam_isp_ctx_handle_buf_done_fail_log( - req->request_id, req_isp); + CAM_WARN(CAM_ISP, + "Duplicate BUF_DONE for req %lld : i=%d, j=%d, res=%s", + req->request_id, i, j, + __cam_isp_resource_handle_id_to_type( + done->resource_handle[i])); + + if (done_next_req) { + done_next_req->resource_handle + [done_next_req->num_handles++] = + done->resource_handle[i]; + } + continue; } @@ -609,7 +620,66 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); -end: + + return rc; +} + +static int __cam_isp_ctx_handle_buf_done_in_activated_state( + struct cam_isp_context *ctx_isp, + struct cam_isp_hw_done_event_data *done, + uint32_t bubble_state) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_done_event_data done_next_req; + + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "Buf done with no active request"); + return 0; + } + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + + rc = __cam_isp_ctx_handle_buf_done_for_request(ctx_isp, req, done, + bubble_state, &done_next_req); + + if (done_next_req.num_handles) { + struct cam_isp_hw_done_event_data unhandled_res; + struct cam_ctx_request *next_req = list_next_entry(req, list); + + if (next_req) { + /* + * Few resource handles are already signalled in the + * current request, lets check if there is another + * request waiting for these resources. This can + * happen if handling some of next request's buf done + * events are happening first before handling current + * request's remaining buf dones due to IRQ scheduling. + * Lets check only one more request as we will have + * maximum of 2 requests in active_list at any time. + */ + + CAM_WARN(CAM_ISP, + "Unhandled buf done resources for req %lld, trying next request %lld in active_list", + req->request_id, next_req->request_id); + + __cam_isp_ctx_handle_buf_done_for_request(ctx_isp, + next_req, &done_next_req, + bubble_state, &unhandled_res); + + if (unhandled_res.num_handles == 0) + CAM_INFO(CAM_ISP, + "BUF Done event handed for next request %lld", + next_req->request_id); + else + CAM_ERR(CAM_ISP, + "BUF Done not handled for next request %lld", + next_req->request_id); + } + } + return rc; } @@ -625,7 +695,7 @@ static int __cam_isp_ctx_reg_upd_in_epoch_state( return 0; } -static int __cam_isp_ctx_reg_upd_in_activated_state( +static int __cam_isp_ctx_reg_upd_in_applied_state( struct cam_isp_context *ctx_isp, void *evt_data) { int rc = 0; @@ -888,10 +958,11 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + CAM_WARN(CAM_ISP, + "Notify CRM about Bubble req %lld frame %lld, ctx %u", + req->request_id, ctx_isp->frame_id, ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); atomic_set(&ctx_isp->process_bubble, 1); - CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld, ctx %u", - ctx_isp->frame_id, ctx->ctx_id); } else { req_isp->bubble_report = 0; } @@ -1038,11 +1109,11 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; - ctx->ctx_crm_intf->notify_err(¬ify); - atomic_set(&ctx_isp->process_bubble, 1); - CAM_DBG(CAM_REQ, + CAM_WARN(CAM_REQ, "Notify CRM about Bubble req_id %llu frame %lld, ctx %u", req->request_id, ctx_isp->frame_id, ctx->ctx_id); + ctx->ctx_crm_intf->notify_err(¬ify); + atomic_set(&ctx_isp->process_bubble, 1); } else { req_isp->bubble_report = 0; } @@ -1105,7 +1176,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, struct cam_ctx_request *req_temp; struct cam_isp_ctx_req *req_isp = NULL; struct cam_isp_ctx_req *req_isp_to_report = NULL; - struct cam_req_mgr_error_notify notify; + struct cam_req_mgr_error_notify notify = {}; uint64_t error_request_id; struct cam_hw_fence_map_entry *fence_map_out = NULL; struct cam_req_mgr_message req_msg; @@ -1295,8 +1366,10 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, notify.error = CRM_KMD_ERR_FATAL; } - CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld ctx %u", - error_request_id, ctx_isp->frame_id, ctx->ctx_id); + CAM_WARN(CAM_ISP, + "Notify CRM: req %lld, frame %lld ctx %u, error %d", + error_request_id, ctx_isp->frame_id, ctx->ctx_id, + notify.error); ctx->ctx_crm_intf->notify_err(¬ify); @@ -1582,7 +1655,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_activated_state, - __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_reg_upd_in_applied_state, __cam_isp_ctx_epoch_in_applied, __cam_isp_ctx_notify_eof_in_activated_state, __cam_isp_ctx_buf_done_in_applied, @@ -1615,7 +1688,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_activated_state, - __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_reg_upd_in_applied_state, __cam_isp_ctx_epoch_in_bubble_applied, NULL, __cam_isp_ctx_buf_done_in_bubble_applied, @@ -1688,7 +1761,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_activated_state, - __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_reg_upd_in_applied_state, __cam_isp_ctx_epoch_in_bubble_applied, NULL, __cam_isp_ctx_buf_done_in_bubble_applied, @@ -1738,7 +1811,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state( ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; if (atomic_read(&ctx_isp->process_bubble)) { - CAM_DBG(CAM_ISP, + CAM_INFO(CAM_ISP, "Processing bubble cannot apply Request Id %llu", apply->request_id); rc = -EAGAIN; @@ -1767,7 +1840,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state( req_isp = (struct cam_isp_ctx_req *) req->req_priv; if (ctx_isp->active_req_cnt >= 2) { - CAM_ERR(CAM_ISP, + CAM_WARN(CAM_ISP, "Reject apply request (id %lld) due to congestion(cnt = %d) ctx %u", req->request_id, ctx_isp->active_req_cnt, @@ -1836,6 +1909,10 @@ static int __cam_isp_ctx_apply_req_in_sof( CAM_ISP_CTX_ACTIVATED_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + if (rc) + CAM_DBG(CAM_ISP, "Apply failed in state %d, rc %d", + ctx_isp->substate_activated, rc); + return rc; } @@ -1852,6 +1929,10 @@ static int __cam_isp_ctx_apply_req_in_epoch( CAM_ISP_CTX_ACTIVATED_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + if (rc) + CAM_DBG(CAM_ISP, "Apply failed in state %d, rc %d", + ctx_isp->substate_activated, rc); + return rc; } @@ -1868,6 +1949,10 @@ static int __cam_isp_ctx_apply_req_in_bubble( CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + if (rc) + CAM_DBG(CAM_ISP, "Apply failed in state %d, rc %d", + ctx_isp->substate_activated, rc); + return rc; } @@ -2244,9 +2329,12 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + CAM_WARN(CAM_ISP, + "Notify CRM about Bubble req %lld frame %lld ctx %u", + req->request_id, + ctx_isp->frame_id, + ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); - CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld", - ctx_isp->frame_id); } else { req_isp->bubble_report = 0; } @@ -2507,6 +2595,10 @@ static int __cam_isp_ctx_rdi_only_apply_req_top_state( CAM_ISP_CTX_ACTIVATED_APPLIED); CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + if (rc) + CAM_ERR(CAM_ISP, "Apply failed in state %d, rc %d", + ctx_isp->substate_activated, rc); + return rc; } @@ -3740,8 +3832,8 @@ static int __cam_isp_ctx_apply_req(struct cam_context *ctx, if (rc) CAM_ERR_RATE_LIMIT(CAM_ISP, - "Apply failed in active substate %d", - ctx_isp->substate_activated); + "Apply failed in active substate %d rc %d", + ctx_isp->substate_activated, rc); return rc; } -- GitLab From c4acb6a0256aa4a6b04725854c51ad2f054941e6 Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Tue, 13 Aug 2019 04:49:19 +0530 Subject: [PATCH 059/410] msm: camera: isp: schedule tasklet with priority To handle tasklet delays in hadling ISP inetrrupts use priority tasklet scheduling. Change-Id: I11961f51092c3f6876d2375595d9e5004f64c656 Signed-off-by: Suresh Vankadara Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index 5145dadded28..a8ff7ff01e11 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -210,7 +210,7 @@ void cam_tasklet_enqueue_cmd( list_add_tail(&tasklet_cmd->list, &tasklet->used_cmd_list); spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); - tasklet_schedule(&tasklet->tasklet); + tasklet_hi_schedule(&tasklet->tasklet); } int cam_tasklet_init( -- GitLab From 9712baaea9096f4e45be8aeb691e9a651354d6aa Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 24 Jul 2019 10:12:08 -0700 Subject: [PATCH 060/410] msm: camera: reqmgr: Update log for shutdown Add warn log to indicate shutdown has occurred. Also decrement the open req count after successfully applying a request. Change-Id: I1b420dff52e016f52e19c5572824e4ed6f53744b Signed-off-by: Karthik Anantha Ram Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_req_mgr/cam_req_mgr_core.c | 4 +--- drivers/cam_req_mgr/cam_req_mgr_dev.c | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 3147eeab0a7b..287db0c46d2f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -625,9 +625,6 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, *failed_dev = dev; break; } - - if (pd == link->max_delay) - link->open_req_cnt--; } trace_cam_req_mgr_apply_request(link, &apply_req, dev); } @@ -1260,6 +1257,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, &idx, reset_step + 1, in_q->num_slots); __cam_req_mgr_reset_req_slot(link, idx); + link->open_req_cnt--; } } diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 718942552bc7..a30dc69a80d0 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -151,6 +151,8 @@ static int cam_req_mgr_close(struct file *filep) struct v4l2_fh *vfh = filep->private_data; struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); + CAM_WARN(CAM_CRM, + "release invoked associated userspace process has died"); mutex_lock(&g_dev.cam_lock); if (g_dev.open_cnt <= 0) { -- GitLab From 6ceb84f1b7356d926aaffe309a6de51154b750ae Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 22 Jul 2019 10:36:56 -0700 Subject: [PATCH 061/410] msm: camera: icp: log cleanup and header update This change cleans up a few logs and updates the HFI headers in line with the current FW. CRs-Fixed: 2513094 Change-Id: I8853ac3711ad3bf36ce59f6860082fa29dca0bf6 Signed-off-by: Karthik Anantha Ram --- drivers/cam_icp/fw_inc/hfi_session_defs.h | 20 ++++++++++++++--- drivers/cam_icp/fw_inc/hfi_sys_defs.h | 15 +++++++++++++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 22 +++++++++++++------ 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/drivers/cam_icp/fw_inc/hfi_session_defs.h b/drivers/cam_icp/fw_inc/hfi_session_defs.h index e50b5d147a2f..9ba7803d4f44 100644 --- a/drivers/cam_icp/fw_inc/hfi_session_defs.h +++ b/drivers/cam_icp/fw_inc/hfi_session_defs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_HFI_SESSION_DEFS_H @@ -272,10 +272,20 @@ enum hfi_ipe_io_images { IPE_OUTPUT_IMAGE_DS4_REF, IPE_OUTPUT_IMAGE_DS16_REF, IPE_OUTPUT_IMAGE_DS64_REF, + IPE_INPUT2_IMAGE_FULL, + IPE_INPUT2_IMAGE_DSX, + IPE_INPUT_OUTPUT_SCRATCHBUFFER, IPE_INPUT_IMAGE_FIRST = IPE_INPUT_IMAGE_FULL, IPE_INPUT_IMAGE_LAST = IPE_INPUT_IMAGE_DS64_REF, + IPE_INPUT_IMAGE_REF_FIRST = IPE_INPUT_IMAGE_FULL_REF, + IPE_INPUT_IMAGE_REF_LAST = IPE_INPUT_IMAGE_DS64_REF, IPE_OUTPUT_IMAGE_FIRST = IPE_OUTPUT_IMAGE_DISPLAY, IPE_OUTPUT_IMAGE_LAST = IPE_OUTPUT_IMAGE_DS64_REF, + IPE_OUTPUT_IMAGE_REF_FIRST = IPE_OUTPUT_IMAGE_FULL_REF, + IPE_OUTPUT_IMAGE_REF_LAST = IPE_OUTPUT_IMAGE_DS64_REF, + IPE_INPUT2_IMAGE_FIRST = IPE_INPUT2_IMAGE_FULL, + IPE_INPUT2_IMAGE_LAST = IPE_INPUT2_IMAGE_DSX, + IPE_INPUT_OUTPUT_IMAGE_LAST = IPE_INPUT_OUTPUT_SCRATCHBUFFER, IPE_IO_IMAGES_MAX }; @@ -300,7 +310,6 @@ struct frame_buffer { } __packed; struct bps_frame_process_data { - struct frame_buffer buffers[BPS_IO_IMAGES_MAX]; uint32_t max_num_cores; uint32_t target_time; uint32_t ubwc_stats_buffer_addr; @@ -311,6 +320,7 @@ struct bps_frame_process_data { uint32_t strip_lib_out_addr; uint32_t cdm_prog_addr; uint32_t request_id; + struct frame_buffer buffers[BPS_IO_IMAGES_MAX]; }; enum hfi_ipe_image_format { @@ -465,7 +475,6 @@ struct ica_stab_params { struct frame_set { struct frame_buffer buffers[IPE_IO_IMAGES_MAX]; - struct ica_stab_params ica_params; uint32_t cdm_ica1_addr; uint32_t cdm_ica2_addr; } __packed; @@ -492,6 +501,11 @@ struct ipe_frame_process_data { uint32_t cdm_tf_ds4; uint32_t cdm_tf_ds16; uint32_t cdm_tf_ds64; + uint32_t cdm_dsx_dc4; + uint32_t cdm_dsx_dc16; + uint32_t cdm_dsz_dc64; + uint32_t cdm_mfhdr_full_pass; + uint32_t cdm_mfhdr_dcx; uint32_t request_id; uint32_t frames_in_batch; struct frame_set framesets[MAX_HFR_GROUP]; diff --git a/drivers/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/cam_icp/fw_inc/hfi_sys_defs.h index ddd9bf15c6aa..905b85a53633 100644 --- a/drivers/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/cam_icp/fw_inc/hfi_sys_defs.h @@ -67,6 +67,21 @@ #define HFI_CMD_SYS_PING (HFI_CMD_COMMON_START + 0x5) #define HFI_CMD_SYS_RESET (HFI_CMD_COMMON_START + 0x6) +/* General Frame process errors */ +#define CAMERAICP_SUCCESS 0 +#define CAMERAICP_EFAILED 1 +#define CAMERAICP_ENOMEMORY 2 +#define CAMERAICP_EBADSTATE 3 +#define CAMERAICP_EBADPARM 4 +#define CAMERAICP_EBADITEM 5 +#define CAMERAICP_EINVALIDFORMAT 6 +#define CAMERAICP_EUNSUPPORTED 7 +#define CAMERAICP_EOUTOFBOUND 8 +#define CAMERAICP_ETIMEDOUT 9 +#define CAMERAICP_EABORTED 10 +#define CAMERAICP_EHWVIOLATION 11 +#define CAMERAICP_ECDMERROR 12 + /* Core level commands */ /* IPE/BPS core Commands */ #define HFI_CMD_IPE_BPS_COMMON_START \ 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 4da5c65412dc..c1ec110ea1d5 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 @@ -1943,10 +1943,20 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) } idx = i; - if (flag == ICP_FRAME_PROCESS_FAILURE) - CAM_ERR(CAM_ICP, "Done with error: ctx_id %d req %llu dev %d", - ctx_data->ctx_id, request_id, - ctx_data->icp_dev_acquire_info->dev_type); + if (flag == ICP_FRAME_PROCESS_FAILURE) { + if (ioconfig_ack->err_type == CAMERAICP_EABORTED) + CAM_WARN(CAM_ICP, + "ctx_id %d req %llu dev %d has been aborted[flushed]", + ctx_data->ctx_id, request_id, + ctx_data->icp_dev_acquire_info->dev_type); + else + CAM_ERR(CAM_ICP, + "Done with error: %u on ctx_id %d dev %d for req %llu", + ioconfig_ack->err_type, + ctx_data->ctx_id, + ctx_data->icp_dev_acquire_info->dev_type, + request_id); + } buf_data.request_id = hfi_frame_process->request_id[idx]; ctx_data->ctxt_event_cb(ctx_data->context_priv, flag, &buf_data); @@ -1975,9 +1985,7 @@ static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) } ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; - if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) { - CAM_ERR(CAM_ICP, "failed with error : %u", - ioconfig_ack->err_type); + if (ioconfig_ack->err_type != CAMERAICP_SUCCESS) { cam_icp_mgr_handle_frame_process(msg_ptr, ICP_FRAME_PROCESS_FAILURE); return -EIO; -- GitLab From 65a6c306f9259ace0cfbf0bac02e81fcb8f168c1 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 21 Aug 2019 12:17:53 -0700 Subject: [PATCH 062/410] msm: camera: smmu: Dump ctx bank info in case of mapping failure When mapping fails for a given context bank, dump all the existing mappings for that context bank to understand the memory usage for that bank. CRs-Fixed: 2513106 Change-Id: Ia17b086dd76378da55cae509255309610820f53f Signed-off-by: Karthik Anantha Ram --- drivers/cam_smmu/cam_smmu_api.c | 90 ++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 478a00657f3b..55962a8f3e7a 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -130,6 +131,9 @@ struct cam_context_bank_info { int cb_count; int secure_count; int pf_count; + + size_t io_mapping_size; + size_t shared_mapping_size; }; struct cam_iommu_cb_set { @@ -140,6 +144,8 @@ struct cam_iommu_cb_set { struct mutex payload_list_lock; struct list_head payload_list; u32 non_fatal_fault; + struct dentry *dentry; + bool cb_dump_enable; }; static const struct of_device_id msm_cam_smmu_dt_match[] = { @@ -237,6 +243,8 @@ static void cam_smmu_clean_user_buffer_list(int idx); static void cam_smmu_clean_kernel_buffer_list(int idx); +static void cam_smmu_dump_cb_info(int idx); + static void cam_smmu_print_user_list(int idx); static void cam_smmu_print_kernel_list(int idx); @@ -287,6 +295,50 @@ static void cam_smmu_page_fault_work(struct work_struct *work) kfree(payload); } +static void cam_smmu_dump_cb_info(int idx) +{ + struct cam_dma_buff_info *mapping, *mapping_temp; + size_t shared_reg_len = 0, io_reg_len = 0; + size_t shared_free_len = 0, io_free_len = 0; + uint32_t i = 0; + struct cam_context_bank_info *cb_info = + &iommu_cb_set.cb_info[idx]; + + if (cb_info->shared_support) { + shared_reg_len = cb_info->shared_info.iova_len; + shared_free_len = shared_reg_len - cb_info->shared_mapping_size; + } + + if (cb_info->io_support) { + io_reg_len = cb_info->io_info.iova_len; + io_free_len = io_reg_len - cb_info->io_mapping_size; + } + + CAM_ERR(CAM_SMMU, + "********** Context bank dump for %s **********", + cb_info->name); + CAM_ERR(CAM_SMMU, + "Usage: shared_usage=%u io_usage=%u shared_free=%u io_free=%u", + (unsigned int)cb_info->shared_mapping_size, + (unsigned int)cb_info->io_mapping_size, + (unsigned int)shared_free_len, + (unsigned int)io_free_len); + + if (iommu_cb_set.cb_dump_enable) { + list_for_each_entry_safe(mapping, mapping_temp, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + i++; + CAM_ERR(CAM_SMMU, + "%u. ion_fd=%d start=0x%x end=0x%x len=%u region=%d", + i, mapping->ion_fd, (void *)mapping->paddr, + ((uint64_t)mapping->paddr + + (uint64_t)mapping->len), + (unsigned int)mapping->len, + mapping->region_id); + } + } +} + static void cam_smmu_print_user_list(int idx) { struct cam_dma_buff_info *mapping; @@ -1712,6 +1764,7 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, *paddr_ptr = iova; *len_ptr = size; } + iommu_cb_set.cb_info[idx].shared_mapping_size += *len_ptr; } else if (region_id == CAM_SMMU_REGION_IO) { attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; @@ -1724,6 +1777,7 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, *paddr_ptr = sg_dma_address(table->sgl); *len_ptr = (size_t)buf->size; + iommu_cb_set.cb_info[idx].io_mapping_size += *len_ptr; } else { CAM_ERR(CAM_SMMU, "Error: Wrong region id passed"); rc = -EINVAL; @@ -1896,8 +1950,11 @@ static int cam_smmu_unmap_buf_and_remove_from_list( if (rc) CAM_ERR(CAM_SMMU, "IOVA free failed"); + iommu_cb_set.cb_info[idx].shared_mapping_size -= + mapping_info->len; } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) { mapping_info->attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + iommu_cb_set.cb_info[idx].io_mapping_size -= mapping_info->len; } dma_buf_unmap_attachment(mapping_info->attach, @@ -2702,10 +2759,12 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir, paddr_ptr, len_ptr, region_id); - if (rc < 0) + if (rc < 0) { CAM_ERR(CAM_SMMU, "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d", idx, ion_fd, region_id, rc); + cam_smmu_dump_cb_info(idx); + } get_addr_end: mutex_unlock(&iommu_cb_set.cb_info[idx].lock); @@ -3498,6 +3557,31 @@ static int cam_populate_smmu_context_banks(struct device *dev, return rc; } +static int cam_smmu_create_debug_fs(void) +{ + iommu_cb_set.dentry = debugfs_create_dir("camera_smmu", + NULL); + + if (!iommu_cb_set.dentry) { + CAM_ERR(CAM_SMMU, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("cb_dump_enable", + 0644, + iommu_cb_set.dentry, + &iommu_cb_set.cb_dump_enable)) { + CAM_ERR(CAM_SMMU, + "failed to create dump_enable_debug"); + goto err; + } + + return 0; +err: + debugfs_remove_recursive(iommu_cb_set.dentry); + return -ENOMEM; +} + static int cam_smmu_probe(struct platform_device *pdev) { int rc = 0; @@ -3547,6 +3631,7 @@ static int cam_smmu_probe(struct platform_device *pdev) INIT_LIST_HEAD(&iommu_cb_set.payload_list); } + cam_smmu_create_debug_fs(); return rc; } @@ -3563,6 +3648,9 @@ static int cam_smmu_remove(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu")) cam_smmu_release_cb(pdev); + + debugfs_remove_recursive(iommu_cb_set.dentry); + iommu_cb_set.dentry = NULL; return 0; } -- GitLab From b582eeddce1df6916d68c903521a7b9807287058 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Thu, 15 Aug 2019 15:39:05 -0700 Subject: [PATCH 063/410] msm: camera: isp: Add atomic flag instead of wait in handle error Errors in isp are handled in soft irq context, putting a wait for cdm done is not allowed. Add atomic flag for checking status of cdm and check it before reg dump to determine the request for which register values can be dumped in command buffer.This is only applicable to reg dump on error. CRs-Fixed: 2510557 Change-Id: If4bfedd1a62078392721c2ea0958da82087f5b26 Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 25 ++++++++++++--------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 3 +++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 96a12a707dd3..8614292c54a7 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2078,6 +2078,7 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { complete_all(&ctx->config_done_complete); + atomic_set(&ctx->cdm_done, 1); CAM_DBG(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", handle, userdata, status, cookie, ctx->ctx_index); @@ -3063,6 +3064,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, ctx->applied_req_id = cfg->request_id; CAM_DBG(CAM_ISP, "Submit to CDM"); + atomic_set(&ctx->cdm_done, 0); rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); if (rc) { CAM_ERR(CAM_ISP, "Failed to apply the configs"); @@ -5371,15 +5373,9 @@ static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, return 0; } - rc = wait_for_completion_timeout( - &ctx->config_done_complete, - msecs_to_jiffies(30)); - if (rc <= 0) { - CAM_ERR(CAM_ISP, - "config done completion timeout rc=%d ctx_index %d", - rc, ctx->ctx_index); - rc = 0; - } + if (!atomic_read(&ctx->cdm_done)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "Reg dump values might be from more than one request"); for (i = 0; i < ctx->num_reg_dump_buf; i++) { CAM_DBG(CAM_ISP, "Reg dump cmd meta data: %d req_type: %d", @@ -5468,8 +5464,17 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) if (ctx->last_dump_flush_req_id == ctx->applied_req_id) return 0; - ctx->last_dump_flush_req_id = ctx->applied_req_id; + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(30)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, + "config done completion timeout, Reg dump will be unreliable rc=%d ctx_index %d", + rc, ctx->ctx_index); + rc = 0; + } + ctx->last_dump_flush_req_id = ctx->applied_req_id; rc = cam_ife_mgr_handle_reg_dump(ctx, CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH); if (rc) { diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 698b0c60ca9b..09ba8bd9c43e 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -122,6 +122,8 @@ struct cam_ife_hw_mgr_debug { * @eof_cnt eof count value per core, used for dual VFE * @overflow_pending flat to specify the overflow is pending for the * context + * @cdm_done flag to indicate cdm has finished writing shadow + * registers * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete * @reg_dump_buf_desc: cmd buffer descriptors for reg dump @@ -164,6 +166,7 @@ struct cam_ife_hw_mgr_ctx { uint32_t epoch_cnt[CAM_IFE_HW_NUM_MAX]; uint32_t eof_cnt[CAM_IFE_HW_NUM_MAX]; atomic_t overflow_pending; + atomic_t cdm_done; uint32_t is_rdi_only_context; struct completion config_done_complete; struct cam_cmd_buf_desc reg_dump_buf_desc[ -- GitLab From 7c65c0fa21c681db863595662cdabde72b52a86a Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 18 Jul 2019 11:29:37 -0700 Subject: [PATCH 064/410] msm: camera: common: Clean shutdown and page fault sequence Avoid unnecessary logging during shutdown and pagefault in camera drivers. CRs-Fixed: 2500721 Change-Id: I2519d45da134306f906186dc25705fc1f84b1972 Signed-off-by: Karthik Anantha Ram --- drivers/cam_core/cam_context.c | 30 +++++++++++-------- drivers/cam_req_mgr/cam_req_mgr_core.c | 17 +++++++---- drivers/cam_req_mgr/cam_req_mgr_core.h | 7 ++++- drivers/cam_req_mgr/cam_req_mgr_dev.c | 2 +- drivers/cam_req_mgr/cam_req_mgr_util.c | 4 +-- .../cam_sensor/cam_sensor_core.c | 10 +++++-- 6 files changed, 45 insertions(+), 25 deletions(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index d2ec399e2895..4d4d4fc5c068 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -54,12 +54,15 @@ int cam_context_shutdown(struct cam_context *ctx) rc = -EINVAL; } - rc = cam_destroy_device_hdl(ctx->dev_hdl); - if (rc) - CAM_ERR(CAM_CORE, "destroy device hdl failed for node %s", - ctx->dev_name); - else - ctx->dev_hdl = -1; + if (ctx->dev_hdl != -1) { + rc = cam_destroy_device_hdl(ctx->dev_hdl); + if (rc) + CAM_ERR(CAM_CORE, + "destroy device hdl failed for node %s", + ctx->dev_name); + else + ctx->dev_hdl = -1; + } return rc; } @@ -237,12 +240,15 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, return -EINVAL; } - if (ctx->state_machine[ctx->state].pagefault_ops) { - rc = ctx->state_machine[ctx->state].pagefault_ops(ctx, iova, - buf_info); - } else { - CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d", - ctx->dev_hdl, ctx->state); + if ((ctx->state > CAM_CTX_AVAILABLE) && + (ctx->state < CAM_CTX_STATE_MAX)) { + if (ctx->state_machine[ctx->state].pagefault_ops) { + rc = ctx->state_machine[ctx->state].pagefault_ops( + ctx, iova, buf_info); + } else { + CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d", + ctx->dev_hdl, ctx->state); + } } return rc; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 287db0c46d2f..6a8e5fed6e67 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -42,6 +42,7 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) link->initial_sync_req = -1; link->in_msync_mode = false; link->retry_cnt = 0; + link->is_shutdown = false; } void cam_req_mgr_handle_core_shutdown(void) @@ -55,7 +56,7 @@ void cam_req_mgr_handle_core_shutdown(void) &g_crm_core_dev->session_head, entry) { ses_info.session_hdl = session->session_hdl; - cam_req_mgr_destroy_session(&ses_info); + cam_req_mgr_destroy_session(&ses_info, true); } } } @@ -2707,10 +2708,12 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) link->state = CAM_CRM_LINK_STATE_IDLE; spin_unlock_bh(&link->link_state_spin_lock); - rc = __cam_req_mgr_disconnect_link(link); - if (rc) - CAM_ERR(CAM_CORE, - "Unlink for all devices was not successful"); + if (!link->is_shutdown) { + rc = __cam_req_mgr_disconnect_link(link); + if (rc) + CAM_ERR(CAM_CORE, + "Unlink for all devices was not successful"); + } mutex_lock(&link->lock); /* Destroy timer of link */ @@ -2738,7 +2741,8 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) } int cam_req_mgr_destroy_session( - struct cam_req_mgr_session_info *ses_info) + struct cam_req_mgr_session_info *ses_info, + bool is_shutdown) { int rc; int i; @@ -2771,6 +2775,7 @@ int cam_req_mgr_destroy_session( continue; /* Ignore return value since session is going away */ + link->is_shutdown = is_shutdown; __cam_req_mgr_unlink(link); __cam_req_mgr_free_link(link); } diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index aeede7a87166..3837c1cd8061 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -332,6 +332,8 @@ struct cam_req_mgr_connected_device { * other link * @retry_cnt : Counter that tracks number of attempts to apply * the same req + * @is_shutdown : Flag to indicate if link needs to be disconnected + * as part of shutdown. */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -359,6 +361,7 @@ struct cam_req_mgr_core_link { bool in_msync_mode; int64_t initial_sync_req; uint32_t retry_cnt; + bool is_shutdown; }; /** @@ -411,11 +414,13 @@ int cam_req_mgr_create_session(struct cam_req_mgr_session_info *ses_info); * cam_req_mgr_destroy_session() * @brief : destroy session * @ses_info : session handle info, input param + * @is_shutdown: To indicate if devices on link need to be disconnected. * * Called as part of session destroy * return success/failure */ -int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info); +int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info, + bool is_shutdown); /** * cam_req_mgr_link() diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index a30dc69a80d0..d567dec91519 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -258,7 +258,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EFAULT; } - rc = cam_req_mgr_destroy_session(&ses_info); + rc = cam_req_mgr_destroy_session(&ses_info, false); } break; diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index f833f667de97..ce83e64363f5 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "CAM-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__ @@ -94,7 +94,7 @@ int cam_req_mgr_util_free_hdls(void) for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++) { if (hdl_tbl->hdl[i].state == HDL_ACTIVE) { - CAM_ERR(CAM_CRM, "Dev handle = %x session_handle = %x", + CAM_WARN(CAM_CRM, "Dev handle = %x session_handle = %x", hdl_tbl->hdl[i].hdl_value, hdl_tbl->hdl[i].session_hdl); hdl_tbl->hdl[i].state = HDL_FREE; diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 680cf4f302bc..2fa447dbace4 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -565,9 +565,13 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) if (s_ctrl->sensor_state != CAM_SENSOR_INIT) cam_sensor_power_down(s_ctrl); - rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); - if (rc < 0) - CAM_ERR(CAM_SENSOR, "dhdl already destroyed: rc = %d", rc); + if (s_ctrl->bridge_intf.device_hdl != -1) { + rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "dhdl already destroyed: rc = %d", rc); + } + s_ctrl->bridge_intf.device_hdl = -1; s_ctrl->bridge_intf.link_hdl = -1; s_ctrl->bridge_intf.session_hdl = -1; -- GitLab From 03e52e70d6d24311f960bd9830eb24634b402214 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 2 Aug 2019 11:06:22 -0700 Subject: [PATCH 065/410] msm: camera: isp: Dump previous acq ctx info on acq failure In case acquire hw fails, dump the previously acquired streams to infer the reason for the failure. CRs-Fixed: 2512474 Change-Id: I3ee2b85e0843ab4a605625950dc60366c0b50713 Signed-off-by: Karthik Anantha Ram --- drivers/cam_core/cam_context.c | 25 +++ drivers/cam_core/cam_context.h | 16 ++ drivers/cam_core/cam_context_utils.c | 29 +++ drivers/cam_core/cam_context_utils.h | 3 +- drivers/cam_core/cam_hw_mgr_intf.h | 16 ++ drivers/cam_core/cam_node.c | 16 +- drivers/cam_isp/cam_isp_context.c | 22 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 226 +++++++++++++++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 3 + 9 files changed, 345 insertions(+), 11 deletions(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index d2ec399e2895..5e42f02dd9ad 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -493,6 +493,31 @@ int cam_context_handle_stop_dev(struct cam_context *ctx, return rc; } +int cam_context_handle_info_dump(void *context, + enum cam_context_dump_id id) +{ + int rc = 0; + struct cam_context *ctx = (struct cam_context *)context; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].dumpinfo_ops) + rc = ctx->state_machine[ctx->state].dumpinfo_ops(ctx, + id); + mutex_unlock(&ctx->ctx_mutex); + + if (rc) + CAM_WARN(CAM_CORE, + "Dump for id %u failed on ctx_id %u name %s state %d", + id, ctx->ctx_id, ctx->dev_name, ctx->state); + + return rc; +} + int cam_context_init(struct cam_context *ctx, const char *dev_name, uint64_t dev_id, diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 1583dd06df3f..854ea0067a27 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -138,6 +138,8 @@ struct cam_ctx_crm_ops { * @crm_ops: CRM to context interface function table * @irq_ops: Hardware event handle function * @pagefault_ops: Function to be called on page fault + * @dumpinfo_ops: Function to be invoked for dumping any + * context info * */ struct cam_ctx_ops { @@ -145,6 +147,7 @@ struct cam_ctx_ops { struct cam_ctx_crm_ops crm_ops; cam_hw_event_cb_func irq_ops; cam_hw_pagefault_cb_func pagefault_ops; + cam_ctx_info_dump_cb_func dumpinfo_ops; }; /** @@ -406,6 +409,19 @@ int cam_context_handle_start_dev(struct cam_context *ctx, int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); +/** + * cam_context_handle_info_dump() + * + * @brief: Handle any dump info for the context + * + * @ctx: Object pointer for cam_context + * @id: To indicate which info pertaining + * to that ctx needs to be dumped + * + */ +int cam_context_handle_info_dump(void *context, + enum cam_context_dump_id id); + /** * cam_context_deinit() * diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 34dc7b81d454..5ec9c6cdc7b1 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -1016,3 +1016,32 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, end: return rc; } + +int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args cmd_args; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input params"); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if (ctx->hw_mgr_intf->hw_cmd) { + cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cmd_args.cmd_type = CAM_HW_MGR_CMD_DUMP_ACQ_INFO; + ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &cmd_args); + } + +end: + return rc; +} diff --git a/drivers/cam_core/cam_context_utils.h b/drivers/cam_core/cam_context_utils.h index c3483327ba81..087fdbf36544 100644 --- a/drivers/cam_core/cam_context_utils.h +++ b/drivers/cam_core/cam_context_utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CONTEXT_UTILS_H_ @@ -29,5 +29,6 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, struct cam_packet *packet, unsigned long iova, uint32_t buf_info, bool *mem_found); +int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx); #endif /* _CAM_CONTEXT_UTILS_H_ */ diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index b7b6ae1bb6b7..462b30119b50 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -24,6 +24,17 @@ /* Maximum reg dump cmd buffer entries in a context */ #define CAM_REG_DUMP_MAX_BUF_ENTRIES 10 +/** + * enum cam_context_dump_id - + * context dump type + * + */ +enum cam_context_dump_id { + CAM_CTX_DUMP_TYPE_NONE, + CAM_CTX_DUMP_ACQ_INFO, + CAM_CTX_DUMP_TYPE_MAX, +}; + /* hardware event callback function type */ typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, void *evt_data); @@ -32,6 +43,10 @@ typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, typedef int (*cam_hw_pagefault_cb_func)(void *context, unsigned long iova, uint32_t buf_info); +/* ctx dump callback function type */ +typedef int (*cam_ctx_info_dump_cb_func)(void *context, + enum cam_context_dump_id dump_id); + /** * struct cam_hw_update_entry - Entry for hardware config * @@ -276,6 +291,7 @@ enum cam_hw_mgr_command { CAM_HW_MGR_CMD_DUMP_PF_INFO, CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH, CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR, + CAM_HW_MGR_CMD_DUMP_ACQ_INFO, }; /** diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 9c4c6f242336..4fefa2f35db3 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -122,6 +122,16 @@ static int __cam_node_handle_acquire_dev(struct cam_node *node, return rc; } +static void __cam_node_handle_acquired_hw_dump( + struct cam_node *node) +{ + int i; + + for (i = 0; i < node->ctx_size; i++) + cam_context_handle_info_dump(&(node->ctx_list[i]), + CAM_CTX_DUMP_ACQ_INFO); +} + static int __cam_node_handle_acquire_hw_v1(struct cam_node *node, struct cam_acquire_hw_cmd_v1 *acquire) { @@ -158,6 +168,7 @@ static int __cam_node_handle_acquire_hw_v1(struct cam_node *node, if (rc) { CAM_ERR(CAM_CORE, "Acquire device failed for node %s", node->name); + __cam_node_handle_acquired_hw_dump(node); return rc; } @@ -197,6 +208,7 @@ static int __cam_node_handle_acquire_hw_v2(struct cam_node *node, if (rc) { CAM_ERR(CAM_CORE, "Acquire device failed for node %s", node->name); + __cam_node_handle_acquired_hw_dump(node); return rc; } @@ -734,7 +746,6 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) "acquire device failed(rc = %d)", rc); goto acquire_kfree; } - CAM_INFO(CAM_CORE, "Acquire HW successful"); } else if (api_version == 2) { rc = __cam_node_handle_acquire_hw_v2(node, acquire_ptr); if (rc) { @@ -742,7 +753,6 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) "acquire device failed(rc = %d)", rc); goto acquire_kfree; } - CAM_INFO(CAM_CORE, "Acquire HW successful"); } if (copy_to_user((void __user *)cmd->handle, acquire_ptr, @@ -849,8 +859,6 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) "release device failed(rc = %d)", rc); } - CAM_INFO(CAM_CORE, "Release HW done(rc = %d)", rc); - release_kfree: kfree(release_ptr); break; diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index c51b8e4a2e5e..46dfeb1915ca 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -139,6 +139,24 @@ static void __cam_isp_ctx_dump_state_monitor_array( } } +static int cam_isp_context_info_dump(void *context, + enum cam_context_dump_id id) +{ + struct cam_context *ctx = (struct cam_context *)context; + + switch (id) { + case CAM_CTX_DUMP_ACQ_INFO: { + cam_context_dump_hw_acq_info(ctx); + break; + } + default: + CAM_DBG(CAM_ISP, "DUMP id not valid %u", id); + break; + } + + return 0; +} + static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) { int i = 0, rc = 0; @@ -3365,7 +3383,6 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, return rc; } - static int __cam_isp_ctx_acquire_hw_in_acquired(struct cam_context *ctx, void *args) { @@ -3904,6 +3921,7 @@ static struct cam_ctx_ops }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, }, /* Ready */ { @@ -3919,6 +3937,7 @@ static struct cam_ctx_ops }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, }, /* Activated */ { @@ -3936,6 +3955,7 @@ static struct cam_ctx_ops }, .irq_ops = __cam_isp_ctx_handle_irq_in_activated, .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, }, }; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 96a12a707dd3..b076583cada2 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -471,6 +471,206 @@ static int cam_ife_hw_mgr_free_hw_res( return 0; } +static const char *cam_ife_hw_mgr_get_res_state( + uint32_t res_state) +{ + switch (res_state) { + case CAM_ISP_RESOURCE_STATE_UNAVAILABLE: + return "UNAVAILABLE"; + case CAM_ISP_RESOURCE_STATE_AVAILABLE: + return "AVAILABLE"; + case CAM_ISP_RESOURCE_STATE_RESERVED: + return "RESERVED"; + case CAM_ISP_RESOURCE_STATE_INIT_HW: + return "HW INIT DONE"; + case CAM_ISP_RESOURCE_STATE_STREAMING: + return "STREAMING"; + default: + return "INVALID STATE"; + } +} + +static const char *cam_ife_hw_mgr_get_csid_res_id( + uint32_t res_id) +{ + switch (res_id) { + case CAM_IFE_PIX_PATH_RES_RDI_0: + return "RDI_0"; + case CAM_IFE_PIX_PATH_RES_RDI_1: + return "RDI_1"; + case CAM_IFE_PIX_PATH_RES_RDI_2: + return "RDI_2"; + case CAM_IFE_PIX_PATH_RES_RDI_3: + return "RDI_3"; + case CAM_IFE_PIX_PATH_RES_IPP: + return "IPP"; + case CAM_IFE_PIX_PATH_RES_PPP: + return "PPP"; + default: + return "INVALID"; + } +} + +static const char *cam_ife_hw_mgr_get_src_res_id( + uint32_t res_id) +{ + switch (res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + return "CAMIF"; + case CAM_ISP_HW_VFE_IN_TESTGEN: + return "TESTGEN"; + case CAM_ISP_HW_VFE_IN_RD: + return "BUS_RD"; + case CAM_ISP_HW_VFE_IN_RDI0: + return "RDI_0"; + case CAM_ISP_HW_VFE_IN_RDI1: + return "RDI_1"; + case CAM_ISP_HW_VFE_IN_RDI2: + return "RDI_2"; + case CAM_ISP_HW_VFE_IN_RDI3: + return "RDI_3"; + case CAM_ISP_HW_VFE_IN_PDLIB: + return "PDLIB"; + case CAM_ISP_HW_VFE_IN_LCR: + return "LCR"; + default: + return "INVALID"; + } +} + +static void cam_ife_hw_mgr_dump_src_acq_info( + struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx, + uint32_t num_pix_port, uint32_t num_rdi_port) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_resource_node *hw_res = NULL; + int i = 0; + + CAM_INFO(CAM_ISP, + "Acquired HW for ctx: %u with pix_port: %u rdi_port: %u", + hwr_mgr_ctx->ctx_index, num_pix_port, num_rdi_port); + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } +} + +static void cam_ife_hw_mgr_dump_acq_data( + struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_resource_node *hw_res = NULL; + struct timespec64 *ts = NULL; + uint64_t ms, tmp; + int i = 0, j = 0; + + ts = &hwr_mgr_ctx->ts; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + + CAM_INFO(CAM_ISP, + "**** %llu:%llu:%llu.%llu ctx_idx: %u rdi_only: %s is_dual: %s acquired ****", + (tmp / 3600) % 24, (tmp / 60) % 60, tmp % 60, ms, + hwr_mgr_ctx->ctx_index, + (hwr_mgr_ctx->is_rdi_only_context ? "true" : "false"), + (hwr_mgr_ctx->is_dual ? "true" : "false")); + + /* Iterate over CID resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_cid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) { + CAM_INFO(CAM_ISP, + "CID split_id: %d res_id: %u hw_idx: %u state: %s", + i, hw_res->res_id, + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + } + + /* Iterate over CSID resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "CSID split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_csid_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE IN resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE RD resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_in_rd, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src_rd split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE OUT resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + hw_mgr_res = &hwr_mgr_ctx->res_list_ife_out[i]; + hw_res = hw_mgr_res->hw_res[j]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE out split_id: %d res_id: 0x%x hw_idx: %u state: %s", + i, hw_res->res_id, + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } +} + static int cam_ife_mgr_csid_stop_hw( struct cam_ife_hw_mgr_ctx *ctx, struct list_head *stop_list, uint32_t base_idx, uint32_t stop_cmd) @@ -2400,8 +2600,11 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) if (rc) { CAM_ERR(CAM_ISP, "can not acquire resource"); + cam_ife_hw_mgr_dump_src_acq_info(ife_ctx, + total_pix_port, total_rdi_port); goto free_mem; } + kfree(in_port->data); kfree(in_port); in_port = NULL; @@ -2426,9 +2629,13 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_args->valid_acquired_hw = acquire_hw_info->num_inputs; - cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + getnstimeofday64(&ife_ctx->ts); + CAM_INFO(CAM_ISP, + "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", + total_pix_port, total_rdi_port, + ife_ctx->is_dual, ife_ctx->ctx_index); - CAM_DBG(CAM_ISP, "Exit...(success)"); + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); return 0; free_mem: @@ -2661,9 +2868,12 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) acquire_args->ctxt_to_hw_map = ife_ctx; ife_ctx->ctx_in_use = 1; - cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + CAM_INFO(CAM_ISP, + "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", + total_pix_port, total_rdi_port, + ife_ctx->is_dual, ife_ctx->ctx_index); - CAM_DBG(CAM_ISP, "Exit...(success)"); + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); return 0; free_res: @@ -3722,8 +3932,11 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->eof_cnt[i] = 0; ctx->epoch_cnt[i] = 0; } - CAM_DBG(CAM_ISP, "Exit...ctx id:%d", + + CAM_INFO(CAM_ISP, "Release HW success ctx id: %u", ctx->ctx_index); + + memset(&ctx->ts, 0, sizeof(struct timespec64)); cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx); return rc; } @@ -5494,6 +5707,9 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) return rc; } + break; + case CAM_HW_MGR_CMD_DUMP_ACQ_INFO: + cam_ife_hw_mgr_dump_acq_data(ctx); break; default: CAM_ERR(CAM_ISP, "Invalid cmd"); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 698b0c60ca9b..40ec7262122a 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -7,6 +7,7 @@ #define _CAM_IFE_HW_MGR_H_ #include +#include #include "cam_isp_hw_mgr.h" #include "cam_vfe_hw_intf.h" #include "cam_ife_csid_hw_intf.h" @@ -132,6 +133,7 @@ struct cam_ife_hw_mgr_debug { * @init_done indicate whether init hw is done * @is_fe_enable indicate whether fetch engine\read path is enabled * @is_dual indicate whether context is in dual VFE mode + * @ts captured timestamp when the ctx is acquired */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -175,6 +177,7 @@ struct cam_ife_hw_mgr_ctx { bool init_done; bool is_fe_enable; bool is_dual; + struct timespec64 ts; }; /** -- GitLab From dd89a305c172e11f16a4d8c86715c0c84c496667 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Fri, 23 Aug 2019 15:53:08 -0700 Subject: [PATCH 066/410] Camera: Snap for drop 08/22/2019 Mainline 146 Change-Id: Ib81b69adb65dbbfc69798e06945e939a1ecf56ef Signed-off-by: Mukund Madhusudan Atre -- GitLab From 0a5b5c49616353d30dd318752d602ec2f2dc3a24 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Fri, 23 Aug 2019 15:58:55 -0700 Subject: [PATCH 067/410] Camera: Snap for drop 08/23/2019 Mainline 147 Change-Id: Ieac77fd6ce6f42d10e55b7154e1fb1056f70b0f8 Signed-off-by: Mukund Madhusudan Atre -- GitLab From f86cd9899de1e67c88330dfa79228b208a3e3a2a Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Mon, 26 Aug 2019 13:39:17 -0700 Subject: [PATCH 068/410] Camera: Snap for drop 08/26/2019 Mainline 148 Change-Id: I386b0e3158e27b975adae77146c6b6fafbf933c9 Signed-off-by: Mukund Madhusudan Atre -- GitLab From 95460b8f2e424a1c62438fa2e8f69a2d25c42d55 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Tue, 20 Aug 2019 13:22:42 +0800 Subject: [PATCH 069/410] msm: camera: isp: Fix RDI only early PCR issue RDI only context also need to get req from wait_req_list afte received RUP event in early PCR case. CRs-Fixed: 2511798 Change-Id: If2e8da36cf83dee1c348dd0d6c6ea916061a376e Signed-off-by: Depeng Shao --- drivers/cam_isp/cam_isp_context.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 46dfeb1915ca..b1ad05f45d2c 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3518,11 +3518,11 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, */ list_del_init(&req->list); - if (req_isp->num_fence_map_out) { + if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) { + list_add_tail(&req->list, &ctx->wait_req_list); + } else { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - } else { - list_add_tail(&req->list, &ctx->wait_req_list); } start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; -- GitLab From 598dfb05afa5de9af8447a823e6a7482957c85c5 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Thu, 29 Aug 2019 11:07:04 +0800 Subject: [PATCH 070/410] msm: camera: isp: Correct the active req cnt assignment order We need to reset the active req cnt before assigning new value. Also move the log behind the active req cnt assignment. CRs-Fixed: 2517421 Change-Id: I38f418f79f5f1adcb8b29bc870f904cd1f925bfc Signed-off-by: Depeng Shao --- drivers/cam_isp/cam_isp_context.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index b1ad05f45d2c..4144bfc62a64 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -989,11 +989,11 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, * Always move the request to active list. Let buf done * function handles the rest. */ - CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", - req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); - ctx_isp->active_req_cnt++; list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); if (req->request_id > ctx_isp->reported_req_id) { request_id = req->request_id; @@ -1140,11 +1140,11 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( * Always move the request to active list. Let buf done * function handles the rest. */ - CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d) ctx %u", - req->request_id, ctx_isp->active_req_cnt); - ctx_isp->active_req_cnt++; list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d) ctx %u", + req->request_id, ctx_isp->active_req_cnt); if (!req_isp->bubble_report) { if (req->request_id > ctx_isp->reported_req_id) { @@ -2361,9 +2361,9 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( * Always move the request to active list. Let buf done * function handles the rest. */ - ctx_isp->active_req_cnt++; list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", req->request_id, ctx_isp->active_req_cnt); @@ -3510,21 +3510,6 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, goto end; } - /* - * In case of CSID TPG we might receive SOF and RUP IRQs - * before hw_mgr_intf->hw_start has returned. So move - * req out of pending list before hw_start and add it - * back to pending list if hw_start fails. - */ - list_del_init(&req->list); - - if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) { - list_add_tail(&req->list, &ctx->wait_req_list); - } else { - list_add_tail(&req->list, &ctx->active_req_list); - ctx_isp->active_req_cnt++; - } - start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; start_isp.hw_config.request_id = req->request_id; start_isp.hw_config.hw_update_entries = req_isp->cfg; @@ -3544,6 +3529,21 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, atomic64_set(&ctx_isp->state_monitor_head, -1); + /* + * In case of CSID TPG we might receive SOF and RUP IRQs + * before hw_mgr_intf->hw_start has returned. So move + * req out of pending list before hw_start and add it + * back to pending list if hw_start fails. + */ + list_del_init(&req->list); + + if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) { + list_add_tail(&req->list, &ctx->wait_req_list); + } else { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + } + /* * Only place to change state before calling the hw due to * hardware tasklet has higher priority that can cause the -- GitLab From 7e0fea6d1cb7423dd6e2d3de3c333e91f2f2f658 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 18 Jun 2019 18:57:01 -0700 Subject: [PATCH 071/410] msm: camera: ife: Add dentry to enable req dump This change adds a dentry to enable req dump in the case of hardware errors. CRs-Fixed: 2513939 Change-Id: I0ae5d6c658964bf33d0e4c1775413aaa9201f7a1 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 13 +++++++++++-- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 89b96ca65f4c..c9f950ca921a 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6038,8 +6038,9 @@ static int cam_ife_hw_mgr_handle_hw_err( if (g_ife_hw_mgr.debug_cfg.enable_recovery) error_event_data.recovery_enabled = true; - else - error_event_data.recovery_enabled = false; + + if (g_ife_hw_mgr.debug_cfg.enable_req_dump) + error_event_data.enable_req_dump = true; rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); @@ -6502,6 +6503,14 @@ static int cam_ife_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_bool("enable_req_dump", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_req_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_req_dump"); + goto err; + } + if (!debugfs_create_file("ife_camif_debug", 0644, g_ife_hw_mgr.debug_cfg.dentry, NULL, diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index ffd0a3ec090f..05ee264e93c9 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -90,7 +90,7 @@ struct cam_ife_hw_mgr_debug { uint64_t csid_debug; uint32_t enable_recovery; uint32_t camif_debug; - uint32_t enable_req_dump; + bool enable_req_dump; }; /** -- GitLab From 7642380776261641126aa327495349b763c98193 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 26 Aug 2019 16:21:55 -0700 Subject: [PATCH 072/410] msm: camera: isp: Add support for custom CSID This change adds support for custom csid HW and programming of user defined interfaces (UDI) in custom csid block. CRs-Fixed: 2515662 Change-Id: I4b226b3a3787fbc3e56eb285e9a4dbd6d62edefa Signed-off-by: Karthik Anantha Ram --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 689 ++++++++++++++++-- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 76 +- .../isp_hw/ife_csid_hw/cam_ife_csid_dev.c | 2 +- .../isp_hw/ife_csid_hw/cam_ife_csid_soc.c | 11 +- .../isp_hw/ife_csid_hw/cam_ife_csid_soc.h | 5 +- .../isp_hw/include/cam_ife_csid_hw_intf.h | 5 + 6 files changed, 737 insertions(+), 51 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index c48d320d0945..ec41759cf50c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -445,6 +445,11 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + for (i = 0 ; i < csid_reg->cmn_reg->num_udis; i++) + cam_io_w_mb(csid_reg->cmn_reg->udi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); @@ -571,7 +576,10 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, val |= CSID_PATH_INFO_RST_DONE; cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_mask_addr); - } else { + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { id = res->res_id; if (!csid_reg->rdi_reg[id]) { CAM_ERR(CAM_ISP, "CSID:%d RDI res not supported :%d", @@ -591,6 +599,31 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, val |= CSID_PATH_INFO_RST_DONE; cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if (!csid_reg->udi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d UDI res not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = + csid_reg->udi_reg[id]->csid_udi_rst_strobes_addr; + complete = + &csid_hw->csid_udin_complete[id]; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id %u", res->res_id); + return -EINVAL; } init_completion(complete); @@ -623,10 +656,10 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, } -static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, +int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, struct cam_csid_hw_reserve_resource_args *cid_reserv) { - int rc = 0, i; + int rc = 0, i, id; struct cam_ife_csid_cid_data *cid_data; uint32_t camera_hw_version; uint32_t valid_vc_dt; @@ -819,6 +852,20 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, goto end; } break; + case CAM_IFE_PIX_PATH_RES_UDI_0: + case CAM_IFE_PIX_PATH_RES_UDI_1: + case CAM_IFE_PIX_PATH_RES_UDI_2: + id = cid_reserv->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if (csid_hw->udi_res[id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d UDI:%d resource not available", + csid_hw->hw_intf->hw_idx, + cid_reserv->res_id); + rc = -EINVAL; + goto end; + } + break; default: CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path", csid_hw->hw_intf->hw_idx); @@ -894,11 +941,10 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, return rc; } - -static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, +int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, struct cam_csid_hw_reserve_resource_args *reserve) { - int rc = 0, i; + int rc = 0, i, id; struct cam_ife_csid_path_cfg *path_data; struct cam_isp_resource_node *res; @@ -998,6 +1044,28 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, res->res_id); } + break; + case CAM_IFE_PIX_PATH_RES_UDI_0: + case CAM_IFE_PIX_PATH_RES_UDI_1: + case CAM_IFE_PIX_PATH_RES_UDI_2: + id = reserve->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if (csid_hw->udi_res[id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d UDI:%d resource not available %d", + csid_hw->hw_intf->hw_idx, + reserve->res_id, + csid_hw->udi_res[id].res_state); + rc = -EINVAL; + goto end; + } else { + res = &csid_hw->udi_res[id]; + CAM_DBG(CAM_ISP, + "CSID:%d UDI resource:%d acquire success", + csid_hw->hw_intf->hw_idx, + res->res_id); + } + break; default: CAM_ERR(CAM_ISP, "CSID:%d Invalid res id:%d", @@ -1020,6 +1088,7 @@ static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->drop_enable = reserve->drop_enable; path_data->horizontal_bin = reserve->in_port->horizontal_bin; path_data->qcfa_bin = reserve->in_port->qcfa_bin; + path_data->num_bytes_out = reserve->in_port->num_bytes_out; CAM_DBG(CAM_ISP, "Res id: %d height:%d line_start %d line_stop %d crop_en %d", @@ -1155,6 +1224,11 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) + cam_io_w_mb(csid_reg->cmn_reg->udi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); @@ -2185,6 +2259,207 @@ static int cam_ife_csid_init_config_rdi_path( return rc; } +static int cam_ife_csid_init_config_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t path_format = 0, plain_fmt = 0, val = 0, val1, id; + uint32_t format_measure_addr; + + path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if ((id >= CAM_IFE_CSID_UDI_MAX) || (!csid_reg->udi_reg[id])) { + CAM_ERR(CAM_ISP, "CSID:%d UDI:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, id); + return -EINVAL; + } + + rc = cam_ife_csid_get_format_rdi(path_data->in_format, + path_data->out_format, &path_format, &plain_fmt); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to get format in_format: %u out_format: %u rc: %d", + path_data->in_format, path_data->out_format, rc); + return rc; + } + + /* if path decode format is payload only then UDI crop is not applied */ + if (path_format == 0xF) + path_data->crop_enable = false; + + /* + * UDI path config and enable the time stamp capture + * Enable the measurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (path_format << csid_reg->cmn_reg->fmt_shift_val) | + (plain_fmt << csid_reg->cmn_reg->plain_fmt_shit_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << 2) | 3; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + + /* select the post irq sub sample strobe for time stamp capture */ + val1 = CSID_TIMESTAMP_STB_POST_IRQ; + + /* select the num bytes out per cycle */ + val1 |= (path_data->num_bytes_out << + csid_reg->cmn_reg->num_bytes_out_shift_val); + + cam_io_w_mb(val1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg1_addr); + + /* Enable Error Detection */ + if (csid_reg->udi_reg[id]->overflow_ctrl_en) { + val = csid_reg->udi_reg[id]->overflow_ctrl_en; + /* Overflow ctrl mode: 2 -> Detect overflow */ + val |= 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_err_recovery_cfg0_addr); + } + + /* set frame drop pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_frm_drop_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_frm_drop_pattern_addr); + /* set IRQ sum sabmple */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_subsample_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_subsample_pattern_addr); + + /* set pixel drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_pix_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_pix_drop_period_addr); + /* set line drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_line_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_line_drop_period_addr); + + /* Configure the halt mode */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) + val |= csid_reg->cmn_reg->format_measure_en_val; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + + format_measure_addr = + csid_reg->udi_reg[id]->csid_udi_format_measure_cfg0_addr; + + /* Enable the HBI/VBI counter */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val |= csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + format_measure_addr); + } + + /* configure the rx packet capture based on csid debug set */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_ife_csid_deinit_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t id, val, format_measure_addr; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + + if ((res->res_id < CAM_IFE_PIX_PATH_RES_UDI_0) || + (res->res_id > CAM_IFE_PIX_PATH_RES_UDI_2) || + (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) || + (!csid_reg->udi_reg[id])) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + /* Disable Error Recovery */ + if (csid_reg->udi_reg[id]->overflow_ctrl_en) { + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_err_recovery_cfg0_addr); + } + + format_measure_addr = + csid_reg->udi_reg[id]->csid_udi_format_measure_cfg0_addr; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + val &= ~csid_reg->cmn_reg->format_measure_en_val; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + + /* Disable the HBI/VBI counter */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val &= ~csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + format_measure_addr); + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + static int cam_ife_csid_deinit_rdi_path( struct cam_ife_csid_hw *csid_hw, struct cam_isp_resource_node *res) @@ -2284,6 +2559,56 @@ static int cam_ife_csid_enable_rdi_path( return 0; } +static int cam_ife_csid_enable_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t id, val; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + + if ((res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) || + (res->res_id > CAM_IFE_PIX_PATH_RES_UDI_2) || + (res->res_id < CAM_IFE_PIX_PATH_RES_UDI_0) || + (!csid_reg->udi_reg[id])) { + CAM_ERR(CAM_ISP, + "CSID:%d invalid res type:%d res_id:%d state%d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + /*resume at frame boundary */ + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + + /* Enable the required UDI interrupts */ + val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + + if (csid_reg->udi_reg[id]->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + + if (csid_reg->udi_reg[id]->overflow_ctrl_en) + val |= CSID_PATH_OVERFLOW_RECOVERY; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + val |= CSID_PATH_INFO_INPUT_SOF; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) + val |= CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} static int cam_ife_csid_disable_rdi_path( struct cam_ife_csid_hw *csid_hw, @@ -2347,11 +2672,74 @@ static int cam_ife_csid_disable_rdi_path( return rc; } +static int cam_ife_csid_disable_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_ife_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t id, val = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + + if ((res->res_id > CAM_IFE_PIX_PATH_RES_UDI_2) || + (res->res_id < CAM_IFE_PIX_PATH_RES_UDI_0) || + (!csid_reg->udi_reg[id])) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, res->res_state); + return rc; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d Invalid res_state%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + if (stop_cmd != CAM_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, "CSID:%d un supported stop command:%d", + csid_hw->hw_intf->hw_idx, stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + + /* Halt the UDI path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + + return rc; +} + static int cam_ife_csid_poll_stop_status( struct cam_ife_csid_hw *csid_hw, uint32_t res_mask) { - int rc = 0; + int rc = 0, id; uint32_t csid_status_addr = 0, val = 0, res_id = 0; const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; @@ -2370,9 +2758,22 @@ static int cam_ife_csid_poll_stop_status( } else if (res_id == CAM_IFE_PIX_PATH_RES_PPP) { csid_status_addr = csid_reg->ppp_reg->csid_pxl_status_addr; - } else { + } else if (res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { csid_status_addr = csid_reg->rdi_reg[res_id]->csid_rdi_status_addr; + } else if (res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + csid_status_addr = + csid_reg->udi_reg[id]->csid_udi_status_addr; + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res_id); + rc = -EINVAL; + break; } CAM_DBG(CAM_ISP, "start polling CSID:%d res_id:%d", @@ -2400,8 +2801,10 @@ static int cam_ife_csid_get_hbi_vbi( struct cam_isp_resource_node *res) { uint32_t hbi, vbi; + int32_t id; const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_rdi_reg_offset *rdi_reg; + const struct cam_ife_csid_udi_reg_offset *udi_reg; struct cam_hw_soc_info *soc_info; csid_reg = csid_hw->csid_info->csid_reg; @@ -2432,12 +2835,27 @@ static int cam_ife_csid_get_hbi_vbi( csid_reg->ppp_reg->csid_pxl_format_measure1_addr); vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_format_measure2_addr); - } else { + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { rdi_reg = csid_reg->rdi_reg[res->res_id]; hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + rdi_reg->csid_rdi_format_measure1_addr); vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + rdi_reg->csid_rdi_format_measure2_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + udi_reg = csid_reg->udi_reg[id]; + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_format_measure2_addr); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + return -EINVAL; } CAM_INFO_RATE_LIMIT(CAM_ISP, @@ -2448,7 +2866,6 @@ static int cam_ife_csid_get_hbi_vbi( return 0; } - static int cam_ife_csid_get_time_stamp( struct cam_ife_csid_hw *csid_hw, void *cmd_args) { @@ -2457,6 +2874,7 @@ static int cam_ife_csid_get_time_stamp( const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_rdi_reg_offset *rdi_reg; + const struct cam_ife_csid_udi_reg_offset *udi_reg; struct timespec64 ts; uint32_t time_32, id; @@ -2494,7 +2912,10 @@ static int cam_ife_csid_get_time_stamp( time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_timestamp_curr0_sof_addr); - } else { + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { id = res->res_id; rdi_reg = csid_reg->rdi_reg[id]; time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -2504,6 +2925,21 @@ static int cam_ife_csid_get_time_stamp( time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + rdi_reg->csid_rdi_timestamp_curr0_sof_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + udi_reg = csid_reg->udi_reg[id]; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_timestamp_curr0_sof_addr); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + return -EINVAL; } time_stamp->time_stamp_val |= (uint64_t) time_32; @@ -2532,7 +2968,7 @@ static int cam_ife_csid_set_csid_debug(struct cam_ife_csid_hw *csid_hw, return 0; } -static int cam_ife_csid_get_hw_caps(void *hw_priv, +int cam_ife_csid_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) { int rc = 0; @@ -2567,7 +3003,7 @@ static int cam_ife_csid_get_hw_caps(void *hw_priv, return rc; } -static int cam_ife_csid_reset(void *hw_priv, +int cam_ife_csid_reset(void *hw_priv, void *reset_args, uint32_t arg_size) { struct cam_ife_csid_hw *csid_hw; @@ -2602,7 +3038,7 @@ static int cam_ife_csid_reset(void *hw_priv, return rc; } -static int cam_ife_csid_reserve(void *hw_priv, +int cam_ife_csid_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) { int rc = 0; @@ -2641,7 +3077,7 @@ static int cam_ife_csid_reserve(void *hw_priv, return rc; } -static int cam_ife_csid_release(void *hw_priv, +int cam_ife_csid_release(void *hw_priv, void *release_args, uint32_t arg_size) { int rc = 0; @@ -2762,7 +3198,7 @@ static int cam_ife_csid_reset_retain_sw_reg( return rc; } -static int cam_ife_csid_init_hw(void *hw_priv, +int cam_ife_csid_init_hw(void *hw_priv, void *init_args, uint32_t arg_size) { int rc = 0; @@ -2819,10 +3255,22 @@ static int cam_ife_csid_init_hw(void *hw_priv, break; case CAM_ISP_RESOURCE_PIX_PATH: if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || - res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { rc = cam_ife_csid_init_config_pxl_path(csid_hw, res); - else + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { rc = cam_ife_csid_init_config_rdi_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_init_config_udi_path(csid_hw, res); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + rc = -EINVAL; + goto end; + } break; default: @@ -2847,7 +3295,7 @@ static int cam_ife_csid_init_hw(void *hw_priv, return rc; } -static int cam_ife_csid_deinit_hw(void *hw_priv, +int cam_ife_csid_deinit_hw(void *hw_priv, void *deinit_args, uint32_t arg_size) { int rc = 0; @@ -2882,10 +3330,22 @@ static int cam_ife_csid_deinit_hw(void *hw_priv, case CAM_ISP_RESOURCE_PIX_PATH: CAM_DBG(CAM_ISP, "De-Init Pix Path: %d\n", res->res_id); if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || - res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { rc = cam_ife_csid_deinit_pxl_path(csid_hw, res); - else + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { rc = cam_ife_csid_deinit_rdi_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_deinit_udi_path(csid_hw, res); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + rc = -EINVAL; + goto end; + } break; default: @@ -2905,7 +3365,7 @@ static int cam_ife_csid_deinit_hw(void *hw_priv, return rc; } -static int cam_ife_csid_start(void *hw_priv, void *start_args, +int cam_ife_csid_start(void *hw_priv, void *start_args, uint32_t arg_size) { int rc = 0; @@ -2950,10 +3410,23 @@ static int cam_ife_csid_start(void *hw_priv, void *start_args, break; case CAM_ISP_RESOURCE_PIX_PATH: if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || - res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { rc = cam_ife_csid_enable_pxl_path(csid_hw, res); - else + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { rc = cam_ife_csid_enable_rdi_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_enable_udi_path(csid_hw, res); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + rc = -EINVAL; + goto end; + } + break; default: CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", @@ -2965,7 +3438,7 @@ static int cam_ife_csid_start(void *hw_priv, void *start_args, return rc; } -static int cam_ife_csid_stop(void *hw_priv, +int cam_ife_csid_stop(void *hw_priv, void *stop_args, uint32_t arg_size) { int rc = 0; @@ -3008,12 +3481,25 @@ static int cam_ife_csid_stop(void *hw_priv, case CAM_ISP_RESOURCE_PIX_PATH: res_mask |= (1 << res->res_id); if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || - res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { rc = cam_ife_csid_disable_pxl_path(csid_hw, res, csid_stop->stop_cmd); - else + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { rc = cam_ife_csid_disable_rdi_path(csid_hw, res, csid_stop->stop_cmd); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_disable_udi_path(csid_hw, + res, csid_stop->stop_cmd); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", + res->res_id); + return -EINVAL; + } break; default: @@ -3038,7 +3524,7 @@ static int cam_ife_csid_stop(void *hw_priv, } -static int cam_ife_csid_read(void *hw_priv, +int cam_ife_csid_read(void *hw_priv, void *read_args, uint32_t arg_size) { CAM_ERR(CAM_ISP, "CSID: un supported"); @@ -3046,7 +3532,7 @@ static int cam_ife_csid_read(void *hw_priv, return -EINVAL; } -static int cam_ife_csid_write(void *hw_priv, +int cam_ife_csid_write(void *hw_priv, void *write_args, uint32_t arg_size) { CAM_ERR(CAM_ISP, "CSID: un supported"); @@ -3107,6 +3593,21 @@ static int cam_ife_csid_sof_irq_debug( } } + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_mask_addr); + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_mask_addr); + val = 0; + } + } + if (sof_irq_enable) { csid_hw->csid_debug |= CSID_DEBUG_ENABLE_SOF_IRQ; csid_hw->sof_irq_triggered = true; @@ -3210,7 +3711,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; - uint32_t irq_status_rdi[4] = {0, 0, 0, 0}; + uint32_t irq_status_rdi[CAM_IFE_CSID_RDI_MAX] = {0, 0, 0, 0}; + uint32_t irq_status_udi[CAM_IFE_CSID_UDI_MAX] = {0, 0, 0}; uint32_t val, irq_status_ppp = 0; bool fatal_err_detected = false; uint32_t sof_irq_debug_en = 0; @@ -3244,10 +3746,21 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) irq_status_ppp = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_status_addr); + if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + irq_status_rdi[i] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); + } + } - for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) - irq_status_rdi[i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); + if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + irq_status_udi[i] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_status_addr); + } + } /* clear */ cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + @@ -3260,10 +3773,22 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) cam_io_w_mb(irq_status_ppp, soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); - for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - cam_io_w_mb(irq_status_rdi[i], soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + cam_io_w_mb(irq_status_rdi[i], + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + } } + + if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + cam_io_w_mb(irq_status_udi[i], + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); + } + } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); @@ -3271,9 +3796,12 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); - CAM_DBG(CAM_ISP, "irq_status_rdi0= 0x%x", irq_status_rdi[0]); - CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]); - CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]); + CAM_DBG(CAM_ISP, + "irq_status_rdi0= 0x%x irq_status_rdi1= 0x%x irq_status_rdi2= 0x%x", + irq_status_rdi[0], irq_status_rdi[1], irq_status_rdi[2]); + CAM_DBG(CAM_ISP, + "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", + irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); @@ -3578,6 +4106,46 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } } + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + if (irq_status_udi[i] & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID UDI%d reset complete", i); + complete(&csid_hw->csid_udin_complete[i]); + } + + if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID UDI:%d SOF received", i); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID UDI:%d EOF received", i); + + if ((irq_status_udi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "CSID UDI :%d CCIF violation", i); + + if ((irq_status_udi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "CSID UDI :%d Overflow due to back pressure", + i); + + if (irq_status_udi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d UDI fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop UDI path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_ctrl_addr); + } + } + if (csid_hw->irq_debug_cnt >= CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX) { cam_ife_csid_sof_irq_debug(csid_hw, &sof_irq_debug_en); csid_hw->irq_debug_cnt = 0; @@ -3588,7 +4156,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, - uint32_t csid_idx) + uint32_t csid_idx, bool is_custom) { int rc = -EINVAL; uint32_t i; @@ -3627,9 +4195,11 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) init_completion(&ife_csid_hw->csid_rdin_complete[i]); + for (i = 0; i < CAM_IFE_CSID_UDI_MAX; i++) + init_completion(&ife_csid_hw->csid_udin_complete[i]); rc = cam_ife_csid_init_soc_resources(&ife_csid_hw->hw_info->soc_info, - cam_ife_csid_irq, ife_csid_hw); + cam_ife_csid_irq, ife_csid_hw, is_custom); if (rc < 0) { CAM_ERR(CAM_ISP, "CSID:%d Failed to init_soc", csid_idx); goto err; @@ -3651,7 +4221,8 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->hw_intf->hw_ops.process_cmd = cam_ife_csid_process_cmd; num_paths = ife_csid_hw->csid_info->csid_reg->cmn_reg->num_pix + - ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis + + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; /* Initialize the CID resource */ for (i = 0; i < num_paths; i++) { ife_csid_hw->cid_res[i].res_type = CAM_ISP_RESOURCE_CID; @@ -3721,6 +4292,27 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->rdi_res[i].res_priv = path_data; } + /* Initialize the UDI resource */ + for (i = 0; i < ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; + i++) { + /* res type is from UDI0 to UDI3 */ + ife_csid_hw->udi_res[i].res_type = + CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->udi_res[i].res_id = i + + CAM_IFE_PIX_PATH_RES_UDI_0; + ife_csid_hw->udi_res[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->udi_res[i].hw_intf = ife_csid_hw->hw_intf; + + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->udi_res[i].res_priv = path_data; + } + ife_csid_hw->csid_debug = 0; ife_csid_hw->error_irq_count = 0; @@ -3734,6 +4326,11 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, i++) kfree(ife_csid_hw->rdi_res[i].res_priv); + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; + i++) + kfree(ife_csid_hw->udi_res[i].res_priv); + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) kfree(ife_csid_hw->cid_res[i].res_priv); @@ -3741,7 +4338,7 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, return rc; } - +EXPORT_SYMBOL(cam_ife_csid_hw_probe_init); int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw) { @@ -3761,6 +4358,11 @@ int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw) i++) { kfree(ife_csid_hw->rdi_res[i].res_priv); } + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; + i++) { + kfree(ife_csid_hw->udi_res[i].res_priv); + } for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) kfree(ife_csid_hw->cid_res[i].res_priv); @@ -3768,3 +4370,4 @@ int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw) return 0; } +EXPORT_SYMBOL(cam_ife_csid_hw_deinit); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index d4a3a840d969..e4c8bafb6303 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -9,6 +9,7 @@ #include "cam_hw.h" #include "cam_ife_csid_hw_intf.h" #include "cam_ife_csid_soc.h" +#include "cam_ife_csid_core.h" #define CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED BIT(0) #define CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED BIT(1) @@ -192,6 +193,59 @@ struct cam_ife_csid_rdi_reg_offset { uint32_t overflow_ctrl_en; }; +struct cam_ife_csid_udi_reg_offset { + uint32_t csid_udi_irq_status_addr; + uint32_t csid_udi_irq_mask_addr; + uint32_t csid_udi_irq_clear_addr; + uint32_t csid_udi_irq_set_addr; + + /* UDI N register address */ + uint32_t csid_udi_cfg0_addr; + uint32_t csid_udi_cfg1_addr; + uint32_t csid_udi_ctrl_addr; + uint32_t csid_udi_frm_drop_pattern_addr; + uint32_t csid_udi_frm_drop_period_addr; + uint32_t csid_udi_irq_subsample_pattern_addr; + uint32_t csid_udi_irq_subsample_period_addr; + uint32_t csid_udi_rpp_hcrop_addr; + uint32_t csid_udi_rpp_vcrop_addr; + uint32_t csid_udi_rpp_pix_drop_pattern_addr; + uint32_t csid_udi_rpp_pix_drop_period_addr; + uint32_t csid_udi_rpp_line_drop_pattern_addr; + uint32_t csid_udi_rpp_line_drop_period_addr; + uint32_t csid_udi_yuv_chroma_conversion_addr; + uint32_t csid_udi_rst_strobes_addr; + uint32_t csid_udi_status_addr; + uint32_t csid_udi_misr_val0_addr; + uint32_t csid_udi_misr_val1_addr; + uint32_t csid_udi_misr_val2_addr; + uint32_t csid_udi_misr_val3_addr; + uint32_t csid_udi_format_measure_cfg0_addr; + uint32_t csid_udi_format_measure_cfg1_addr; + uint32_t csid_udi_format_measure0_addr; + uint32_t csid_udi_format_measure1_addr; + uint32_t csid_udi_format_measure2_addr; + uint32_t csid_udi_timestamp_curr0_sof_addr; + uint32_t csid_udi_timestamp_curr1_sof_addr; + uint32_t csid_udi_timestamp_prev0_sof_addr; + uint32_t csid_udi_timestamp_prev1_sof_addr; + uint32_t csid_udi_timestamp_curr0_eof_addr; + uint32_t csid_udi_timestamp_curr1_eof_addr; + uint32_t csid_udi_timestamp_prev0_eof_addr; + uint32_t csid_udi_timestamp_prev1_eof_addr; + uint32_t csid_udi_err_recovery_cfg0_addr; + uint32_t csid_udi_err_recovery_cfg1_addr; + uint32_t csid_udi_err_recovery_cfg2_addr; + uint32_t csid_udi_multi_vcdt_cfg0_addr; + uint32_t csid_udi_byte_cntr_ping_addr; + uint32_t csid_udi_byte_cntr_pong_addr; + + /* configuration */ + uint32_t packing_format; + uint32_t ccif_violation_en; + uint32_t overflow_ctrl_en; +}; + struct cam_ife_csid_csi2_rx_reg_offset { uint32_t csid_csi2_rx_irq_status_addr; uint32_t csid_csi2_rx_irq_mask_addr; @@ -288,6 +342,7 @@ struct cam_ife_csid_common_reg_offset { uint32_t major_version; uint32_t minor_version; uint32_t version_incr; + uint32_t num_udis; uint32_t num_rdis; uint32_t num_pix; uint32_t num_ppp; @@ -310,8 +365,10 @@ struct cam_ife_csid_common_reg_offset { uint32_t ipp_irq_mask_all; uint32_t rdi_irq_mask_all; uint32_t ppp_irq_mask_all; + uint32_t udi_irq_mask_all; uint32_t measure_en_hbi_vbi_cnt_mask; uint32_t format_measure_en_val; + uint32_t num_bytes_out_shift_val; }; /** @@ -320,7 +377,9 @@ struct cam_ife_csid_common_reg_offset { * @cmn_reg: csid common registers info * @ipp_reg: ipp register offset information * @ppp_reg: ppp register offset information - * @rdi_reg: rdi register offser information + * @rdi_reg: rdi register offset information + * @udi_reg: udi register offset information + * @tpg_reg: tpg register offset information * */ struct cam_ife_csid_reg_offset { @@ -329,6 +388,7 @@ struct cam_ife_csid_reg_offset { const struct cam_ife_csid_pxl_reg_offset *ipp_reg; const struct cam_ife_csid_pxl_reg_offset *ppp_reg; const struct cam_ife_csid_rdi_reg_offset *rdi_reg[CAM_IFE_CSID_RDI_MAX]; + const struct cam_ife_csid_udi_reg_offset *udi_reg[CAM_IFE_CSID_UDI_MAX]; const struct cam_ife_csid_csi2_tpg_reg_offset *tpg_reg; }; @@ -427,6 +487,7 @@ struct cam_ife_csid_cid_data { * @master_idx: For Slave reservation, Give master IFE instance Index. * Slave will synchronize with master Start and stop operations * @clk_rate Clock rate + * @num_bytes_out: Number of output bytes per cycle * */ struct cam_ife_csid_path_cfg { @@ -451,6 +512,7 @@ struct cam_ife_csid_path_cfg { uint64_t clk_rate; uint32_t horizontal_bin; uint32_t qcfa_bin; + uint32_t num_bytes_out; }; /** @@ -468,12 +530,14 @@ struct cam_ife_csid_path_cfg { * @ipp_res: image pixel path resource * @ppp_res: phase pxl path resource * @rdi_res: raw dump image path resources + * @udi_res: udi path resources * @cid_res: cid resources state * @csid_top_reset_complete: csid top reset completion * @csid_csi2_reset_complete: csi2 reset completion * @csid_ipp_reset_complete: ipp reset completion * @csid_ppp_complete: ppp reset completion * @csid_rdin_reset_complete: rdi n completion + * @csid_udin_reset_complete: udi n completion * @csid_debug: csid debug information to enable the SOT, EOT, * SOF, EOF, measure etc in the csid hw * @clk_rate Clock rate @@ -499,12 +563,14 @@ struct cam_ife_csid_hw { struct cam_isp_resource_node ipp_res; struct cam_isp_resource_node ppp_res; struct cam_isp_resource_node rdi_res[CAM_IFE_CSID_RDI_MAX]; + struct cam_isp_resource_node udi_res[CAM_IFE_CSID_UDI_MAX]; struct cam_isp_resource_node cid_res[CAM_IFE_CSID_CID_MAX]; struct completion csid_top_complete; struct completion csid_csi2_complete; struct completion csid_ipp_complete; struct completion csid_ppp_complete; struct completion csid_rdin_complete[CAM_IFE_CSID_RDI_MAX]; + struct completion csid_udin_complete[CAM_IFE_CSID_UDI_MAX]; uint64_t csid_debug; uint64_t clk_rate; bool sof_irq_triggered; @@ -517,8 +583,14 @@ struct cam_ife_csid_hw { }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, - uint32_t csid_idx); + uint32_t csid_idx, bool is_custom); int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw); +int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *cid_reserv); + +int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *reserve); + #endif /* _CAM_IFE_CSID_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c index 05bf36899392..eca0e43a9b5e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c @@ -76,7 +76,7 @@ int cam_ife_csid_probe(struct platform_device *pdev) /* need to setup the pdev before call the ife hw probe init */ csid_dev->csid_info = csid_hw_data; - rc = cam_ife_csid_hw_probe_init(csid_hw_intf, csid_dev_idx); + rc = cam_ife_csid_hw_probe_init(csid_hw_intf, csid_dev_idx, false); if (rc) goto free_dev; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c index 3a6d3e8abf98..ede6dbc5ea6e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -39,7 +39,7 @@ static int cam_ife_csid_request_platform_resource( } int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, - irq_handler_t csid_irq_handler, void *irq_data) + irq_handler_t csid_irq_handler, void *irq_data, bool is_custom) { int rc = 0; struct cam_cpas_register_params cpas_register_param; @@ -66,8 +66,13 @@ int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, } memset(&cpas_register_param, 0, sizeof(cpas_register_param)); - strlcpy(cpas_register_param.identifier, "csid", - CAM_HW_IDENTIFIER_LENGTH); + if (is_custom) + strlcpy(cpas_register_param.identifier, "csid-custom", + CAM_HW_IDENTIFIER_LENGTH); + else + strlcpy(cpas_register_param.identifier, "csid", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; cpas_register_param.dev = soc_info->dev; rc = cam_cpas_register_client(&cpas_register_param); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h index 317dcb39a59b..4f76d084fba3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_SOC_H_ @@ -39,10 +39,11 @@ struct csid_device_soc_info { * @soc_info: soc info structure pointer * @csid_irq_handler: irq handler function to be registered * @irq_data: irq data for the callback function + * @is_custom: for custom csid hw * */ int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, - irq_handler_t csid_irq_handler, void *irq_data); + irq_handler_t csid_irq_handler, void *irq_data, bool is_custom); /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index e31cddc91b11..56ce59636dda 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -12,6 +12,7 @@ /* MAX IFE CSID instance */ #define CAM_IFE_CSID_HW_NUM_MAX 7 #define CAM_IFE_CSID_RDI_MAX 4 +#define CAM_IFE_CSID_UDI_MAX 3 /** * enum cam_ife_pix_path_res_id - Specify the csid patch @@ -23,6 +24,9 @@ enum cam_ife_pix_path_res_id { CAM_IFE_PIX_PATH_RES_RDI_3, CAM_IFE_PIX_PATH_RES_IPP, CAM_IFE_PIX_PATH_RES_PPP, + CAM_IFE_PIX_PATH_RES_UDI_0, + CAM_IFE_PIX_PATH_RES_UDI_1, + CAM_IFE_PIX_PATH_RES_UDI_2, CAM_IFE_PIX_PATH_RES_MAX, }; @@ -97,6 +101,7 @@ struct cam_isp_in_port_generic_info { uint32_t num_out_res; uint32_t horizontal_bin; uint32_t qcfa_bin; + uint32_t num_bytes_out; struct cam_isp_out_port_generic_info *data; }; -- GitLab From 02f76464135a71868aa200644f2266be27abda4a Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 26 Aug 2019 13:37:18 -0700 Subject: [PATCH 073/410] msm: camera: custom: Add uapi for custom HW This change adds uapi for custom HW block. CRs-Fixed: 2515662 Change-Id: Id4284594746a313ab09dad5c290cedc2b9edb62c Signed-off-by: Karthik Anantha Ram --- include/uapi/media/cam_custom.h | 198 +++++++++++++++++++++++++++++++ include/uapi/media/cam_req_mgr.h | 1 + 2 files changed, 199 insertions(+) create mode 100644 include/uapi/media/cam_custom.h diff --git a/include/uapi/media/cam_custom.h b/include/uapi/media/cam_custom.h new file mode 100644 index 000000000000..b36891f4a0dc --- /dev/null +++ b/include/uapi/media/cam_custom.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_CUSTOM_H__ +#define __UAPI_CAM_CUSTOM_H__ + +#include "cam_defs.h" + +/* Custom driver name */ +#define CAM_CUSTOM_DEV_NAME "cam-custom" + +#define CAM_CUSTOM_NUM_SUB_DEVICES 2 + +/* HW type */ +#define CAM_CUSTOM_HW1 0 +#define CAM_CUSTOM_HW2 1 + +/* output path resource id's */ +#define CAM_CUSTOM_OUT_RES_UDI_0 1 +#define CAM_CUSTOM_OUT_RES_UDI_1 2 +#define CAM_CUSTOM_OUT_RES_UDI_2 3 + +/* input resource for custom hw */ +#define CAM_CUSTOM_IN_RES_UDI_0 1 + +/* Resource ID */ +#define CAM_CUSTOM_RES_ID_PORT 0 + +/* Packet opcode for Custom */ +#define CAM_CUSTOM_PACKET_OP_BASE 0 +#define CAM_CUSTOM_PACKET_INIT_DEV 1 +#define CAM_CUSTOM_PACKET_UPDATE_DEV 2 +#define CAM_CUSTOM_PACKET_OP_MAX 3 + +/* max number of vc-dt cfg for a given input */ +#define CAM_CUSTOM_VC_DT_CFG_MAX 4 + +/* phy input resource types */ +#define CAM_CUSTOM_IN_RES_BASE 0x5000 +#define CAM_CUSTOM_IN_RES_PHY_0 (CAM_CUSTOM_IN_RES_BASE + 1) +#define CAM_CUSTOM_IN_RES_PHY_1 (CAM_CUSTOM_IN_RES_BASE + 2) +#define CAM_CUSTOM_IN_RES_PHY_2 (CAM_CUSTOM_IN_RES_BASE + 3) +#define CAM_CUSTOM_IN_RES_PHY_3 (CAM_CUSTOM_IN_RES_BASE + 4) + +/* Query devices */ +/** + * struct cam_custom_dev_cap_info - A cap info for particular hw type + * + * @hw_type: Custom HW type + * @hw_version: Hardware version + * + */ +struct cam_custom_dev_cap_info { + uint32_t hw_type; + uint32_t hw_version; +}; + +/** + * struct cam_custom_query_cap_cmd - Custom HW query device capability payload + * + * @device_iommu: returned iommu handles for device + * @cdm_iommu: returned iommu handles for cdm + * @num_dev: returned number of device capabilities + * @reserved: reserved field for alignment + * @dev_caps: returned device capability array + * + */ +struct cam_custom_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + int32_t num_dev; + uint32_t reserved; + struct cam_custom_dev_cap_info dev_caps[CAM_CUSTOM_NUM_SUB_DEVICES]; +}; + +/* Acquire Device */ +/** + * struct cam_custom_out_port_info - An output port resource info + * + * @res_type: output resource type + * @format: output format of the resource + * @custom_info 1-3: custom params + * @reserved: reserved field for alignment + * + */ +struct cam_custom_out_port_info { + uint32_t res_type; + uint32_t format; + uint32_t custom_info1; + uint32_t custom_info2; + uint32_t custom_info3; + uint32_t reserved; +}; + +/** + * struct cam_custom_in_port_info - An input port resource info + * + * @res_type: input resource type + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @num_valid_vc_dt: number of valid vc-dt + * @format: input format + * @test_pattern: test pattern for the testgen + * @usage_type: whether dual vfe is required + * @left_start: left input start offset in pixels + * @left_stop: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * @right_stop: right input stop offset in pixels. + * @right_width: right input width in pixels. + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @pixel_clk; sensor output clock + * @num_out_byte: number of valid output bytes per cycle + * @custom_info1: custom_info1 + * @custom_info2: custom info 2 + * @num_out_res: number of the output resource associated + * @data: payload that contains the output resources + * + */ +struct cam_custom_in_port_info { + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc[CAM_CUSTOM_VC_DT_CFG_MAX]; + uint32_t dt[CAM_CUSTOM_VC_DT_CFG_MAX]; + uint32_t num_valid_vc_dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t num_bytes_out; + uint32_t custom_info1; + uint32_t custom_info2; + uint32_t num_out_res; + struct cam_custom_out_port_info data[1]; +}; + +/** + * struct cam_custom_resource - A resource bundle + * + * @resoruce_id: resource id for the resource bundle + * @length: length of the while resource blob + * @handle_type: type of the resource handle + * @reserved: reserved field for alignment + * @res_hdl: resource handle that points to the + * resource array; + */ +struct cam_custom_resource { + uint32_t resource_id; + uint32_t length; + uint32_t handle_type; + uint32_t reserved; + uint64_t res_hdl; +}; + +/** + * struct cam_custom_cmd_buf_type_1 - cmd buf type 1 + * + * @custom_info: custom info + * @reserved: reserved + */ +struct cam_custom_cmd_buf_type_1 { + uint32_t custom_info; + uint32_t reserved; +}; + +/** + * struct cam_custom_cmd_buf_type_2 - cmd buf type 2 + * + * @custom_info1: Custom info 1 + * @custom_info2: Custom info 2 + * @custom_info3: Custom info 3 + * @reserved: reserved + */ +struct cam_custom_cmd_buf_type_2 { + uint32_t custom_info1; + uint32_t custom_info2; + uint32_t custom_info3; + uint32_t reserved; +}; +#endif /* __UAPI_CAM_CUSTOM_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index a1278dda9b09..36471a290ad3 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -29,6 +29,7 @@ #define CAM_FLASH_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 11) #define CAM_EEPROM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 12) #define CAM_OIS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 13) +#define CAM_CUSTOM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 14) /* cam_req_mgr hdl info */ #define CAM_REQ_MGR_HDL_IDX_POS 8 -- GitLab From 9c771385d3db9828bddc66f1aca863f09ac1a2b7 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 26 Aug 2019 16:28:49 -0700 Subject: [PATCH 074/410] msm: camera: custom: Add support for custom HW This change provides a template to add any custom HW block. CRs-Fixed: 2515662 Change-Id: Ie707c27950a330658cdaa4b64b7e304f4d62a5b2 Signed-off-by: Karthik Anantha Ram --- drivers/Makefile | 1 + drivers/cam_cust/Makefile | 19 + drivers/cam_cust/cam_custom_context.c | 945 ++++++++++++ drivers/cam_cust/cam_custom_context.h | 115 ++ drivers/cam_cust/cam_custom_dev.c | 198 +++ drivers/cam_cust/cam_custom_dev.h | 34 + drivers/cam_cust/cam_custom_hw_mgr/Makefile | 20 + .../cam_custom_csid/Makefile | 16 + .../cam_custom_csid/cam_custom_csid480.h | 272 ++++ .../cam_custom_csid/cam_custom_csid_dev.c | 190 +++ .../cam_custom_csid/cam_custom_csid_dev.h | 12 + .../cam_custom_hw_mgr/cam_custom_hw1/Makefile | 10 + .../cam_custom_hw1/cam_custom_sub_mod_core.c | 337 +++++ .../cam_custom_hw1/cam_custom_sub_mod_core.h | 79 + .../cam_custom_hw1/cam_custom_sub_mod_dev.c | 162 ++ .../cam_custom_hw1/cam_custom_sub_mod_dev.h | 15 + .../cam_custom_hw1/cam_custom_sub_mod_soc.c | 160 ++ .../cam_custom_hw1/cam_custom_sub_mod_soc.h | 35 + .../cam_custom_hw_mgr/cam_custom_hw_mgr.c | 1329 +++++++++++++++++ .../cam_custom_hw_mgr/cam_custom_hw_mgr.h | 180 +++ .../cam_custom_hw_mgr/include/cam_custom_hw.h | 57 + .../include/cam_custom_hw_mgr_intf.h | 104 ++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 4 +- drivers/cam_utils/cam_debug_util.c | 3 + drivers/cam_utils/cam_debug_util.h | 1 + 25 files changed, 4297 insertions(+), 1 deletion(-) create mode 100644 drivers/cam_cust/Makefile create mode 100644 drivers/cam_cust/cam_custom_context.c create mode 100644 drivers/cam_cust/cam_custom_context.h create mode 100644 drivers/cam_cust/cam_custom_dev.c create mode 100644 drivers/cam_cust/cam_custom_dev.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/Makefile create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/Makefile create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.c create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/Makefile create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.c create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.c create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw.h create mode 100644 drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw_mgr_intf.h diff --git a/drivers/Makefile b/drivers/Makefile index 9e0aee9f69e3..13edfb587419 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cust/ diff --git a/drivers/cam_cust/Makefile b/drivers/cam_cust/Makefile new file mode 100644 index 000000000000..732b9593c38b --- /dev/null +++ b/drivers/cam_cust/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_dev.o cam_custom_context.o diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c new file mode 100644 index 000000000000..5709530f7bf3 --- /dev/null +++ b/drivers/cam_cust/cam_custom_context.c @@ -0,0 +1,945 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "cam_mem_mgr.h" +#include "cam_sync_api.h" +#include "cam_req_mgr_dev.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" +#include "cam_context_utils.h" +#include "cam_custom_context.h" +#include "cam_common_util.h" + +static const char custom_dev_name[] = "custom hw"; + +static int __cam_custom_ctx_handle_irq_in_activated( + void *context, uint32_t evt_id, void *evt_data); + +static int __cam_custom_ctx_enqueue_request_in_order( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + struct cam_ctx_request *req_current; + struct cam_ctx_request *req_prev; + struct list_head temp_list; + + INIT_LIST_HEAD(&temp_list); + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + } else { + list_for_each_entry_safe_reverse( + req_current, req_prev, &ctx->pending_req_list, list) { + if (req->request_id < req_current->request_id) { + list_del_init(&req_current->list); + list_add(&req_current->list, &temp_list); + continue; + } else if (req->request_id == req_current->request_id) { + CAM_WARN(CAM_CUSTOM, + "Received duplicated request %lld", + req->request_id); + } + break; + } + list_add_tail(&req->list, &ctx->pending_req_list); + + if (!list_empty(&temp_list)) { + list_for_each_entry_safe( + req_current, req_prev, &temp_list, list) { + list_del_init(&req_current->list); + list_add_tail(&req_current->list, + &ctx->pending_req_list); + } + } + } + spin_unlock_bh(&ctx->lock); + return 0; +} + +static int __cam_custom_ctx_flush_req(struct cam_context *ctx, + struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req) +{ + int i, rc; + uint32_t cancel_req_id_found = 0; + struct cam_ctx_request *req; + struct cam_ctx_request *req_temp; + struct cam_custom_dev_ctx_req *req_custom; + struct list_head flush_list; + + INIT_LIST_HEAD(&flush_list); + if (list_empty(req_list)) { + CAM_DBG(CAM_CUSTOM, "request list is empty"); + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + CAM_ERR(CAM_CUSTOM, "no request to cancel"); + return -EINVAL; + } else { + return 0; + } + } + + CAM_DBG(CAM_CUSTOM, "Flush [%u] in progress for req_id %llu", + flush_req->type, flush_req->req_id); + list_for_each_entry_safe(req, req_temp, req_list, list) { + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + if (req->request_id != flush_req->req_id) { + continue; + } else { + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + cancel_req_id_found = 1; + break; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + } + + list_for_each_entry_safe(req, req_temp, &flush_list, list) { + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + for (i = 0; i < req_custom->num_fence_map_out; i++) { + if (req_custom->fence_map_out[i].sync_id != -1) { + CAM_DBG(CAM_CUSTOM, + "Flush req 0x%llx, fence %d", + req->request_id, + req_custom->fence_map_out[i].sync_id); + rc = cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc) + CAM_ERR_RATE_LIMIT(CAM_CUSTOM, + "signal fence failed\n"); + req_custom->fence_map_out[i].sync_id = -1; + } + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_CUSTOM, + "Flush request id:%lld is not found in the list", + flush_req->req_id); + + return 0; +} + +static int __cam_custom_ctx_flush_req_in_top_state( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + CAM_INFO(CAM_CUSTOM, "Last request id to flush is %lld", + flush_req->req_id); + ctx->last_flush_req = flush_req->req_id; + } + + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); + + return rc; +} + +static int __cam_custom_ctx_flush_req_in_ready( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + + CAM_DBG(CAM_CUSTOM, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + + /* if nothing is in pending req list, change state to acquire */ + if (list_empty(&ctx->pending_req_list)) + ctx->state = CAM_CTX_ACQUIRED; + spin_unlock_bh(&ctx->lock); + + CAM_DBG(CAM_CUSTOM, "Flush request in ready state. next state %d", + ctx->state); + return rc; +} + +static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->state = CAM_CTX_ACQUIRED; + + return 0; +} + +static int __cam_custom_stop_dev_core( + struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd) +{ + int rc = 0; + uint32_t i; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_hw_stop_args stop; + + if (ctx_custom->hw_ctx) { + stop.ctxt_to_hw_map = ctx_custom->hw_ctx; + + stop.args = NULL; + if (ctx->hw_mgr_intf->hw_stop) + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop); + } + + while (!list_empty(&ctx->pending_req_list)) { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + CAM_DBG(CAM_CUSTOM, + "signal fence in pending list. fence num %d", + req_custom->num_fence_map_out); + for (i = 0; i < req_custom->num_fence_map_out; i++) + if (req_custom->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + CAM_DBG(CAM_CUSTOM, "signal fence in wait list. fence num %d", + req_custom->num_fence_map_out); + for (i = 0; i < req_custom->num_fence_map_out; i++) + if (req_custom->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + CAM_DBG(CAM_CUSTOM, "signal fence in active list. fence num %d", + req_custom->num_fence_map_out); + for (i = 0; i < req_custom->num_fence_map_out; i++) + if (req_custom->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + ctx_custom->frame_id = 0; + ctx_custom->active_req_cnt = 0; + + CAM_DBG(CAM_CUSTOM, "Stop device success next state %d on ctx %u", + ctx->state, ctx->ctx_id); + + if (!stop_cmd) { + rc = __cam_custom_ctx_unlink_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unlink failed rc=%d", rc); + } + return rc; +} + +static int __cam_custom_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *)ctx->ctx_priv; + + __cam_custom_stop_dev_core(ctx, cmd); + ctx_custom->init_received = false; + ctx->state = CAM_CTX_ACQUIRED; + + return 0; +} + +static int __cam_custom_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_req_mgr_flush_request flush_req; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unable to release device"); + + ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; + ctx_custom->frame_id = 0; + ctx_custom->active_req_cnt = 0; + ctx_custom->init_received = false; + + if (!list_empty(&ctx->active_req_list)) + CAM_ERR(CAM_CUSTOM, "Active list is not empty"); + + /* Flush all the pending request list */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_CUSTOM, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, + &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_AVAILABLE; + + CAM_DBG(CAM_CUSTOM, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); + + return rc; +} + +static int __cam_custom_ctx_apply_req_in_activated_state( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_custom_context *custom_ctx = NULL; + struct cam_hw_config_args cfg; + + if (list_empty(&ctx->pending_req_list)) { + CAM_ERR(CAM_CUSTOM, "No available request for Apply id %lld", + apply->request_id); + rc = -EFAULT; + goto end; + } + + custom_ctx = (struct cam_custom_context *) ctx->ctx_priv; + spin_lock_bh(&ctx->lock); + req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + list); + spin_unlock_bh(&ctx->lock); + + /* + * Check whether the request id is matching the tip + */ + if (req->request_id != apply->request_id) { + CAM_ERR_RATE_LIMIT(CAM_CUSTOM, + "Invalid Request Id asking %llu existing %llu", + apply->request_id, req->request_id); + rc = -EFAULT; + goto end; + } + + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + + cfg.ctxt_to_hw_map = custom_ctx->hw_ctx; + cfg.request_id = req->request_id; + cfg.hw_update_entries = req_custom->cfg; + cfg.num_hw_update_entries = req_custom->num_cfg; + cfg.priv = &req_custom->hw_update_data; + cfg.init_packet = 0; + + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_CUSTOM, + "Can not apply the configuration"); + } else { + spin_lock_bh(&ctx->lock); + list_del_init(&req->list); + if (!req->num_out_map_entries) { + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + } else { + list_add_tail(&req->list, &ctx->active_req_list); + spin_unlock_bh(&ctx->lock); + /* + * for test purposes only-this should be + * triggered based on irq + */ + __cam_custom_ctx_handle_irq_in_activated(ctx, 0, NULL); + } + } + +end: + return rc; +} + +static int __cam_custom_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + struct cam_custom_context *custom_ctx; + + custom_ctx = (struct cam_custom_context *) ctx->ctx_priv; + + if (cmd->num_resources > CAM_CUSTOM_DEV_CTX_RES_MAX) { + CAM_ERR(CAM_CUSTOM, "Too much resources in the acquire"); + rc = -ENOMEM; + return rc; + } + + if (cmd->handle_type != 1) { + CAM_ERR(CAM_CUSTOM, "Only user pointer is supported"); + rc = -EINVAL; + return rc; + } + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_ACQUIRED; + custom_ctx->hw_ctx = ctx->ctxt_to_hw_map; + } + + CAM_DBG(CAM_CUSTOM, "Acquire done %d", ctx->ctx_id); + return rc; +} + +static int __cam_custom_ctx_enqueue_init_request( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + int rc = 0; + struct cam_ctx_request *req_old; + struct cam_custom_dev_ctx_req *req_custom_old; + struct cam_custom_dev_ctx_req *req_custom_new; + + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + goto end; + } + + req_old = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + req_custom_old = (struct cam_custom_dev_ctx_req *) req_old->req_priv; + req_custom_new = (struct cam_custom_dev_ctx_req *) req->req_priv; + if (req_custom_old->hw_update_data.packet_opcode_type == + CAM_CUSTOM_PACKET_INIT_DEV) { + if ((req_custom_old->num_cfg + req_custom_new->num_cfg) >= + CAM_CUSTOM_CTX_CFG_MAX) { + CAM_WARN(CAM_CUSTOM, "Can not merge INIT pkt"); + rc = -ENOMEM; + } + + if (req_custom_old->num_fence_map_out != 0 || + req_custom_old->num_fence_map_in != 0) { + CAM_WARN(CAM_CUSTOM, "Invalid INIT pkt sequence"); + rc = -EINVAL; + } + + if (!rc) { + memcpy(req_custom_old->fence_map_out, + req_custom_new->fence_map_out, + sizeof(req_custom_new->fence_map_out[0])* + req_custom_new->num_fence_map_out); + req_custom_old->num_fence_map_out = + req_custom_new->num_fence_map_out; + + memcpy(req_custom_old->fence_map_in, + req_custom_new->fence_map_in, + sizeof(req_custom_new->fence_map_in[0])* + req_custom_new->num_fence_map_in); + req_custom_old->num_fence_map_in = + req_custom_new->num_fence_map_in; + + memcpy(&req_custom_old->cfg[req_custom_old->num_cfg], + req_custom_new->cfg, + sizeof(req_custom_new->cfg[0])* + req_custom_new->num_cfg); + req_custom_old->num_cfg += req_custom_new->num_cfg; + + req_old->request_id = req->request_id; + + list_add_tail(&req->list, &ctx->free_req_list); + } + } else { + CAM_WARN(CAM_CUSTOM, + "Received Update pkt before INIT pkt. req_id= %lld", + req->request_id); + rc = -EINVAL; + } +end: + spin_unlock_bh(&ctx->lock); + return rc; +} + +static int __cam_custom_ctx_config_dev(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0, i; + struct cam_ctx_request *req = NULL; + struct cam_custom_dev_ctx_req *req_custom; + uintptr_t packet_addr; + struct cam_packet *packet; + size_t len = 0; + struct cam_hw_prepare_update_args cfg; + struct cam_req_mgr_add_request add_req; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + /* get free request */ + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->free_req_list)) { + req = list_first_entry(&ctx->free_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + } + spin_unlock_bh(&ctx->lock); + + if (!req) { + CAM_ERR(CAM_CUSTOM, "No more request obj free"); + return -ENOMEM; + } + + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + + /* for config dev, only memory handle is supported */ + /* map packet from the memhandle */ + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Can not get packet address"); + rc = -EINVAL; + goto free_req; + } + + packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset); + CAM_DBG(CAM_CUSTOM, "pack_handle %llx", cmd->packet_handle); + CAM_DBG(CAM_CUSTOM, "packet address is 0x%zx", packet_addr); + CAM_DBG(CAM_CUSTOM, "packet with length %zu, offset 0x%llx", + len, cmd->offset); + CAM_DBG(CAM_CUSTOM, "Packet request id %lld", + packet->header.request_id); + CAM_DBG(CAM_CUSTOM, "Packet size 0x%x", packet->header.size); + CAM_DBG(CAM_CUSTOM, "packet op %d", packet->header.op_code); + + if ((((packet->header.op_code) & 0xF) == + CAM_CUSTOM_PACKET_UPDATE_DEV) + && (packet->header.request_id <= ctx->last_flush_req)) { + CAM_DBG(CAM_CUSTOM, + "request %lld has been flushed, reject packet", + packet->header.request_id); + rc = -EINVAL; + goto free_req; + } + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.ctxt_to_hw_map = ctx_custom->hw_ctx; + cfg.out_map_entries = req_custom->fence_map_out; + cfg.in_map_entries = req_custom->fence_map_in; + cfg.priv = &req_custom->hw_update_data; + cfg.pf_data = &(req->pf_data); + + rc = ctx->hw_mgr_intf->hw_prepare_update( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Prepare config packet failed in HW layer"); + rc = -EFAULT; + goto free_req; + } + + req_custom->num_cfg = cfg.num_hw_update_entries; + req_custom->num_fence_map_out = cfg.num_out_map_entries; + req_custom->num_fence_map_in = cfg.num_in_map_entries; + req_custom->num_acked = 0; + + for (i = 0; i < req_custom->num_fence_map_out; i++) { + rc = cam_sync_get_obj_ref(req_custom->fence_map_out[i].sync_id); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Can't get ref for fence %d", + req_custom->fence_map_out[i].sync_id); + goto put_ref; + } + } + + CAM_DBG(CAM_CUSTOM, + "num_entry: %d, num fence out: %d, num fence in: %d", + req_custom->num_cfg, req_custom->num_fence_map_out, + req_custom->num_fence_map_in); + + req->request_id = packet->header.request_id; + req->status = 1; + + CAM_DBG(CAM_CUSTOM, "Packet request id %lld packet opcode:%d", + packet->header.request_id, + req_custom->hw_update_data.packet_opcode_type); + + if (req_custom->hw_update_data.packet_opcode_type == + CAM_CUSTOM_PACKET_INIT_DEV) { + if (ctx->state < CAM_CTX_ACTIVATED) { + rc = __cam_custom_ctx_enqueue_init_request(ctx, req); + if (rc) + CAM_ERR(CAM_CUSTOM, "Enqueue INIT pkt failed"); + ctx_custom->init_received = true; + } else { + rc = -EINVAL; + CAM_ERR(CAM_CUSTOM, "Recevied INIT pkt in wrong state"); + } + } else { + if (ctx->state >= CAM_CTX_READY && ctx->ctx_crm_intf->add_req) { + add_req.link_hdl = ctx->link_hdl; + add_req.dev_hdl = ctx->dev_hdl; + add_req.req_id = req->request_id; + add_req.skip_before_applying = 0; + rc = ctx->ctx_crm_intf->add_req(&add_req); + if (rc) { + CAM_ERR(CAM_CUSTOM, + "Add req failed: req id=%llu", + req->request_id); + } else { + __cam_custom_ctx_enqueue_request_in_order( + ctx, req); + } + } else { + rc = -EINVAL; + CAM_ERR(CAM_CUSTOM, "Recevied Update in wrong state"); + } + } + + if (rc) + goto put_ref; + + CAM_DBG(CAM_CUSTOM, + "Preprocessing Config req_id %lld successful on ctx %u", + req->request_id, ctx->ctx_id); + + return rc; + +put_ref: + for (--i; i >= 0; i--) { + if (cam_sync_put_obj_ref(req_custom->fence_map_out[i].sync_id)) + CAM_ERR(CAM_CUSTOM, "Failed to put ref of fence %d", + req_custom->fence_map_out[i].sync_id); + } +free_req: + spin_lock_bh(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + + return rc; + +} + +static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + + rc = __cam_custom_ctx_config_dev(ctx, cmd); + + if (!rc && (ctx->link_hdl >= 0)) + ctx->state = CAM_CTX_READY; + + return rc; +} + +static int __cam_custom_ctx_link_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + ctx->link_hdl = link->link_hdl; + ctx->ctx_crm_intf = link->crm_cb; + ctx_custom->subscribe_event = link->subscribe_event; + + /* change state only if we had the init config */ + if (ctx_custom->init_received) + ctx->state = CAM_CTX_READY; + + CAM_DBG(CAM_CUSTOM, "next state %d", ctx->state); + + return 0; +} + +static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + + return 0; +} + +static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_device_info *dev_info) +{ + dev_info->dev_hdl = ctx->dev_hdl; + strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name)); + dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW; + dev_info->p_delay = 1; + dev_info->trigger = CAM_TRIGGER_POINT_SOF; + + return 0; +} + +static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_config_args hw_config; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + if (cmd->session_handle != ctx->session_hdl || + cmd->dev_handle != ctx->dev_hdl) { + rc = -EPERM; + goto end; + } + + if (list_empty(&ctx->pending_req_list)) { + /* should never happen */ + CAM_ERR(CAM_CUSTOM, "Start device with empty configuration"); + rc = -EFAULT; + goto end; + } else { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + } + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + + if (!ctx_custom->hw_ctx) { + CAM_ERR(CAM_CUSTOM, "Wrong hw context pointer."); + rc = -EFAULT; + goto end; + } + + hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx; + hw_config.request_id = req->request_id; + hw_config.hw_update_entries = req_custom->cfg; + hw_config.num_hw_update_entries = req_custom->num_cfg; + hw_config.priv = &req_custom->hw_update_data; + hw_config.init_packet = 1; + + ctx->state = CAM_CTX_ACTIVATED; + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_config); + if (rc) { + /* HW failure. User need to clean up the resource */ + CAM_ERR(CAM_CUSTOM, "Start HW failed"); + ctx->state = CAM_CTX_READY; + goto end; + } + + CAM_DBG(CAM_CUSTOM, "start device success ctx %u", + ctx->ctx_id); + + spin_lock_bh(&ctx->lock); + list_del_init(&req->list); + if (req_custom->num_fence_map_out) + list_add_tail(&req->list, &ctx->active_req_list); + else + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + +end: + return rc; +} + +static int __cam_custom_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + rc = __cam_custom_stop_dev_core(ctx, NULL); + if (rc) + CAM_ERR(CAM_CUSTOM, "Stop device failed rc=%d", rc); + + rc = __cam_custom_release_dev_in_acquired(ctx, cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Release device failed rc=%d", rc); + + return rc; +} + +static int __cam_custom_ctx_unlink_in_activated(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + CAM_WARN(CAM_CUSTOM, + "Received unlink in activated state. It's unexpected"); + + rc = __cam_custom_stop_dev_in_activated(ctx, NULL); + if (rc) + CAM_WARN(CAM_CUSTOM, "Stop device failed rc=%d", rc); + + rc = __cam_custom_ctx_unlink_in_ready(ctx, unlink); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unlink failed rc=%d", rc); + + return rc; +} + +static int __cam_custom_ctx_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *link_evt_data) +{ + switch (link_evt_data->evt_type) { + case CAM_REQ_MGR_LINK_EVT_ERR: + /* Handle error/bubble related issues */ + break; + default: + CAM_WARN(CAM_CUSTOM, "Unknown event from CRM"); + break; + } + + return 0; +} + +static int __cam_custom_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc; + struct cam_context *ctx = + (struct cam_context *)context; + + CAM_DBG(CAM_CUSTOM, "Enter %d", ctx->ctx_id); + + /* + * handle based on different irq's currently + * triggering only buf done if there are fences + */ + rc = cam_context_buf_done_from_hw(ctx, evt_data, 0); + if (rc) + CAM_ERR(CAM_CUSTOM, "Failed in buf done, rc=%d", rc); + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = + __cam_custom_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_custom_release_dev_in_acquired, + .config_dev = __cam_custom_ctx_config_dev_in_acquired, + }, + .crm_ops = { + .link = __cam_custom_ctx_link_in_acquired, + .unlink = __cam_custom_ctx_unlink_in_acquired, + .get_dev_info = + __cam_custom_ctx_get_dev_info_in_acquired, + .flush_req = __cam_custom_ctx_flush_req_in_top_state, + }, + .irq_ops = NULL, + .pagefault_ops = NULL, + }, + /* Ready */ + { + .ioctl_ops = { + .start_dev = __cam_custom_ctx_start_dev_in_ready, + .release_dev = __cam_custom_release_dev_in_acquired, + .config_dev = __cam_custom_ctx_config_dev, + }, + .crm_ops = { + .unlink = __cam_custom_ctx_unlink_in_ready, + .flush_req = __cam_custom_ctx_flush_req_in_ready, + }, + .irq_ops = NULL, + .pagefault_ops = NULL, + }, + /* Activated */ + { + .ioctl_ops = { + .stop_dev = __cam_custom_stop_dev_in_activated, + .release_dev = + __cam_custom_ctx_release_dev_in_activated, + .config_dev = __cam_custom_ctx_config_dev, + }, + .crm_ops = { + .unlink = __cam_custom_ctx_unlink_in_activated, + .apply_req = + __cam_custom_ctx_apply_req_in_activated_state, + .flush_req = __cam_custom_ctx_flush_req_in_top_state, + .process_evt = __cam_custom_ctx_process_evt, + }, + .irq_ops = __cam_custom_ctx_handle_irq_in_activated, + .pagefault_ops = NULL, + }, +}; + +int cam_custom_dev_context_init(struct cam_custom_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) +{ + int rc = -1, i = 0; + + if (!ctx || !ctx_base) { + CAM_ERR(CAM_CUSTOM, "Invalid Context"); + return -EINVAL; + } + + /* Custom HW context setup */ + memset(ctx, 0, sizeof(*ctx)); + + ctx->base = ctx_base; + ctx->frame_id = 0; + ctx->active_req_cnt = 0; + ctx->hw_ctx = NULL; + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + ctx->req_base[i].req_priv = &ctx->req_custom[i]; + ctx->req_custom[i].base = &ctx->req_base[i]; + } + + /* camera context setup */ + rc = cam_context_init(ctx_base, custom_dev_name, CAM_CUSTOM, ctx_id, + crm_node_intf, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Camera Context Base init failed"); + return rc; + } + + /* link camera context with custom HW context */ + ctx_base->state_machine = cam_custom_dev_ctx_top_state_machine; + ctx_base->ctx_priv = ctx; + + return rc; +} + +int cam_custom_dev_context_deinit(struct cam_custom_context *ctx) +{ + if (ctx->base) + cam_context_deinit(ctx->base); + + memset(ctx, 0, sizeof(*ctx)); + return 0; +} diff --git a/drivers/cam_cust/cam_custom_context.h b/drivers/cam_cust/cam_custom_context.h new file mode 100644 index 000000000000..91acf1e5ee80 --- /dev/null +++ b/drivers/cam_cust/cam_custom_context.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_CONTEXT_H_ +#define _CAM_CUSTOM_CONTEXT_H_ + +#include +#include +#include + +#include "cam_context.h" +#include "cam_custom_hw_mgr_intf.h" + +/* + * Maximum hw resource - This number is based on the maximum + * output port resource. The current maximum resource number + * is 2. + */ +#define CAM_CUSTOM_DEV_CTX_RES_MAX 2 + +#define CAM_CUSTOM_CTX_CFG_MAX 8 + +/* forward declaration */ +struct cam_custom_context; + +/** + * struct cam_custom_dev_ctx_req - Custom context request object + * + * @base: Common request object pointer + * @cfg: Custom hardware configuration array + * @num_cfg: Number of custom hardware configuration entries + * @fence_map_out: Output fence mapping array + * @num_fence_map_out: Number of the output fence map + * @fence_map_in: Input fence mapping array + * @num_fence_map_in: Number of input fence map + * @num_acked: Count to track acked entried for output. + * If count equals the number of fence out, it means + * the request has been completed. + * @hw_update_data: HW update data for this request + * + */ +struct cam_custom_dev_ctx_req { + struct cam_ctx_request *base; + struct cam_hw_update_entry cfg + [CAM_CUSTOM_CTX_CFG_MAX]; + uint32_t num_cfg; + struct cam_hw_fence_map_entry fence_map_out + [CAM_CUSTOM_DEV_CTX_RES_MAX]; + uint32_t num_fence_map_out; + struct cam_hw_fence_map_entry fence_map_in + [CAM_CUSTOM_DEV_CTX_RES_MAX]; + uint32_t num_fence_map_in; + uint32_t num_acked; + struct cam_custom_prepare_hw_update_data hw_update_data; +}; + +/** + * struct cam_custom_context - Custom device context + * @base: custom device context object + * @state_machine: state machine for Custom device context + * @state: Common context state + * @hw_ctx: HW object returned by the acquire device command + * @init_received: Indicate whether init config packet is received + * @subscribe_event: The irq event mask that CRM subscribes to, + * custom HW will invoke CRM cb at those event. + * @active_req_cnt: Counter for the active request + * @frame_id: Frame id tracking for the custom context + * @req_base: common request structure + * @req_custom: custom request structure + * + */ +struct cam_custom_context { + struct cam_context *base; + struct cam_ctx_ops *state_machine; + uint32_t state; + void *hw_ctx; + bool init_received; + uint32_t subscribe_event; + uint32_t active_req_cnt; + int64_t frame_id; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + struct cam_custom_dev_ctx_req req_custom[CAM_CTX_REQ_MAX]; +}; + + +/** + * cam_custom_dev_context_init() + * + * @brief: Initialization function for the custom context + * + * @ctx: Custom context obj to be initialized + * @bridge_ops: Bridge call back funciton + * @hw_intf: Cust hw manager interface + * @ctx_id: ID for this context + * + */ +int cam_custom_dev_context_init(struct cam_custom_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *bridge_ops, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); + +/** + * cam_custom_dev_context_deinit() + * + * @brief: Deinitialize function for the Custom context + * + * @ctx: Custom context obj to be deinitialized + * + */ +int cam_custom_dev_context_deinit(struct cam_custom_context *ctx); + +#endif /* _CAM_CUSTOM_CONTEXT_H_ */ diff --git a/drivers/cam_cust/cam_custom_dev.c b/drivers/cam_cust/cam_custom_dev.c new file mode 100644 index 000000000000..76d4a7d0e17b --- /dev/null +++ b/drivers/cam_cust/cam_custom_dev.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "cam_custom_dev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_custom_hw_mgr_intf.h" +#include "cam_node.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +static struct cam_custom_dev g_custom_dev; + +static void cam_custom_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_CUSTOM, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static const struct of_device_id cam_custom_dt_match[] = { + { + .compatible = "qcom,cam-custom" + }, + {} +}; + +static int cam_custom_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + mutex_lock(&g_custom_dev.custom_dev_mutex); + g_custom_dev.open_cnt++; + mutex_unlock(&g_custom_dev.custom_dev_mutex); + + return 0; +} + +static int cam_custom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_node *node = v4l2_get_subdevdata(sd); + + mutex_lock(&g_custom_dev.custom_dev_mutex); + if (g_custom_dev.open_cnt <= 0) { + CAM_DBG(CAM_CUSTOM, "Custom subdev is already closed"); + rc = -EINVAL; + goto end; + } + + g_custom_dev.open_cnt--; + if (!node) { + CAM_ERR(CAM_CUSTOM, "Node ptr is NULL"); + rc = -EINVAL; + goto end; + } + + if (g_custom_dev.open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&g_custom_dev.custom_dev_mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_custom_subdev_internal_ops = { + .close = cam_custom_subdev_close, + .open = cam_custom_subdev_open, +}; + +static int cam_custom_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + int i; + + /* clean up resources */ + for (i = 0; i < CAM_CUSTOM_HW_MAX_INSTANCES; i++) { + rc = cam_custom_dev_context_deinit(&g_custom_dev.ctx_custom[i]); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Custom context %d deinit failed", i); + } + + rc = cam_subdev_remove(&g_custom_dev.sd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unregister failed"); + + memset(&g_custom_dev, 0, sizeof(g_custom_dev)); + return 0; +} + +static int cam_custom_dev_probe(struct platform_device *pdev) +{ + int rc = -EINVAL; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + int iommu_hdl = -1; + + g_custom_dev.sd.internal_ops = &cam_custom_subdev_internal_ops; + + rc = cam_subdev_probe(&g_custom_dev.sd, pdev, CAM_CUSTOM_DEV_NAME, + CAM_CUSTOM_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom device cam_subdev_probe failed!"); + goto err; + } + node = (struct cam_node *) g_custom_dev.sd.token; + + memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf)); + rc = cam_custom_hw_mgr_init(pdev->dev.of_node, + &hw_mgr_intf, &iommu_hdl); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Can not initialized Custom HW manager!"); + goto unregister; + } + + for (i = 0; i < CAM_CUSTOM_HW_MAX_INSTANCES; i++) { + rc = cam_custom_dev_context_init(&g_custom_dev.ctx_custom[i], + &g_custom_dev.ctx[i], + &node->crm_node_intf, + &node->hw_mgr_intf, + i); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom context init failed!"); + goto unregister; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_custom_dev.ctx, + CAM_CUSTOM_HW_MAX_INSTANCES, CAM_CUSTOM_DEV_NAME); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom HW node init failed!"); + goto unregister; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_custom_dev_iommu_fault_handler, node); + + mutex_init(&g_custom_dev.custom_dev_mutex); + + CAM_DBG(CAM_CUSTOM, "Camera custom HW probe complete"); + + return 0; +unregister: + rc = cam_subdev_remove(&g_custom_dev.sd); +err: + return rc; +} + + +static struct platform_driver custom_driver = { + .probe = cam_custom_dev_probe, + .remove = cam_custom_dev_remove, + .driver = { + .name = "cam_custom", + .of_match_table = cam_custom_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_custom_dev_init_module(void) +{ + return platform_driver_register(&custom_driver); +} + +static void __exit cam_custom_dev_exit_module(void) +{ + platform_driver_unregister(&custom_driver); +} + +module_init(cam_custom_dev_init_module); +module_exit(cam_custom_dev_exit_module); +MODULE_DESCRIPTION("MSM CUSTOM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_cust/cam_custom_dev.h b/drivers/cam_cust/cam_custom_dev.h new file mode 100644 index 000000000000..77ea6badfe94 --- /dev/null +++ b/drivers/cam_cust/cam_custom_dev.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_DEV_H_ +#define _CAM_CUSTOM_DEV_H_ + +#include "cam_subdev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_custom_hw_mgr.h" +#include "cam_context.h" +#include "cam_custom_context.h" + +#define CAM_CUSTOM_HW_MAX_INSTANCES 3 + +/** + * struct cam_custom_dev - Camera Custom V4l2 device node + * + * @sd: Common camera subdevice node + * @ctx: Custom base context storage + * @ctx_custom: Custom private context storage + * @custom_dev_mutex: Custom dev mutex + * @open_cnt: Open device count + */ +struct cam_custom_dev { + struct cam_subdev sd; + struct cam_context ctx[CAM_CUSTOM_HW_MAX_INSTANCES]; + struct cam_custom_context ctx_custom[CAM_CUSTOM_HW_MAX_INSTANCES]; + struct mutex custom_dev_mutex; + int32_t open_cnt; +}; + +#endif /* _CAM_CUSTOM_DEV_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/Makefile b/drivers/cam_cust/cam_custom_hw_mgr/Makefile new file mode 100644 index 000000000000..1e0917637b8e --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw1/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw1/ cam_custom_csid/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw_mgr.o + diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/Makefile b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/Makefile new file mode 100644 index 000000000000..ab36c8862888 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_csid_dev.o diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h new file mode 100644 index 000000000000..a55bb002ffc2 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h @@ -0,0 +1,272 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_CSID_480_H_ +#define _CAM_CUSTOM_CSID_480_H_ + +#include "cam_ife_csid_core.h" + +#define CAM_CSID_VERSION_V480 0x40080000 + +static struct cam_ife_csid_udi_reg_offset + cam_custom_csid_480_udi_0_reg_offset = { + .csid_udi_irq_status_addr = 0x30, + .csid_udi_irq_mask_addr = 0x34, + .csid_udi_irq_clear_addr = 0x38, + .csid_udi_irq_set_addr = 0x3c, + .csid_udi_cfg0_addr = 0x200, + .csid_udi_cfg1_addr = 0x204, + .csid_udi_ctrl_addr = 0x208, + .csid_udi_frm_drop_pattern_addr = 0x20c, + .csid_udi_frm_drop_period_addr = 0x210, + .csid_udi_irq_subsample_pattern_addr = 0x214, + .csid_udi_irq_subsample_period_addr = 0x218, + .csid_udi_rpp_hcrop_addr = 0x21c, + .csid_udi_rpp_vcrop_addr = 0x220, + .csid_udi_rpp_pix_drop_pattern_addr = 0x224, + .csid_udi_rpp_pix_drop_period_addr = 0x228, + .csid_udi_rpp_line_drop_pattern_addr = 0x22c, + .csid_udi_rpp_line_drop_period_addr = 0x230, + .csid_udi_rst_strobes_addr = 0x240, + .csid_udi_status_addr = 0x250, + .csid_udi_misr_val0_addr = 0x254, + .csid_udi_misr_val1_addr = 0x258, + .csid_udi_misr_val2_addr = 0x25c, + .csid_udi_misr_val3_addr = 0x260, + .csid_udi_format_measure_cfg0_addr = 0x270, + .csid_udi_format_measure_cfg1_addr = 0x274, + .csid_udi_format_measure0_addr = 0x278, + .csid_udi_format_measure1_addr = 0x27c, + .csid_udi_format_measure2_addr = 0x280, + .csid_udi_timestamp_curr0_sof_addr = 0x290, + .csid_udi_timestamp_curr1_sof_addr = 0x294, + .csid_udi_timestamp_prev0_sof_addr = 0x298, + .csid_udi_timestamp_prev1_sof_addr = 0x29c, + .csid_udi_timestamp_curr0_eof_addr = 0x2a0, + .csid_udi_timestamp_curr1_eof_addr = 0x2a4, + .csid_udi_timestamp_prev0_eof_addr = 0x2a8, + .csid_udi_timestamp_prev1_eof_addr = 0x2ac, + .csid_udi_err_recovery_cfg0_addr = 0x2b0, + .csid_udi_err_recovery_cfg1_addr = 0x2b4, + .csid_udi_err_recovery_cfg2_addr = 0x2b8, + .csid_udi_multi_vcdt_cfg0_addr = 0x2bc, + .csid_udi_byte_cntr_ping_addr = 0x2e0, + .csid_udi_byte_cntr_pong_addr = 0x2e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_udi_reg_offset + cam_custom_csid_480_udi_1_reg_offset = { + .csid_udi_irq_status_addr = 0x40, + .csid_udi_irq_mask_addr = 0x44, + .csid_udi_irq_clear_addr = 0x48, + .csid_udi_irq_set_addr = 0x4c, + .csid_udi_cfg0_addr = 0x300, + .csid_udi_cfg1_addr = 0x304, + .csid_udi_ctrl_addr = 0x308, + .csid_udi_frm_drop_pattern_addr = 0x30c, + .csid_udi_frm_drop_period_addr = 0x310, + .csid_udi_irq_subsample_pattern_addr = 0x314, + .csid_udi_irq_subsample_period_addr = 0x318, + .csid_udi_rpp_hcrop_addr = 0x31c, + .csid_udi_rpp_vcrop_addr = 0x320, + .csid_udi_rpp_pix_drop_pattern_addr = 0x324, + .csid_udi_rpp_pix_drop_period_addr = 0x328, + .csid_udi_rpp_line_drop_pattern_addr = 0x32c, + .csid_udi_rpp_line_drop_period_addr = 0x330, + .csid_udi_rst_strobes_addr = 0x340, + .csid_udi_status_addr = 0x350, + .csid_udi_misr_val0_addr = 0x354, + .csid_udi_misr_val1_addr = 0x358, + .csid_udi_misr_val2_addr = 0x35c, + .csid_udi_misr_val3_addr = 0x360, + .csid_udi_format_measure_cfg0_addr = 0x370, + .csid_udi_format_measure_cfg1_addr = 0x374, + .csid_udi_format_measure0_addr = 0x378, + .csid_udi_format_measure1_addr = 0x37c, + .csid_udi_format_measure2_addr = 0x380, + .csid_udi_timestamp_curr0_sof_addr = 0x390, + .csid_udi_timestamp_curr1_sof_addr = 0x394, + .csid_udi_timestamp_prev0_sof_addr = 0x398, + .csid_udi_timestamp_prev1_sof_addr = 0x39c, + .csid_udi_timestamp_curr0_eof_addr = 0x3a0, + .csid_udi_timestamp_curr1_eof_addr = 0x3a4, + .csid_udi_timestamp_prev0_eof_addr = 0x3a8, + .csid_udi_timestamp_prev1_eof_addr = 0x3ac, + .csid_udi_err_recovery_cfg0_addr = 0x3b0, + .csid_udi_err_recovery_cfg1_addr = 0x3b4, + .csid_udi_err_recovery_cfg2_addr = 0x3b8, + .csid_udi_multi_vcdt_cfg0_addr = 0x3bc, + .csid_udi_byte_cntr_ping_addr = 0x3e0, + .csid_udi_byte_cntr_pong_addr = 0x3e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_udi_reg_offset + cam_custom_csid_480_udi_2_reg_offset = { + .csid_udi_irq_status_addr = 0x50, + .csid_udi_irq_mask_addr = 0x54, + .csid_udi_irq_clear_addr = 0x58, + .csid_udi_irq_set_addr = 0x5c, + .csid_udi_cfg0_addr = 0x400, + .csid_udi_cfg1_addr = 0x404, + .csid_udi_ctrl_addr = 0x408, + .csid_udi_frm_drop_pattern_addr = 0x40c, + .csid_udi_frm_drop_period_addr = 0x410, + .csid_udi_irq_subsample_pattern_addr = 0x414, + .csid_udi_irq_subsample_period_addr = 0x418, + .csid_udi_rpp_hcrop_addr = 0x41c, + .csid_udi_rpp_vcrop_addr = 0x420, + .csid_udi_rpp_pix_drop_pattern_addr = 0x424, + .csid_udi_rpp_pix_drop_period_addr = 0x428, + .csid_udi_rpp_line_drop_pattern_addr = 0x42c, + .csid_udi_rpp_line_drop_period_addr = 0x430, + .csid_udi_yuv_chroma_conversion_addr = 0x434, + .csid_udi_rst_strobes_addr = 0x440, + .csid_udi_status_addr = 0x450, + .csid_udi_misr_val0_addr = 0x454, + .csid_udi_misr_val1_addr = 0x458, + .csid_udi_misr_val2_addr = 0x45c, + .csid_udi_misr_val3_addr = 0x460, + .csid_udi_format_measure_cfg0_addr = 0x470, + .csid_udi_format_measure_cfg1_addr = 0x474, + .csid_udi_format_measure0_addr = 0x478, + .csid_udi_format_measure1_addr = 0x47c, + .csid_udi_format_measure2_addr = 0x480, + .csid_udi_timestamp_curr0_sof_addr = 0x490, + .csid_udi_timestamp_curr1_sof_addr = 0x494, + .csid_udi_timestamp_prev0_sof_addr = 0x498, + .csid_udi_timestamp_prev1_sof_addr = 0x49c, + .csid_udi_timestamp_curr0_eof_addr = 0x4a0, + .csid_udi_timestamp_curr1_eof_addr = 0x4a4, + .csid_udi_timestamp_prev0_eof_addr = 0x4a8, + .csid_udi_timestamp_prev1_eof_addr = 0x4ac, + .csid_udi_err_recovery_cfg0_addr = 0x4b0, + .csid_udi_err_recovery_cfg1_addr = 0x4b4, + .csid_udi_err_recovery_cfg2_addr = 0x4b8, + .csid_udi_multi_vcdt_cfg0_addr = 0x4bc, + .csid_udi_byte_cntr_ping_addr = 0x4e0, + .csid_udi_byte_cntr_pong_addr = 0x4e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_custom_csid_480_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_common_reg_offset + cam_custom_csid_480_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_udis = 3, + .num_rdis = 0, + .num_pix = 0, + .num_ppp = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0, + .rdi_irq_mask_all = 0, + .ppp_irq_mask_all = 0, + .udi_irq_mask_all = 0x7FFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, + .num_bytes_out_shift_val = 3, +}; + +static struct cam_ife_csid_reg_offset cam_custom_csid_480_reg_offset = { + .cmn_reg = &cam_custom_csid_480_cmn_reg_offset, + .csi2_reg = &cam_custom_csid_480_csi2_reg_offset, + .ipp_reg = NULL, + .ppp_reg = NULL, + .rdi_reg = { + NULL, + NULL, + NULL, + NULL, + }, + .udi_reg = { + &cam_custom_csid_480_udi_0_reg_offset, + &cam_custom_csid_480_udi_1_reg_offset, + &cam_custom_csid_480_udi_2_reg_offset, + }, + .tpg_reg = NULL, +}; + +#endif /*_CAM_IFE_CSID_480_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.c new file mode 100644 index 000000000000..be472372aeb0 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "linux/module.h" +#include "cam_custom_csid_dev.h" +#include "cam_ife_csid_core.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_custom_csid480.h" +#include "cam_debug_util.h" + +#define CAM_CUSTOM_CSID_DRV_NAME "custom_csid" + +static struct cam_hw_intf *cam_custom_csid_hw_list[CAM_IFE_CSID_HW_NUM_MAX] = { + 0, 0, 0, 0}; + +static char csid_dev_name[16]; + +static struct cam_ife_csid_hw_info cam_custom_csid480_hw_info = { + .csid_reg = &cam_custom_csid_480_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V480, +}; + +static int cam_custom_csid_probe(struct platform_device *pdev) +{ + + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + struct cam_ife_csid_hw *csid_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_ife_csid_hw_info *csid_hw_data = NULL; + uint32_t csid_dev_idx; + int rc = 0; + + csid_hw_intf = kzalloc(sizeof(*csid_hw_intf), GFP_KERNEL); + if (!csid_hw_intf) { + rc = -ENOMEM; + goto err; + } + + csid_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!csid_hw_info) { + rc = -ENOMEM; + goto free_hw_intf; + } + + csid_dev = kzalloc(sizeof(struct cam_ife_csid_hw), GFP_KERNEL); + if (!csid_dev) { + rc = -ENOMEM; + goto free_hw_info; + } + + /* get custom csid hw index */ + of_property_read_u32(pdev->dev.of_node, "cell-index", &csid_dev_idx); + /* get custom csid hw information */ + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_CUSTOM, + "No matching table for the CUSTOM CSID HW!"); + rc = -EINVAL; + goto free_dev; + } + + memset(csid_dev_name, 0, sizeof(csid_dev_name)); + snprintf(csid_dev_name, sizeof(csid_dev_name), + "csid-custom%1u", csid_dev_idx); + + csid_hw_intf->hw_idx = csid_dev_idx; + csid_hw_intf->hw_type = CAM_ISP_HW_TYPE_IFE_CSID; + csid_hw_intf->hw_priv = csid_hw_info; + + csid_hw_info->core_info = csid_dev; + csid_hw_info->soc_info.pdev = pdev; + csid_hw_info->soc_info.dev = &pdev->dev; + csid_hw_info->soc_info.dev_name = csid_dev_name; + csid_hw_info->soc_info.index = csid_dev_idx; + + csid_hw_data = (struct cam_ife_csid_hw_info *)match_dev->data; + csid_dev->csid_info = csid_hw_data; + + rc = cam_ife_csid_hw_probe_init(csid_hw_intf, csid_dev_idx, true); + if (rc) + goto free_dev; + + platform_set_drvdata(pdev, csid_dev); + CAM_DBG(CAM_CUSTOM, "CSID:%d probe successful for dev %s", + csid_hw_intf->hw_idx, csid_dev_name); + + if (csid_hw_intf->hw_idx < CAM_IFE_CSID_HW_NUM_MAX) + cam_custom_csid_hw_list[csid_hw_intf->hw_idx] = csid_hw_intf; + else + goto free_dev; + + return 0; + +free_dev: + kfree(csid_dev); +free_hw_info: + kfree(csid_hw_info); +free_hw_intf: + kfree(csid_hw_intf); +err: + return rc; +} + +static int cam_custom_csid_remove(struct platform_device *pdev) +{ + struct cam_ife_csid_hw *csid_dev = NULL; + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + + csid_dev = (struct cam_ife_csid_hw *)platform_get_drvdata(pdev); + csid_hw_intf = csid_dev->hw_intf; + csid_hw_info = csid_dev->hw_info; + + CAM_DBG(CAM_CUSTOM, "CSID:%d remove", + csid_dev->hw_intf->hw_idx); + + cam_ife_csid_hw_deinit(csid_dev); + + /*release the csid device memory */ + kfree(csid_dev); + kfree(csid_hw_info); + kfree(csid_hw_intf); + return 0; +} + +static const struct of_device_id cam_custom_csid_dt_match[] = { + { + .compatible = "qcom,csid-custom480", + .data = &cam_custom_csid480_hw_info + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_custom_csid_dt_match); + +static struct platform_driver cam_custom_csid_driver = { + .probe = cam_custom_csid_probe, + .driver = { + .name = "qcom,custom-csid", + .of_match_table = cam_custom_csid_dt_match, + .suppress_bind_attrs = true, + }, + .remove = cam_custom_csid_remove, +}; + +static int __init cam_custom_csid_driver_init(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_custom_csid_driver); + if (rc < 0) + CAM_ERR(CAM_CUSTOM, "platform_driver_register Failed: rc = %d", + rc); + + return rc; +} + +int cam_custom_csid_hw_init(struct cam_hw_intf **custom_csid_hw, + uint32_t hw_idx) +{ + int rc = 0; + + if (cam_custom_csid_hw_list[hw_idx]) { + *custom_csid_hw = cam_custom_csid_hw_list[hw_idx]; + } else { + *custom_csid_hw = NULL; + rc = -1; + } + + return rc; +} + +static void __exit cam_custom_csid_driver_exit(void) +{ + platform_driver_unregister(&cam_custom_csid_driver); +} + +module_init(cam_custom_csid_driver_init); +module_exit(cam_custom_csid_driver_exit); +MODULE_DESCRIPTION("cam_custom_csid_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.h new file mode 100644 index 000000000000..f0c086ccab18 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_DEV_H_ +#define _CAM_IFE_CSID_DEV_H_ + +#include "cam_debug_util.h" +#include "cam_custom_hw_mgr_intf.h" + +#endif /*_CAM_IFE_CSID_DEV_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/Makefile b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/Makefile new file mode 100644 index 000000000000..4895219ffd06 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1 + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_sub_mod_soc.o cam_custom_sub_mod_dev.o cam_custom_sub_mod_core.o diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.c new file mode 100644 index 000000000000..9ac5da25571e --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "cam_custom_sub_mod_core.h" + +int cam_custom_hw_sub_mod_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + /* Add HW Capabilities to be published */ + return rc; +} + +int cam_custom_hw_sub_mod_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_resource_node *custom_res = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + custom_hw->open_count++; + if (custom_hw->open_count > 1) { + mutex_unlock(&custom_hw->hw_mutex); + CAM_DBG(CAM_CUSTOM, + "Cam Custom has already been initialized cnt %d", + custom_hw->open_count); + return 0; + } + mutex_unlock(&custom_hw->hw_mutex); + + soc_info = &custom_hw->soc_info; + + /* Turn ON Regulators, Clocks and other SOC resources */ + rc = cam_custom_hw_sub_mod_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Enable SOC failed"); + rc = -EFAULT; + goto decrement_open_cnt; + } + + custom_res = (struct cam_custom_resource_node *)init_hw_args; + if (custom_res && custom_res->init) { + rc = custom_res->init(custom_res, NULL, 0); + if (rc) { + CAM_ERR(CAM_CUSTOM, "init Failed rc=%d", rc); + goto decrement_open_cnt; + } + } + + rc = cam_custom_hw_sub_mod_reset(hw_priv, NULL, 0); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, "Custom HW reset failed : %d", rc); + goto decrement_open_cnt; + } + /* Initialize all resources here */ + custom_hw->hw_state = CAM_HW_STATE_POWER_UP; + return rc; + +decrement_open_cnt: + mutex_lock(&custom_hw->hw_mutex); + custom_hw->open_count--; + mutex_unlock(&custom_hw->hw_mutex); + return rc; +} + +int cam_custom_hw_sub_mod_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_resource_node *custom_res = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + if (!custom_hw->open_count) { + mutex_unlock(&custom_hw->hw_mutex); + CAM_ERR(CAM_CUSTOM, "Error! Unbalanced deinit"); + return -EFAULT; + } + custom_hw->open_count--; + if (custom_hw->open_count) { + mutex_unlock(&custom_hw->hw_mutex); + CAM_DBG(CAM_CUSTOM, + "open_cnt non-zero =%d", custom_hw->open_count); + return 0; + } + mutex_unlock(&custom_hw->hw_mutex); + + soc_info = &custom_hw->soc_info; + + custom_res = (struct cam_custom_resource_node *)deinit_hw_args; + if (custom_res && custom_res->deinit) { + rc = custom_res->deinit(custom_res, NULL, 0); + if (rc) + CAM_ERR(CAM_CUSTOM, "deinit failed"); + } + + rc = cam_custom_hw_sub_mod_reset(hw_priv, NULL, 0); + + /* Turn OFF Regulators, Clocks and other SOC resources */ + CAM_DBG(CAM_CUSTOM, "Disable SOC resource"); + rc = cam_custom_hw_sub_mod_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_CUSTOM, "Disable SOC failed"); + + custom_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + + return rc; +} + +int cam_custom_hw_sub_mod_reset(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &custom_hw->soc_info; + /* Do Reset of HW */ + return rc; +} + +int cam_custom_hw_sub_mod_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + int rc = 0; + + if (!hw_priv || !reserve_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + /*Reserve Args */ + return rc; +} + + +int cam_custom_hw_sub_mod_release(void *hw_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + int rc = 0; + + if (!hw_priv || !release_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + /* Release Resources */ + mutex_unlock(&custom_hw->hw_mutex); + + return rc; +} + + +int cam_custom_hw_sub_mod_start(void *hw_priv, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + int rc = 0; + + if (!hw_priv || !start_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + /* Start HW -- Stream On*/ + mutex_unlock(&custom_hw->hw_mutex); + + return rc; +} + +int cam_custom_hw_sub_mod_stop(void *hw_priv, + void *stop_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + int rc = 0; + + if (!hw_priv || !stop_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + /* Stop HW */ + mutex_unlock(&custom_hw->hw_mutex); + + return rc; +} + +int cam_custom_hw_sub_mod_read(void *hw_priv, + void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_custom_hw_sub_mod_write(void *hw_priv, + void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_custom_hw_submit_req(void *hw_priv, void *hw_submit_args, + uint32_t arg_size) +{ + struct cam_hw_info *custom_dev = hw_priv; + struct cam_custom_sub_mod_req_to_dev *submit_req = + (struct cam_custom_sub_mod_req_to_dev *)hw_submit_args; + struct cam_custom_sub_mod_core_info *core_info = NULL; + + core_info = + (struct cam_custom_sub_mod_core_info *)custom_dev->core_info; + + spin_lock(&custom_dev->hw_lock); + if (core_info->curr_req) { + CAM_WARN(CAM_CUSTOM, "Req %lld still processed by %s", + core_info->curr_req->req_id, + custom_dev->soc_info.dev_name); + spin_unlock(&custom_dev->hw_lock); + return -EAGAIN; + } + + core_info->curr_req = submit_req; + spin_unlock(&custom_dev->hw_lock); + + /* Do other submit procedures */ + return 0; +} + +irqreturn_t cam_custom_hw_sub_mod_irq(int irq_num, void *data) +{ + struct cam_hw_info *custom_dev = data; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_hw_cb_args cb_args; + struct cam_custom_sub_mod_core_info *core_info = NULL; + uint32_t irq_status = 0; + + if (!data) { + CAM_ERR(CAM_CUSTOM, "Invalid custom_dev_info"); + return IRQ_HANDLED; + } + + soc_info = &custom_dev->soc_info; + core_info = + (struct cam_custom_sub_mod_core_info *)custom_dev->core_info; + + irq_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + core_info->device_hw_info->irq_status); + + cam_io_w_mb(irq_status, + soc_info->reg_map[0].mem_base + + core_info->device_hw_info->irq_clear); + + spin_lock(&custom_dev->hw_lock); + cb_args.irq_status = irq_status; + cb_args.req_info = core_info->curr_req; + core_info->curr_req = NULL; + if (core_info->irq_cb.custom_hw_mgr_cb) + core_info->irq_cb.custom_hw_mgr_cb( + core_info->irq_cb.data, &cb_args); + spin_unlock(&custom_dev->hw_lock); + + return IRQ_HANDLED; +} + +int cam_custom_hw_sub_mod_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_sub_mod_core_info *core_info = NULL; + unsigned long flag = 0; + int rc = 0; + + if (!hw_priv || !cmd_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &hw->soc_info; + core_info = hw->core_info; + /* Handle any custom process cmds */ + + switch (cmd_type) { + case CAM_CUSTOM_SET_IRQ_CB: { + struct cam_custom_sub_mod_set_irq_cb *irq_cb = cmd_args; + + CAM_DBG(CAM_CUSTOM, "Setting irq cb"); + spin_lock_irqsave(&hw->hw_lock, flag); + core_info->irq_cb.custom_hw_mgr_cb = irq_cb->custom_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + spin_unlock_irqrestore(&hw->hw_lock, flag); + break; + } + case CAM_CUSTOM_SUBMIT_REQ: { + rc = cam_custom_hw_submit_req(hw_priv, cmd_args, arg_size); + break; + } + default: + break; + } + + return rc; +} + + diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.h new file mode 100644 index 000000000000..d27d578f6c8d --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_SUB_MOD_CORE_H_ +#define _CAM_CUSTOM_SUB_MOD_CORE_H_ + +#include "cam_debug_util.h" +#include "cam_custom_hw.h" +#include "cam_custom_sub_mod_soc.h" +#include "cam_custom_hw_mgr_intf.h" + +struct cam_custom_sub_mod_set_irq_cb { + int32_t (*custom_hw_mgr_cb)(void *data, + struct cam_custom_hw_cb_args *cb_args); + void *data; +}; + +struct cam_custom_sub_mod_req_to_dev { + uint64_t req_id; + uint32_t ctx_idx; + uint32_t dev_idx; +}; + +struct cam_custom_device_hw_info { + uint32_t hw_ver; + uint32_t irq_status; + uint32_t irq_mask; + uint32_t irq_clear; +}; + +struct cam_custom_sub_mod_core_info { + uint32_t cpas_handle; + bool cpas_start; + bool clk_enable; + struct cam_custom_sub_mod_set_irq_cb irq_cb; + struct cam_custom_sub_mod_req_to_dev *curr_req; + struct cam_custom_device_hw_info *device_hw_info; + struct cam_hw_info *custom_hw_info; +}; + +enum cam_custom_hw_resource_type { + CAM_CUSTOM_HW_RESOURCE_UNINT, + CAM_CUSTOM_HW_RESOURCE_SRC, + CAM_CUSTOM_HW_RESOURCE_MAX, +}; + +struct cam_custom_sub_mod_acq { + enum cam_custom_hw_resource_type rsrc_type; + int32_t acq; + struct cam_custom_resource_node *rsrc_node; +}; + +int cam_custom_hw_sub_mod_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_reset(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_release(void *hw_priv, + void *release_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_start(void *hw_priv, + void *start_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_stop(void *hw_priv, + void *stop_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_read(void *hw_priv, + void *read_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_write(void *hw_priv, + void *write_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_custom_hw_sub_mod_irq(int irq_num, void *data); + +#endif /* _CAM_CUSTOM_SUB_MOD_CORE_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.c new file mode 100644 index 000000000000..bd7d65913649 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include "cam_custom_sub_mod_dev.h" +#include "cam_custom_sub_mod_core.h" +#include "cam_custom_sub_mod_soc.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_custom_hw_sub_mod_list + [CAM_CUSTOM_SUB_MOD_MAX_INSTANCES] = {0, 0}; + +static char cam_custom_hw_sub_mod_name[8]; + +struct cam_custom_device_hw_info cam_custom_hw_info = { + .hw_ver = 0x0, + .irq_status = 0x0, + .irq_mask = 0x0, + .irq_clear = 0x0, +}; +EXPORT_SYMBOL(cam_custom_hw_info); + +int cam_custom_hw_sub_mod_init(struct cam_hw_intf **custom_hw, uint32_t hw_idx) +{ + int rc = 0; + + if (cam_custom_hw_sub_mod_list[hw_idx]) { + *custom_hw = cam_custom_hw_sub_mod_list[hw_idx]; + rc = 0; + } else { + *custom_hw = NULL; + rc = -ENODEV; + } + return 0; +} + +int cam_custom_hw_sub_mod_probe(struct platform_device *pdev) +{ + struct cam_hw_info *hw = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_custom_sub_mod_core_info *core_info = NULL; + int rc = 0; + + hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!hw_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_intf->hw_idx); + + hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!hw) { + rc = -ENOMEM; + goto free_hw_intf; + } + + memset(cam_custom_hw_sub_mod_name, 0, + sizeof(cam_custom_hw_sub_mod_name)); + snprintf(cam_custom_hw_sub_mod_name, sizeof(cam_custom_hw_sub_mod_name), + "custom_hw%1u", hw_intf->hw_idx); + + hw->soc_info.pdev = pdev; + hw->soc_info.dev = &pdev->dev; + hw->soc_info.dev_name = cam_custom_hw_sub_mod_name; + hw_intf->hw_priv = hw; + hw_intf->hw_ops.get_hw_caps = cam_custom_hw_sub_mod_get_hw_caps; + hw_intf->hw_ops.init = cam_custom_hw_sub_mod_init_hw; + hw_intf->hw_ops.deinit = cam_custom_hw_sub_mod_deinit_hw; + hw_intf->hw_ops.reset = cam_custom_hw_sub_mod_reset; + hw_intf->hw_ops.reserve = cam_custom_hw_sub_mod_reserve; + hw_intf->hw_ops.release = cam_custom_hw_sub_mod_release; + hw_intf->hw_ops.start = cam_custom_hw_sub_mod_start; + hw_intf->hw_ops.stop = cam_custom_hw_sub_mod_stop; + hw_intf->hw_ops.read = cam_custom_hw_sub_mod_read; + hw_intf->hw_ops.write = cam_custom_hw_sub_mod_write; + hw_intf->hw_ops.process_cmd = cam_custom_hw_sub_mod_process_cmd; + hw_intf->hw_type = CAM_CUSTOM_HW_TYPE_1; + + platform_set_drvdata(pdev, hw_intf); + + hw->core_info = kzalloc(sizeof(struct cam_custom_sub_mod_core_info), + GFP_KERNEL); + if (!hw->core_info) { + CAM_DBG(CAM_CUSTOM, "Failed to alloc for core"); + rc = -ENOMEM; + goto free_hw; + } + core_info = (struct cam_custom_sub_mod_core_info *)hw->core_info; + + core_info->custom_hw_info = hw; + + rc = cam_custom_hw_sub_mod_init_soc_resources(&hw->soc_info, + cam_custom_hw_sub_mod_irq, hw); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, "Failed to init soc rc=%d", rc); + goto free_core_info; + } + + /* Initialize HW */ + + hw->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&hw->hw_mutex); + spin_lock_init(&hw->hw_lock); + init_completion(&hw->hw_complete); + + if (hw_intf->hw_idx < CAM_CUSTOM_HW_SUB_MOD_MAX) + cam_custom_hw_sub_mod_list[hw_intf->hw_idx] = hw_intf; + + /* needs to be invoked when custom hw is in place */ + //cam_custom_hw_sub_mod_init_hw(hw, NULL, 0); + + CAM_DBG(CAM_CUSTOM, "Custom hw_idx[%d] probe successful", + hw_intf->hw_idx); + return rc; + +free_core_info: + kfree(hw->core_info); +free_hw: + kfree(hw); +free_hw_intf: + kfree(hw_intf); + return rc; +} + +static const struct of_device_id cam_custom_hw_sub_mod_dt_match[] = { + { + .compatible = "qcom,cam_custom_hw_sub_mod", + .data = &cam_custom_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_custom_hw_sub_mod_dt_match); + +static struct platform_driver cam_custom_hw_sub_mod_driver = { + .probe = cam_custom_hw_sub_mod_probe, + .driver = { + .name = CAM_CUSTOM_SUB_MOD_NAME, + .of_match_table = cam_custom_hw_sub_mod_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_custom_hw_sub_module_init(void) +{ + return platform_driver_register(&cam_custom_hw_sub_mod_driver); +} + +static void __exit cam_custom_hw_sub_module_exit(void) +{ + platform_driver_unregister(&cam_custom_hw_sub_mod_driver); +} + +module_init(cam_custom_hw_sub_module_init); +module_exit(cam_custom_hw_sub_module_exit); +MODULE_DESCRIPTION("CAM CUSTOM HW SUB MODULE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.h new file mode 100644 index 000000000000..1da630ed5ec2 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_SUB_MOD_DEV_H_ +#define _CAM_CUSTOM_SUB_MOD_DEV_H_ + +#include "cam_custom_hw_mgr_intf.h" + +#define CAM_CUSTOM_SUB_MOD_NAME "cam_custom_sub_mod" + +#define CAM_CUSTOM_SUB_MOD_MAX_INSTANCES 2 + +#endif /* _CAM_CUSTOM_SUB_MOD_DEV_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c new file mode 100644 index 000000000000..0b517b93c6c0 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_cpas_api.h" +#include "cam_custom_sub_mod_soc.h" +#include "cam_debug_util.h" + +int cam_custom_hw_sub_mod_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *irq_data) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private = NULL; + struct cam_cpas_register_params cpas_register_param; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, + "Error! Get DT properties failed rc=%d", rc); + /* For Test Purposes */ + return 0; + } + + soc_private = kzalloc(sizeof(struct cam_custom_hw_soc_private), + GFP_KERNEL); + if (!soc_private) { + CAM_DBG(CAM_CUSTOM, "Error! soc_private Alloc Failed"); + return -ENOMEM; + } + soc_info->soc_private = soc_private; + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + irq_data); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, + "Error! Request platform resources failed rc=%d", rc); + return rc; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + cpas_register_param.cam_cpas_client_cb = NULL; + cpas_register_param.userdata = soc_info; + soc_private->cpas_handle = + cpas_register_param.client_handle; + + rc = cam_cpas_register_client(&cpas_register_param); + if (rc < 0) + goto release_soc; + + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} + +int cam_custom_hw_sub_mod_deinit_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private = NULL; + + if (!soc_info) { + CAM_ERR(CAM_CUSTOM, "Error! soc_info NULL"); + return -ENODEV; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_CUSTOM, "Error! soc_private NULL"); + return -ENODEV; + } + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_CUSTOM, "CPAS0 unregistration failed rc=%d", rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc < 0) + CAM_ERR(CAM_CUSTOM, + "Error! Release platform resources failed rc=%d", rc); + + kfree(soc_private); + + return rc; +} + +int cam_custom_hw_sub_mod_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private = soc_info->soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = 7200000; + axi_vote.axi_path[0].mnoc_ab_bw = 7200000; + axi_vote.axi_path[0].mnoc_ib_bw = 7200000; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = 512000000; + axi_vote.axi_path[1].mnoc_ab_bw = 512000000; + axi_vote.axi_path[1].mnoc_ib_bw = 512000000; + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Error! CPAS0 start failed rc=%d", rc); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_TURBO_VOTE, true); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Error! enable platform failed rc=%d", rc); + goto stop_cpas; + } + + return 0; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_custom_hw_sub_mod_disable_soc_resources( + struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_CUSTOM, "Error! Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Disable platform failed rc=%d", rc); + return rc; + } + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Error! CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.h new file mode 100644 index 000000000000..e9c95d43d366 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_SUB_MOD_SOC_H_ +#define _CAM_CUSTOM_HW_SUB_MOD_SOC_H_ + +#include "cam_soc_util.h" +/* + * struct cam_custom_hw_soc_private: + * + * @Brief: Private SOC data specific to Custom HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + */ +struct cam_custom_hw_soc_private { + uint32_t cpas_handle; +}; + +int cam_custom_hw_sub_mod_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *irq_data); + +int cam_custom_hw_sub_mod_deinit_soc_resources( + struct cam_hw_soc_info *soc_info); + +int cam_custom_hw_sub_mod_enable_soc_resources( + struct cam_hw_soc_info *soc_info); + +int cam_custom_hw_sub_mod_disable_soc_resources( + struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_CUSTOM_HW_SUB_MOD_SOC_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c new file mode 100644 index 000000000000..1db06bb3ab1f --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c @@ -0,0 +1,1329 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cam_sync_api.h" +#include "cam_smmu_api.h" +#include "cam_req_mgr_workq.h" +#include "cam_custom_hw_mgr.h" +#include "cam_packet_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_mem_mgr_api.h" +#include "cam_common_util.h" +#include "cam_hw.h" + +static struct cam_custom_hw_mgr g_custom_hw_mgr; + +static int cam_custom_mgr_get_hw_caps(void *hw_mgr_priv, + void *hw_caps_args) +{ + int rc = 0; + struct cam_custom_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query = hw_caps_args; + struct cam_custom_query_cap_cmd custom_hw_cap; + struct cam_hw_info *cam_custom_hw; + struct cam_hw_soc_info *soc_info_hw; + + cam_custom_hw = (struct cam_hw_info *) + g_custom_hw_mgr.custom_hw[0]->hw_priv; + if (cam_custom_hw) + soc_info_hw = &cam_custom_hw->soc_info; + + CAM_DBG(CAM_CUSTOM, "enter"); + + if (query->handle_type != CAM_HANDLE_USER_POINTER) + CAM_ERR(CAM_CUSTOM, "Wrong Args"); + + if (copy_from_user(&custom_hw_cap, + u64_to_user_ptr(query->caps_handle), + sizeof(struct cam_custom_query_cap_cmd))) { + rc = -EFAULT; + return rc; + } + + custom_hw_cap.device_iommu.non_secure = hw_mgr->img_iommu_hdl; + custom_hw_cap.device_iommu.secure = -1; + + /* Initializing cdm handles to -1 */ + custom_hw_cap.cdm_iommu.non_secure = -1; + custom_hw_cap.cdm_iommu.secure = -1; + + custom_hw_cap.num_dev = 1; + custom_hw_cap.dev_caps[0].hw_type = 0; + custom_hw_cap.dev_caps[0].hw_version = 0; + + if (copy_to_user(u64_to_user_ptr(query->caps_handle), + &custom_hw_cap, sizeof(struct cam_custom_query_cap_cmd))) + rc = -EFAULT; + + CAM_DBG(CAM_CUSTOM, "exit rc :%d", rc); + return rc; +} + +enum cam_custom_hw_resource_state + cam_custom_hw_mgr_get_custom_res_state( + uint32_t in_rsrc_state) +{ + enum cam_custom_hw_resource_state rsrc_state; + + CAM_DBG(CAM_CUSTOM, "rsrc_state %x", in_rsrc_state); + + switch (in_rsrc_state) { + case CAM_ISP_RESOURCE_STATE_UNAVAILABLE: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE; + break; + case CAM_ISP_RESOURCE_STATE_AVAILABLE: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_AVAILABLE; + break; + case CAM_ISP_RESOURCE_STATE_RESERVED: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_RESERVED; + break; + case CAM_ISP_RESOURCE_STATE_INIT_HW: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_INIT_HW; + break; + case CAM_ISP_RESOURCE_STATE_STREAMING: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_STREAMING; + break; + default: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE; + CAM_DBG(CAM_CUSTOM, "invalid rsrc type"); + break; + } + + return rsrc_state; +} + +enum cam_isp_resource_state + cam_custom_hw_mgr_get_isp_res_state( + uint32_t in_rsrc_state) +{ + enum cam_isp_resource_state rsrc_state; + + CAM_DBG(CAM_CUSTOM, "rsrc_state %x", in_rsrc_state); + + switch (in_rsrc_state) { + case CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE: + rsrc_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_AVAILABLE: + rsrc_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_RESERVED: + rsrc_state = CAM_ISP_RESOURCE_STATE_RESERVED; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_INIT_HW: + rsrc_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_STREAMING: + rsrc_state = CAM_ISP_RESOURCE_STATE_STREAMING; + break; + default: + rsrc_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + CAM_DBG(CAM_CUSTOM, "invalid rsrc type"); + break; + } + + return rsrc_state; +} + +enum cam_isp_resource_type + cam_custom_hw_mgr_get_isp_res_type( + enum cam_custom_hw_mgr_res_type res_type) +{ + switch (res_type) { + case CAM_CUSTOM_CID_HW: + return CAM_ISP_RESOURCE_CID; + case CAM_CUSTOM_CSID_HW: + return CAM_ISP_RESOURCE_PIX_PATH; + default: + return CAM_ISP_RESOURCE_MAX; + } +} + +static int cam_custom_hw_mgr_deinit_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.deinit) { + CAM_DBG(CAM_CUSTOM, "DEINIT HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.deinit(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "DEINIT HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_hw_mgr_stop_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_csid_hw_stop_args stop_cmd; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.stop) { + CAM_DBG(CAM_CUSTOM, "STOP HW for res_id:%u", + hw_mgr_res->res_id); + stop_cmd.num_res = 1; + stop_cmd.node_res = &isp_rsrc_node; + stop_cmd.stop_cmd = CAM_CSID_HALT_AT_FRAME_BOUNDARY; + rc = hw_intf->hw_ops.stop(hw_intf->hw_priv, + &stop_cmd, sizeof(struct cam_csid_hw_stop_args)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "STOP HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_custom_hw_mgr_res *hw_mgr_res; + struct cam_custom_hw_mgr_ctx *ctx; + + if (!hw_mgr_priv || !stop_hw_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_custom_hw_mgr_ctx *) + stop_args->ctxt_to_hw_map; + + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, " Enter...ctx id:%d", ctx->ctx_index); + + /* Stop custom cid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_stop_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + + /* Stop custom csid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_stop_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + } + + + /* stop custom hw here */ + + /* Deinit custom cid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_deinit_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + + /* Deinit custom csid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_deinit_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + } + + /* deinit custom rsrc */ + + return rc; +} + +static int cam_custom_hw_mgr_init_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.init) { + CAM_DBG(CAM_CUSTOM, "INIT HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.init(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "INIT HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_hw_mgr_start_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.start) { + CAM_DBG(CAM_CUSTOM, "Start HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.start(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "START HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_mgr_start_hw(void *hw_mgr_priv, + void *start_hw_args) +{ + int rc = 0; + struct cam_hw_config_args *hw_config; + struct cam_hw_stop_args stop_args; + struct cam_custom_hw_mgr_res *hw_mgr_res; + struct cam_custom_hw_mgr_ctx *ctx; + + if (!hw_mgr_priv || !start_hw_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + hw_config = (struct cam_hw_config_args *)start_hw_args; + + ctx = (struct cam_custom_hw_mgr_ctx *) + hw_config->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, "Enter... ctx id:%d", + ctx->ctx_index); + + /* Init custom cid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT CID(id :%d)", + hw_mgr_res->res_id); + goto deinit_hw; + } + } + + /* Init custom csid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT CSID(id :%d)", + hw_mgr_res->res_id); + goto deinit_hw; + } + } + + + /* Init custom hw here */ + + /* Apply init config */ + + /* Start custom HW first */ + if (rc < 0) + goto err; + + /* Start custom csid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not START CSID(id :%d)", + hw_mgr_res->res_id); + goto err; + } + } + + /* Start custom cid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not START CID(id :%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_CUSTOM, "Start success for ctx id:%d", ctx->ctx_index); + return 0; + +err: + stop_args.ctxt_to_hw_map = hw_config->ctxt_to_hw_map; + cam_custom_mgr_stop_hw(hw_mgr_priv, &stop_args); +deinit_hw: + /* deinit the hw previously initialized */ + CAM_DBG(CAM_CUSTOM, "Exit...(rc=%d)", rc); + return rc; +} + +static int cam_custom_mgr_read(void *hw_mgr_priv, void *read_args) +{ + return -EPERM; +} + +static int cam_custom_mgr_write(void *hw_mgr_priv, void *write_args) +{ + return -EPERM; +} + +static int cam_custom_hw_mgr_put_ctx( + struct list_head *src_list, + struct cam_custom_hw_mgr_ctx **custom_ctx) +{ + struct cam_custom_hw_mgr_ctx *ctx_ptr = NULL; + + ctx_ptr = *custom_ctx; + if (ctx_ptr) + list_add_tail(&ctx_ptr->list, src_list); + *custom_ctx = NULL; + return 0; +} + +static int cam_custom_hw_mgr_get_ctx( + struct list_head *src_list, + struct cam_custom_hw_mgr_ctx **custom_ctx) +{ + struct cam_custom_hw_mgr_ctx *ctx_ptr = NULL; + + if (!list_empty(src_list)) { + ctx_ptr = list_first_entry(src_list, + struct cam_custom_hw_mgr_ctx, list); + list_del_init(&ctx_ptr->list); + } else { + CAM_ERR(CAM_CUSTOM, "No more free custom hw mgr ctx"); + return -EINVAL; + } + *custom_ctx = ctx_ptr; + memset(ctx_ptr->sub_hw_list, 0, + sizeof(struct cam_custom_hw_mgr_res) * + CAM_CUSTOM_HW_RES_MAX); + + return 0; +} + +static int cam_custom_hw_mgr_put_res( + struct list_head *src_list, + struct cam_custom_hw_mgr_res **res) +{ + struct cam_custom_hw_mgr_res *res_ptr = NULL; + + res_ptr = *res; + if (res_ptr) + list_add_tail(&res_ptr->list, src_list); + + return 0; +} + +static int cam_custom_hw_mgr_get_res( + struct list_head *src_list, + struct cam_custom_hw_mgr_res **res) +{ + int rc = 0; + struct cam_custom_hw_mgr_res *res_ptr = NULL; + + if (!list_empty(src_list)) { + res_ptr = list_first_entry(src_list, + struct cam_custom_hw_mgr_res, list); + list_del_init(&res_ptr->list); + } else { + CAM_ERR(CAM_CUSTOM, "No more free custom ctx rsrc"); + rc = -1; + } + *res = res_ptr; + + return rc; +} + +static enum cam_ife_pix_path_res_id + cam_custom_hw_mgr_get_csid_res_type( + uint32_t out_port_type) +{ + enum cam_ife_pix_path_res_id path_id; + + CAM_DBG(CAM_CUSTOM, "out_port_type %x", out_port_type); + + switch (out_port_type) { + case CAM_CUSTOM_OUT_RES_UDI_0: + path_id = CAM_IFE_PIX_PATH_RES_UDI_0; + break; + case CAM_CUSTOM_OUT_RES_UDI_1: + path_id = CAM_IFE_PIX_PATH_RES_UDI_1; + break; + case CAM_CUSTOM_OUT_RES_UDI_2: + path_id = CAM_IFE_PIX_PATH_RES_UDI_2; + break; + default: + path_id = CAM_IFE_PIX_PATH_RES_MAX; + CAM_DBG(CAM_CUSTOM, "maximum rdi output type exceeded"); + break; + } + + CAM_DBG(CAM_CUSTOM, "out_port %x path_id %d", out_port_type, path_id); + + return path_id; +} + +static int cam_custom_hw_mgr_acquire_cid_res( + struct cam_custom_hw_mgr_ctx *custom_ctx, + struct cam_isp_in_port_generic_info *in_port, + struct cam_custom_hw_mgr_res **cid_res, + enum cam_ife_pix_path_res_id path_res_id, + struct cam_isp_resource_node **cid_rsrc_node) +{ + int rc = -1; + int i; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_hw_intf *hw_intf; + struct cam_custom_hw_mgr_res *cid_res_temp; + struct cam_csid_hw_reserve_resource_args csid_acquire; + struct cam_isp_resource_node *isp_rsrc_node; + struct cam_isp_out_port_generic_info *out_port = NULL; + + custom_hw_mgr = custom_ctx->hw_mgr; + *cid_res = NULL; + + rc = cam_custom_hw_mgr_get_res( + &custom_ctx->free_res_list, cid_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "No more free hw mgr resource"); + goto end; + } + + memset(&csid_acquire, 0, sizeof(csid_acquire)); + cid_res_temp = *cid_res; + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + csid_acquire.res_id = path_res_id; + csid_acquire.node_res = NULL; + CAM_DBG(CAM_CUSTOM, "path_res_id %d", path_res_id); + + if (in_port->num_out_res) + out_port = &(in_port->data[0]); + + for (i = 0; i < CAM_CUSTOM_CSID_HW_MAX; i++) { + if (!custom_hw_mgr->csid_devices[i]) + continue; + + hw_intf = custom_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + /* since there is a need of 1 cid at this stage */ + if (rc) + continue; + else + break; + + } + + if (!csid_acquire.node_res) { + CAM_ERR(CAM_CUSTOM, + "Can not acquire custom cid resource for path %d", + path_res_id); + rc = -EAGAIN; + goto put_res; + } + + *cid_rsrc_node = csid_acquire.node_res; + isp_rsrc_node = csid_acquire.node_res; + cid_res_temp->rsrc_node = isp_rsrc_node; + cid_res_temp->res_type = CAM_CUSTOM_CID_HW; + cid_res_temp->res_id = isp_rsrc_node->res_id; + cam_custom_hw_mgr_put_res(&custom_ctx->res_list_custom_cid, + &cid_res_temp); + + CAM_DBG(CAM_CUSTOM, "CID acquired successfully %u", + isp_rsrc_node->res_id); + + return 0; + +put_res: + cam_custom_hw_mgr_put_res(&custom_ctx->free_res_list, cid_res); +end: + return rc; + +} + +static int cam_custom_hw_mgr_acquire_csid_res( + struct cam_custom_hw_mgr_ctx *custom_ctx, + struct cam_isp_in_port_generic_info *in_port_info) +{ + int rc = 0, i = 0; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_isp_out_port_generic_info *out_port; + struct cam_custom_hw_mgr_res *custom_csid_res; + struct cam_custom_hw_mgr_res *custom_cid_res; + struct cam_hw_intf *hw_intf; + struct cam_csid_hw_reserve_resource_args custom_csid_acquire; + enum cam_ife_pix_path_res_id path_res_id; + struct cam_isp_resource_node *isp_rsrc_node; + struct cam_isp_resource_node *cid_rsrc_node = NULL; + + custom_hw_mgr = custom_ctx->hw_mgr; + + for (i = 0; i < in_port_info->num_out_res; i++) { + out_port = &in_port_info->data[i]; + path_res_id = cam_custom_hw_mgr_get_csid_res_type( + out_port->res_type); + + if (path_res_id == CAM_IFE_PIX_PATH_RES_MAX) { + CAM_WARN(CAM_CUSTOM, "Invalid out port res_type %u", + out_port->res_type); + continue; + } + + rc = cam_custom_hw_mgr_acquire_cid_res(custom_ctx, in_port_info, + &custom_cid_res, path_res_id, &cid_rsrc_node); + if (rc) { + CAM_ERR(CAM_CUSTOM, "No free cid rsrc %d", rc); + goto end; + } + + rc = cam_custom_hw_mgr_get_res(&custom_ctx->free_res_list, + &custom_csid_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "No more free hw mgr rsrc"); + goto end; + } + + memset(&custom_csid_acquire, 0, sizeof(custom_csid_acquire)); + custom_csid_acquire.res_id = path_res_id; + custom_csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + custom_csid_acquire.cid = cid_rsrc_node->res_id; + custom_csid_acquire.in_port = in_port_info; + custom_csid_acquire.out_port = out_port; + custom_csid_acquire.sync_mode = 0; + custom_csid_acquire.node_res = NULL; + + hw_intf = cid_rsrc_node->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &custom_csid_acquire, sizeof(custom_csid_acquire)); + if (rc) { + CAM_ERR(CAM_CUSTOM, + "Custom csid acquire failed for hw_idx %u rc %d", + hw_intf->hw_idx, rc); + goto put_res; + } + + if (custom_csid_acquire.node_res == NULL) { + CAM_ERR(CAM_CUSTOM, "Acquire custom csid failed"); + rc = -EAGAIN; + goto put_res; + } + + isp_rsrc_node = custom_csid_acquire.node_res; + custom_csid_res->rsrc_node = isp_rsrc_node; + custom_csid_res->res_type = CAM_CUSTOM_CSID_HW; + custom_csid_res->res_id = custom_csid_acquire.res_id; + cam_custom_hw_mgr_put_res( + &custom_ctx->res_list_custom_csid, + &custom_csid_res); + CAM_DBG(CAM_CUSTOM, "Custom CSID acquired for path %d", + path_res_id); + } + + return 0; + +put_res: + cam_custom_hw_mgr_put_res(&custom_ctx->free_res_list, + &custom_csid_res); +end: + return rc; +} + +static int cam_custom_hw_mgr_free_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = 0; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.release) { + CAM_DBG(CAM_CUSTOM, "RELEASE HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.release(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Release HW failed for hw_idx %d", + hw_intf->hw_idx); + } + + /* caller should make sure the resource is in a list */ + list_del_init(&hw_mgr_res->list); + memset(hw_mgr_res, 0, sizeof(*hw_mgr_res)); + INIT_LIST_HEAD(&hw_mgr_res->list); + + return 0; +} + +static int cam_custom_hw_mgr_release_hw_for_ctx( + struct cam_custom_hw_mgr_ctx *custom_ctx) +{ + int rc = -1; + struct cam_custom_hw_mgr_res *hw_mgr_res; + struct cam_custom_hw_mgr_res *hw_mgr_res_temp; + + /* Release custom cid */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &custom_ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_ISP, "Can not release CID(id :%d)", + hw_mgr_res->res_id); + cam_custom_hw_mgr_put_res( + &custom_ctx->free_res_list, &hw_mgr_res); + } + + /* Release custom csid */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &custom_ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_ISP, "Can not release CSID(id :%d)", + hw_mgr_res->res_id); + cam_custom_hw_mgr_put_res( + &custom_ctx->free_res_list, &hw_mgr_res); + } + + /* Release custom HW Here */ + + return 0; +} +static int cam_custom_mgr_release_hw(void *hw_mgr_priv, + void *release_hw_args) +{ + int rc = 0; + struct cam_hw_release_args *release_args = release_hw_args; + struct cam_custom_hw_mgr_ctx *custom_ctx; + + if (!hw_mgr_priv || !release_hw_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + custom_ctx = + (struct cam_custom_hw_mgr_ctx *)release_args->ctxt_to_hw_map; + if (!custom_ctx || !custom_ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, "Enter...ctx id:%d", + custom_ctx->ctx_index); + + cam_custom_hw_mgr_release_hw_for_ctx(custom_ctx); + list_del_init(&custom_ctx->list); + custom_ctx->ctx_in_use = 0; + cam_custom_hw_mgr_put_ctx(&g_custom_hw_mgr.free_ctx_list, &custom_ctx); + CAM_DBG(CAM_CUSTOM, "Release Exit.."); + return rc; +} + +static void cam_custom_hw_mgr_acquire_get_unified_dev_str( + struct cam_custom_in_port_info *in, + struct cam_isp_in_port_generic_info *gen_port_info) +{ + int i; + + gen_port_info->res_type = in->res_type + + CAM_ISP_IFE_IN_RES_BASE - CAM_CUSTOM_IN_RES_BASE; + gen_port_info->lane_type = in->lane_type; + gen_port_info->lane_num = in->lane_num; + gen_port_info->lane_cfg = in->lane_cfg; + gen_port_info->vc[0] = in->vc[0]; + gen_port_info->dt[0] = in->dt[0]; + gen_port_info->num_valid_vc_dt = in->num_valid_vc_dt; + gen_port_info->format = in->format; + gen_port_info->test_pattern = in->test_pattern; + gen_port_info->usage_type = in->usage_type; + gen_port_info->left_start = in->left_start; + gen_port_info->left_stop = in->left_stop; + gen_port_info->left_width = in->left_width; + gen_port_info->right_start = in->right_start; + gen_port_info->right_stop = in->right_stop; + gen_port_info->right_width = in->right_width; + gen_port_info->line_start = in->line_start; + gen_port_info->line_stop = in->line_stop; + gen_port_info->height = in->height; + gen_port_info->pixel_clk = in->pixel_clk; + gen_port_info->cust_node = 1; + gen_port_info->num_out_res = in->num_out_res; + gen_port_info->num_bytes_out = in->num_bytes_out; + + for (i = 0; i < in->num_out_res; i++) { + gen_port_info->data[i].res_type = in->data[i].res_type; + gen_port_info->data[i].format = in->data[i].format; + } +} + +static int cam_custom_mgr_acquire_hw_for_ctx( + struct cam_custom_hw_mgr_ctx *custom_ctx, + struct cam_isp_in_port_generic_info *in_port_info, + uint32_t *acquired_hw_id, uint32_t *acquired_hw_path) +{ + int rc = 0, i = 0; + struct cam_hw_intf *hw_intf; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_custom_sub_mod_acq acq; + + custom_hw_mgr = custom_ctx->hw_mgr; + + /* Acquire custom csid */ + rc = cam_custom_hw_mgr_acquire_csid_res(custom_ctx, in_port_info); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom csid acquire failed rc %d"); + goto err; + } + + /* Acquire custom hw */ + for (i = 0; i < CAM_CUSTOM_HW_SUB_MOD_MAX; i++) { + hw_intf = custom_hw_mgr->custom_hw[i]; + if (!hw_intf) + continue; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &acq, sizeof(acq)); + if (rc) { + CAM_DBG(CAM_CUSTOM, + "No custom resource from hw %d", + hw_intf->hw_idx); + continue; + } + /* need to be set in reserve based on HW being acquired */ + //custom_ctx->sub_hw_list[i].hw_res = acq.rsrc_node; + //custom_ctx->sub_hw_list[i].res_type = + //custom_ctx->sub_hw_list[i].res_id = ; + break; + } + +err: + return rc; +} + +static int cam_custom_mgr_acquire_hw( + void *hw_mgr_priv, + void *acquire_hw_args) +{ + int rc = -1; + int32_t i; + uint32_t in_port_length; + struct cam_custom_hw_mgr_ctx *custom_ctx; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_hw_acquire_args *acquire_args = + (struct cam_hw_acquire_args *) acquire_hw_args; + struct cam_custom_in_port_info *in_port_info; + struct cam_custom_resource *custom_rsrc; + struct cam_isp_in_port_generic_info *gen_port_info = NULL; + + if (!hw_mgr_priv || !acquire_args || (acquire_args->num_acq <= 0)) { + CAM_ERR(CAM_CUSTOM, "Invalid params"); + return -EINVAL; + } + + custom_hw_mgr = (struct cam_custom_hw_mgr *) hw_mgr_priv; + mutex_lock(&g_custom_hw_mgr.ctx_mutex); + rc = cam_custom_hw_mgr_get_ctx( + &custom_hw_mgr->free_ctx_list, &custom_ctx); + if (rc || !custom_ctx) { + CAM_ERR(CAM_CUSTOM, "Get custom hw context failed"); + mutex_unlock(&g_custom_hw_mgr.ctx_mutex); + goto err; + } + mutex_unlock(&g_custom_hw_mgr.ctx_mutex); + + /* Handle Acquire Here */ + custom_ctx->hw_mgr = custom_hw_mgr; + custom_ctx->cb_priv = acquire_args->context_data; + custom_ctx->event_cb = acquire_args->event_cb; + + custom_rsrc = kcalloc(acquire_args->num_acq, + sizeof(*custom_rsrc), GFP_KERNEL); + if (!custom_rsrc) { + rc = -ENOMEM; + goto free_ctx; + } + + CAM_DBG(CAM_CUSTOM, "start copy %d resources from user", + acquire_args->num_acq); + + if (copy_from_user(custom_rsrc, + (void __user *)acquire_args->acquire_info, + ((sizeof(*custom_rsrc)) * acquire_args->num_acq))) { + rc = -EFAULT; + goto free_ctx; + } + + for (i = 0; i < acquire_args->num_acq; i++) { + if (custom_rsrc[i].resource_id != CAM_CUSTOM_RES_ID_PORT) + continue; + + CAM_DBG(CAM_CUSTOM, "acquire no = %d total = %d", i, + acquire_args->num_acq); + + CAM_DBG(CAM_CUSTOM, + "start copy from user handle %lld with len = %d", + custom_rsrc[i].res_hdl, + custom_rsrc[i].length); + + in_port_length = sizeof(struct cam_custom_in_port_info); + if (in_port_length > custom_rsrc[i].length) { + CAM_ERR(CAM_CUSTOM, "buffer size is not enough"); + rc = -EINVAL; + goto free_res; + } + + in_port_info = memdup_user( + u64_to_user_ptr(custom_rsrc[i].res_hdl), + custom_rsrc[i].length); + + if (!IS_ERR(in_port_info)) { + if (in_port_info->num_out_res > + CAM_CUSTOM_HW_OUT_RES_MAX) { + CAM_ERR(CAM_CUSTOM, "too many output res %d", + in_port_info->num_out_res); + rc = -EINVAL; + kfree(in_port_info); + goto free_res; + } + + in_port_length = + sizeof(struct cam_custom_in_port_info) + + (in_port_info->num_out_res - 1) * + sizeof(struct cam_custom_out_port_info); + + if (in_port_length > custom_rsrc[i].length) { + CAM_ERR(CAM_CUSTOM, + "buffer size is not enough"); + rc = -EINVAL; + kfree(in_port_info); + goto free_res; + } + + gen_port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), + GFP_KERNEL); + if (gen_port_info == NULL) { + rc = -ENOMEM; + goto free_res; + } + + gen_port_info->data = kcalloc( + sizeof(struct cam_isp_out_port_generic_info), + in_port_info->num_out_res, GFP_KERNEL); + if (gen_port_info->data == NULL) { + kfree(gen_port_info); + gen_port_info = NULL; + rc = -ENOMEM; + goto free_res; + } + + cam_custom_hw_mgr_acquire_get_unified_dev_str( + in_port_info, gen_port_info); + + rc = cam_custom_mgr_acquire_hw_for_ctx(custom_ctx, + gen_port_info, &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + + kfree(in_port_info); + if (gen_port_info != NULL) { + kfree(gen_port_info->data); + kfree(gen_port_info); + gen_port_info = NULL; + } + + if (rc) { + CAM_ERR(CAM_CUSTOM, "can not acquire resource"); + goto free_res; + } + } else { + CAM_ERR(CAM_CUSTOM, + "Copy from user failed with in_port = %pK", + in_port_info); + rc = -EFAULT; + goto free_res; + } + } + + custom_ctx->ctx_in_use = 1; + acquire_args->ctxt_to_hw_map = custom_ctx; + CAM_DBG(CAM_CUSTOM, "Exit...(success)"); + return 0; + +free_res: + cam_custom_hw_mgr_release_hw_for_ctx(custom_ctx); +free_ctx: + cam_custom_hw_mgr_put_ctx(&custom_hw_mgr->free_ctx_list, &custom_ctx); +err: + CAM_DBG(CAM_CUSTOM, "Exit...(rc=%d)", rc); + return rc; +} + +static int cam_custom_add_io_buffers( + int iommu_hdl, + struct cam_hw_prepare_update_args *prepare) +{ + int rc = 0, i = 0; + int32_t hdl; + uint32_t plane_id; + struct cam_buf_io_cfg *io_cfg; + + io_cfg = (struct cam_buf_io_cfg *)((uint8_t *) + &prepare->packet->payload + + prepare->packet->io_configs_offset); + + /* Validate hw update entries */ + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_CUSTOM, "======= io config idx %d ============", i); + CAM_DBG(CAM_CUSTOM, + "i %d req_id %llu resource_type:%d fence:%d direction %d", + i, prepare->packet->header.request_id, + io_cfg[i].resource_type, io_cfg[i].fence, + io_cfg[i].direction); + + CAM_DBG(CAM_CUSTOM, "format: %d", io_cfg[i].format); + + if (io_cfg[i].direction == CAM_BUF_OUTPUT) { + CAM_DBG(CAM_CUSTOM, + "output fence 0x%x", io_cfg[i].fence); + } else if (io_cfg[i].direction == CAM_BUF_INPUT) { + CAM_DBG(CAM_CUSTOM, + "input fence 0x%x", io_cfg[i].fence); + } else { + CAM_ERR(CAM_CUSTOM, "Invalid io config direction :%d", + io_cfg[i].direction); + return -EINVAL; + } + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + continue; + + hdl = io_cfg[i].mem_handle[plane_id]; + CAM_DBG(CAM_CUSTOM, "handle 0x%x for plane %d", + hdl, plane_id); + /* Use cam_mem_get_io_buf() to retrieve iova */ + } + + /* Do other I/O config operations */ + } + + return rc; +} + +static int cam_custom_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc = 0; + struct cam_hw_prepare_update_args *prepare; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_custom_prepare_hw_update_data *prepare_hw_data; + struct cam_custom_hw_mgr *hw_mgr; + struct cam_custom_hw_mgr_ctx *ctx = NULL; + uint32_t *ptr; + size_t len; + struct cam_custom_cmd_buf_type_1 *custom_buf_type1; + + if (!hw_mgr_priv || !prepare_hw_update_args) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_mgr = (struct cam_custom_hw_mgr *) hw_mgr_priv; + prepare = + (struct cam_hw_prepare_update_args *) prepare_hw_update_args; + + CAM_DBG(CAM_CUSTOM, "Enter for req_id %lld", + prepare->packet->header.request_id); + + /* Prepare packet */ + prepare_hw_data = + (struct cam_custom_prepare_hw_update_data *)prepare->priv; + prepare_hw_data->packet_opcode_type = + (prepare->packet->header.op_code & 0xFFF); + ctx = (struct cam_custom_hw_mgr_ctx *) prepare->ctxt_to_hw_map; + + /* Test purposes-check the data in cmd buffer */ + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint8_t *)&prepare->packet->payload + + prepare->packet->cmd_buf_offset); + rc = cam_packet_util_get_cmd_mem_addr( + cmd_desc->mem_handle, &ptr, &len); + if (!rc) { + ptr += (cmd_desc->offset / 4); + custom_buf_type1 = + (struct cam_custom_cmd_buf_type_1 *)ptr; + CAM_DBG(CAM_CUSTOM, "frame num %u", + custom_buf_type1->custom_info); + } + + cam_custom_add_io_buffers(hw_mgr->img_iommu_hdl, prepare); + return 0; +} + +static int cam_custom_mgr_config_hw(void *hw_mgr_priv, + void *hw_config_args) +{ + int rc = 0; + int i = 0; + struct cam_custom_hw_mgr_ctx *custom_ctx; + struct cam_custom_hw_mgr_res *res; + struct cam_hw_config_args *cfg; + struct cam_hw_intf *hw_intf = NULL; + + CAM_DBG(CAM_CUSTOM, "Enter"); + if (!hw_mgr_priv || !hw_config_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + cfg = + (struct cam_hw_config_args *)hw_config_args; + custom_ctx = cfg->ctxt_to_hw_map; + + if (!custom_ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context parameters"); + return -EPERM; + } + + for (i = 0; i < CAM_CUSTOM_HW_SUB_MOD_MAX; i++) { + res = &custom_ctx->sub_hw_list[i]; + if (res->hw_res) { + hw_intf = res->hw_res->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + struct cam_custom_sub_mod_req_to_dev req_to_dev; + + req_to_dev.ctx_idx = custom_ctx->ctx_index; + req_to_dev.dev_idx = i; + req_to_dev.req_id = cfg->request_id; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_CUSTOM_SUBMIT_REQ, + &req_to_dev, sizeof(req_to_dev)); + } + } + } + + return rc; +} + +static int cam_custom_hw_mgr_irq_cb(void *data, + struct cam_custom_hw_cb_args *cb_args) +{ + struct cam_custom_sub_mod_req_to_dev *proc_req; + struct cam_hw_done_event_data evt_data; + struct cam_custom_hw_mgr_ctx *custom_ctx; + uint32_t ctx_idx; + + proc_req = cb_args->req_info; + ctx_idx = proc_req->ctx_idx; + custom_ctx = &g_custom_hw_mgr.ctx_pool[ctx_idx]; + + if (!custom_ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "ctx %u not in use", ctx_idx); + return 0; + } + + /* Based on irq status notify success/failure */ + + evt_data.request_id = proc_req->req_id; + custom_ctx->event_cb(custom_ctx->cb_priv, + CAM_CUSTOM_EVENT_BUF_DONE, &evt_data); + + return 0; +} + +int cam_custom_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) +{ + int rc = 0; + int i, j; + struct cam_custom_hw_mgr_ctx *ctx_pool; + struct cam_custom_sub_mod_set_irq_cb irq_cb_args; + struct cam_hw_intf *hw_intf = NULL; + + memset(&g_custom_hw_mgr, 0, sizeof(g_custom_hw_mgr)); + mutex_init(&g_custom_hw_mgr.ctx_mutex); + + /* fill custom hw intf information */ + for (i = 0; i < CAM_CUSTOM_HW_SUB_MOD_MAX; i++) { + /* Initialize sub modules */ + rc = cam_custom_hw_sub_mod_init( + &g_custom_hw_mgr.custom_hw[i], i); + + /* handle in case init fails */ + if (g_custom_hw_mgr.custom_hw[i]) { + hw_intf = g_custom_hw_mgr.custom_hw[i]; + if (hw_intf->hw_ops.process_cmd) { + irq_cb_args.custom_hw_mgr_cb = + cam_custom_hw_mgr_irq_cb; + irq_cb_args.data = + g_custom_hw_mgr.custom_hw[i]->hw_priv; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_CUSTOM_SET_IRQ_CB, &irq_cb_args, + sizeof(irq_cb_args)); + } + } + } + + for (i = 0; i < CAM_CUSTOM_CSID_HW_MAX; i++) { + /* Initialize csid custom modules */ + rc = cam_custom_csid_hw_init( + &g_custom_hw_mgr.csid_devices[i], i); + } + + INIT_LIST_HEAD(&g_custom_hw_mgr.free_ctx_list); + INIT_LIST_HEAD(&g_custom_hw_mgr.used_ctx_list); + + /* + * for now, we only support one iommu handle. later + * we will need to setup more iommu handle for other + * use cases. + * Also, we have to release them once we have the + * deinit support + */ + if (cam_smmu_get_handle("custom", + &g_custom_hw_mgr.img_iommu_hdl)) { + CAM_ERR(CAM_CUSTOM, "Can not get iommu handle"); + return -EINVAL; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + memset(&g_custom_hw_mgr.ctx_pool[i], 0, + sizeof(g_custom_hw_mgr.ctx_pool[i])); + INIT_LIST_HEAD(&g_custom_hw_mgr.ctx_pool[i].list); + + ctx_pool = &g_custom_hw_mgr.ctx_pool[i]; + + /* init context pool */ + INIT_LIST_HEAD(&g_custom_hw_mgr.ctx_pool[i].free_res_list); + INIT_LIST_HEAD( + &g_custom_hw_mgr.ctx_pool[i].res_list_custom_csid); + INIT_LIST_HEAD( + &g_custom_hw_mgr.ctx_pool[i].res_list_custom_cid); + for (j = 0; j < CAM_CUSTOM_HW_RES_MAX; j++) { + INIT_LIST_HEAD( + &g_custom_hw_mgr.ctx_pool[i].res_pool[j].list); + list_add_tail( + &g_custom_hw_mgr.ctx_pool[i].res_pool[j].list, + &g_custom_hw_mgr.ctx_pool[i].free_res_list); + } + + g_custom_hw_mgr.ctx_pool[i].ctx_index = i; + g_custom_hw_mgr.ctx_pool[i].hw_mgr = &g_custom_hw_mgr; + + list_add_tail(&g_custom_hw_mgr.ctx_pool[i].list, + &g_custom_hw_mgr.free_ctx_list); + } + + /* fill return structure */ + hw_mgr_intf->hw_mgr_priv = &g_custom_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_custom_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_custom_mgr_acquire_hw; + hw_mgr_intf->hw_start = cam_custom_mgr_start_hw; + hw_mgr_intf->hw_stop = cam_custom_mgr_stop_hw; + hw_mgr_intf->hw_read = cam_custom_mgr_read; + hw_mgr_intf->hw_write = cam_custom_mgr_write; + hw_mgr_intf->hw_release = cam_custom_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_custom_mgr_prepare_hw_update; + hw_mgr_intf->hw_config = cam_custom_mgr_config_hw; + + if (iommu_hdl) + *iommu_hdl = g_custom_hw_mgr.img_iommu_hdl; + + CAM_DBG(CAM_CUSTOM, "HW manager initialized"); + return 0; +} diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h new file mode 100644 index 000000000000..64f4555528bf --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_MGR_H_ +#define _CAM_CUSTOM_HW_MGR_H_ + +#include +#include "cam_custom_hw_mgr_intf.h" +#include "cam_custom_sub_mod_core.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_isp_hw.h" +#include "cam_custom_hw.h" +#include +#include + +enum cam_custom_hw_mgr_res_type { + CAM_CUSTOM_HW_SUB_MODULE, + CAM_CUSTOM_CID_HW, + CAM_CUSTOM_CSID_HW, + CAM_CUSTOM_HW_MAX, +}; + +/* Needs to be suitably defined */ +#define CAM_CUSTOM_HW_OUT_RES_MAX 1 + +/** + * struct cam_custom_hw_mgr_res - HW resources for the Custom manager + * + * @list: used by the resource list + * @res_type: Custom manager resource type + * @res_id: resource id based on the resource type for root or + * leaf resource, it matches the KMD interface port id. + * For branch resource, it is defined by the Custom HW + * layer + * @rsrc_node: isp hw layer resource for csid/cid + * @hw_res: hw layer resource array. + */ +struct cam_custom_hw_mgr_res { + struct list_head list; + enum cam_custom_hw_mgr_res_type res_type; + uint32_t res_id; + void *rsrc_node; + struct cam_custom_resource_node *hw_res; +}; + + +/** + * struct ctx_base_info - Base hardware information for the context + * + * @idx: Base resource index + * + */ +struct ctx_base_info { + uint32_t idx; +}; + + +/** + * struct cam_custom_hw_mgr_ctx - Custom HW manager ctx object + * + * @list: used by the ctx list. + * @ctx_index: acquired context id. + * @hw_mgr: Custom hw mgr which owns this context + * @ctx_in_use: flag to tell whether context is active + * @res_list_custom_csid: custom csid modules for this context + * @res_list_custom_cid: custom cid modules for this context + * @sub_hw_list: HW submodules for this context + * @free_res_list: Free resources list for the branch node + * @res_pool: memory storage for the free resource list + * @base: device base index array contain the all + * Custom HW instance associated with this ctx. + * @num_base: number of valid base data in the base array + * @init_done: indicate whether init hw is done + * @event_cb: event_cb to ctx + * @cb_priv: data sent back with event_cb + * + */ +struct cam_custom_hw_mgr_ctx { + struct list_head list; + + uint32_t ctx_index; + struct cam_custom_hw_mgr *hw_mgr; + uint32_t ctx_in_use; + + struct list_head res_list_custom_csid; + struct list_head res_list_custom_cid; + struct cam_custom_hw_mgr_res sub_hw_list[ + CAM_CUSTOM_HW_RES_MAX]; + + struct list_head free_res_list; + struct cam_custom_hw_mgr_res res_pool[CAM_CUSTOM_HW_RES_MAX]; + struct ctx_base_info base[CAM_CUSTOM_HW_SUB_MOD_MAX]; + uint32_t num_base; + bool init_done; + cam_hw_event_cb_func event_cb; + void *cb_priv; +}; + +/** + * struct cam_custom_hw_mgr - Custom HW Manager + * + * @img_iommu_hdl: iommu handle + * @custom_hw: Custom device instances array. This will be filled by + * HW layer during initialization + * @csid_devices: Custom csid device instance array + * @ctx_mutex: mutex for the hw context pool + * @free_ctx_list: free hw context list + * @used_ctx_list: used hw context list + * @ctx_pool: context storage + * + */ +struct cam_custom_hw_mgr { + int img_iommu_hdl; + struct cam_hw_intf *custom_hw[CAM_CUSTOM_HW_SUB_MOD_MAX]; + struct cam_hw_intf *csid_devices[CAM_CUSTOM_CSID_HW_MAX]; + struct mutex ctx_mutex; + struct list_head free_ctx_list; + struct list_head used_ctx_list; + struct cam_custom_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; +}; + +/** + * cam_custom_hw_mgr_init() + * + * @brief: Initialize the Custom hardware manger. This is the + * etnry functinon for the Cust HW manager. + * + * @of_node: Device node + * @hw_mgr_intf: Custom hardware manager object returned + * @iommu_hdl: Iommu handle to be returned + * + */ +int cam_custom_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); + + +/* Utility APIs */ + +/** + * cam_custom_hw_mgr_get_custom_res_state() + * + * @brief: Obtain equivalent custom rsrc state + * from isp rsrc state + * + * @in_rsrc_state: isp rsrc state + * + */ +enum cam_custom_hw_resource_state + cam_custom_hw_mgr_get_custom_res_state( + uint32_t in_rsrc_state); + +/** + * cam_custom_hw_mgr_get_isp_res_state() + * + * @brief: Obtain equivalent isp rsrc state + * from custom rsrc state + * + * @in_rsrc_state: custom rsrc state + * + */ +enum cam_isp_resource_state + cam_custom_hw_mgr_get_isp_res_state( + uint32_t in_rsrc_state); + +/** + * cam_custom_hw_mgr_get_isp_res_type() + * + * @brief: Obtain equivalent isp rsrc type + * from custom rsrc type + * + * @res_type: custom rsrc type + * + */ +enum cam_isp_resource_type + cam_custom_hw_mgr_get_isp_res_type( + enum cam_custom_hw_mgr_res_type res_type); + +#endif /* _CAM_CUSTOM_HW_MGR_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw.h b/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw.h new file mode 100644 index 000000000000..0fd557c14052 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_H_ +#define _CAM_CUSTOM_HW_H_ + +#include +#include +#include +#include + +enum cam_custom_hw_resource_state { + CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE = 0, + CAM_CUSTOM_HW_RESOURCE_STATE_AVAILABLE = 1, + CAM_CUSTOM_HW_RESOURCE_STATE_RESERVED = 2, + CAM_CUSTOM_HW_RESOURCE_STATE_INIT_HW = 3, + CAM_CUSTOM_HW_RESOURCE_STATE_STREAMING = 4, +}; + +/* + * struct cam_custom_resource_node: + * + * @Brief: Structure representing HW resource object + * + * @res_id: Unique resource ID within res_type objects + * for a particular HW + * @res_state: State of the resource + * @hw_intf: HW Interface of HW to which this resource + * belongs + * @res_priv: Private data of the resource + * @irq_handle: handle returned on subscribing for IRQ event + * @init: function pointer to init the HW resource + * @deinit: function pointer to deinit the HW resource + * @start: function pointer to start the HW resource + * @stop: function pointer to stop the HW resource + * @process_cmd: function pointer for processing commands + * specific to the resource + */ +struct cam_custom_resource_node { + uint32_t res_id; + enum cam_custom_hw_resource_state res_state; + struct cam_hw_intf *hw_intf; + void *res_priv; + int irq_handle; + + int (*init)(struct cam_custom_resource_node *rsrc_node, + void *init_args, uint32_t arg_size); + int (*deinit)(struct cam_custom_resource_node *rsrc_node, + void *deinit_args, uint32_t arg_size); + int (*start)(struct cam_custom_resource_node *rsrc_node); + int (*stop)(struct cam_custom_resource_node *rsrc_node); + int (*process_cmd)(struct cam_custom_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); +}; +#endif /* _CAM_CUSTOM_HW_H_ */ diff --git a/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw_mgr_intf.h b/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw_mgr_intf.h new file mode 100644 index 000000000000..b1fb1cb42913 --- /dev/null +++ b/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw_mgr_intf.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_MGR_INTF_H_ +#define _CAM_CUSTOM_HW_MGR_INTF_H_ + +#include +#include +#include +#include +#include "cam_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" + +#define CAM_CUSTOM_HW_TYPE_1 1 + +#define CAM_CUSTOM_HW_RES_MAX 32 + +#define CAM_CUSTOM_HW_SUB_MOD_MAX 1 +#define CAM_CUSTOM_CSID_HW_MAX 1 + +enum cam_custom_hw_event_type { + CAM_CUSTOM_EVENT_TYPE_ERROR, + CAM_CUSTOM_EVENT_BUF_DONE, +}; + +enum cam_custom_cmd_types { + CAM_CUSTOM_CMD_NONE, + CAM_CUSTOM_SET_IRQ_CB, + CAM_CUSTOM_SUBMIT_REQ, +}; + +/** + * struct cam_custom_stop_args - hardware stop arguments + * + * @stop_only Send stop only to hw drivers. No Deinit to be + * done. + */ +struct cam_custom_stop_args { + bool stop_only; +}; + +/** + * struct cam_custom_start_args - custom hardware start arguments + * + * @hw_config: Hardware configuration commands. + * @start_only Send start only to hw drivers. No init to + * be done. + * + */ +struct cam_custom_start_args { + struct cam_hw_config_args hw_config; + bool start_only; +}; + +/** + * struct cam_custom_prepare_hw_update_data - hw prepare data + * + * @packet_opcode_type: Packet header opcode in the packet header + * this opcode defines, packet is init packet or + * update packet + * + */ +struct cam_custom_prepare_hw_update_data { + uint32_t packet_opcode_type; +}; + +/** + * struct cam_custom_hw_cb_args : HW manager callback args + * + * @irq_status : irq status + * @req_info : Pointer to the request info associated with the cb + */ +struct cam_custom_hw_cb_args { + uint32_t irq_status; + struct cam_custom_sub_mod_req_to_dev *req_info; +}; + +/** + * cam_custom_hw_sub_mod_init() + * + * @Brief: Initialize Custom HW device + * + * @custom_hw: cust_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of Custom HW + */ +int cam_custom_hw_sub_mod_init(struct cam_hw_intf **custom_hw, uint32_t hw_idx); + +/** + * cam_custom_csid_hw_init() + * + * @Brief: Initialize Custom HW device + * + * @custom_hw: cust_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of Custom HW + */ +int cam_custom_csid_hw_init( + struct cam_hw_intf **custom_hw, uint32_t hw_idx); + +#endif /* _CAM_CUSTOM_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index 40c9050afbb5..551bc85ae73c 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_INTERFACE_H @@ -151,6 +151,7 @@ enum cam_req_mgr_device_error { * @FLASH : LED flash or dual LED device * @ACTUATOR : lens mover * @IFE : Image processing device + * @CUSTOM : Custom HW block * @EXTERNAL_1 : third party device * @EXTERNAL_2 : third party device * @EXTERNAL_3 : third party device @@ -162,6 +163,7 @@ enum cam_req_mgr_device_id { CAM_REQ_MGR_DEVICE_FLASH, CAM_REQ_MGR_DEVICE_ACTUATOR, CAM_REQ_MGR_DEVICE_IFE, + CAM_REQ_MGR_DEVICE_CUSTOM_HW, CAM_REQ_MGR_DEVICE_EXTERNAL_1, CAM_REQ_MGR_DEVICE_EXTERNAL_2, CAM_REQ_MGR_DEVICE_EXTERNAL_3, diff --git a/drivers/cam_utils/cam_debug_util.c b/drivers/cam_utils/cam_debug_util.c index 3c178f1e77ac..274980f8bb64 100644 --- a/drivers/cam_utils/cam_debug_util.c +++ b/drivers/cam_utils/cam_debug_util.c @@ -91,6 +91,9 @@ const char *cam_get_module_name(unsigned int module_id) case CAM_REQ: name = "CAM-REQ"; break; + case CAM_CUSTOM: + name = "CAM-CUSTOM"; + break; default: name = "CAM"; break; diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 0491e6a214ac..181a1558a904 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -38,6 +38,7 @@ /* CAM_PERF: Used for performance (clock, BW etc) logs */ #define CAM_PERF (1 << 25) +#define CAM_CUSTOM (1 << 26) #define STR_BUFFER_MAX_LENGTH 1024 -- GitLab From 9556262e87effc7735455b6e16475a699b186caa Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 5 Aug 2019 19:18:44 -0700 Subject: [PATCH 075/410] msm: camera: ife: Correct sanitary check logic Current sanitary checks for integer overflow exhibit incorrect behavior if number of RDI/paths paths are filled in as zero. This change addresses that. CRs-Fixed: 2513939 Change-Id: Ib4cf369971f2d50be0ec167ff78f46fb0d985b33 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index c9f950ca921a..941949aff311 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -4846,7 +4846,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } /* Check for integer overflow */ - if (clock_config->num_rdi != 1) { + if (clock_config->num_rdi > 1) { if (sizeof(uint64_t) > ((UINT_MAX - sizeof(struct cam_isp_clock_config)) / (clock_config->num_rdi - 1))) { @@ -4858,8 +4858,9 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } } - if (blob_size < (sizeof(struct cam_isp_clock_config) + - sizeof(uint64_t) * (clock_config->num_rdi - 1))) { + if ((clock_config->num_rdi != 0) && (blob_size < + (sizeof(struct cam_isp_clock_config) + + sizeof(uint64_t) * (clock_config->num_rdi - 1)))) { CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", blob_size, sizeof(uint32_t) * 2 + sizeof(uint64_t) * @@ -4893,7 +4894,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } /* Check for integer overflow */ - if (bw_config->num_rdi != 1) { + if (bw_config->num_rdi > 1) { if (sizeof(struct cam_isp_bw_vote) > ((UINT_MAX - sizeof(struct cam_isp_bw_config)) / (bw_config->num_rdi - 1))) { @@ -4905,9 +4906,10 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } } - if (blob_size < (sizeof(struct cam_isp_bw_config) + + if ((bw_config->num_rdi != 0) && (blob_size < + (sizeof(struct cam_isp_bw_config) + (bw_config->num_rdi - 1) * - sizeof(struct cam_isp_bw_vote))) { + sizeof(struct cam_isp_bw_vote)))) { CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", blob_size, sizeof(struct cam_isp_bw_config) + (bw_config->num_rdi - 1) * @@ -4949,7 +4951,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } /* Check for integer overflow */ - if (bw_config->num_paths != 1) { + if (bw_config->num_paths > 1) { if (sizeof(struct cam_axi_per_path_bw_vote) > ((UINT_MAX - sizeof(struct cam_isp_bw_config_v2)) / @@ -4963,8 +4965,9 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } } - if (blob_size < (sizeof(struct cam_isp_bw_config_v2) + - ((bw_config->num_paths - 1) * + if ((bw_config->num_paths != 0) && (blob_size < + (sizeof(struct cam_isp_bw_config_v2) + + (bw_config->num_paths - 1) * sizeof(struct cam_axi_per_path_bw_vote)))) { CAM_ERR(CAM_ISP, "Invalid blob size: %u, num_paths: %u, bw_config size: %lu, per_path_vote size: %lu", -- GitLab From 6678f1003b26829dd6ca17455586c6861ce96d77 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 19 Aug 2019 12:55:04 -0700 Subject: [PATCH 076/410] msm: camera: ife: Use correct enum to convert resource ID to path Currently CSID path resource enum is being used to convert resource ID to path to notify UMD of acquired resources. This change addresses this inaccuracy. CRs-Fixed: 2513939 Change-Id: I8d31904dd9b8b500c3f4504142b153151cdcee71 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 62 ++++++++++++++------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 941949aff311..708390b72db8 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1327,34 +1327,56 @@ static int cam_ife_hw_mgr_acquire_res_ife_rd_src( static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx) { - if (hw_idx == 0) - return CAM_ISP_IFE0_HW; - else if (hw_idx == 1) - return CAM_ISP_IFE1_HW; - else if (hw_idx == 2) - return CAM_ISP_IFE0_LITE_HW; - else if (hw_idx == 3) - return CAM_ISP_IFE1_LITE_HW; - else if (hw_idx == 4) - return CAM_ISP_IFE2_LITE_HW; - return 0; + uint32_t hw_version, rc = 0; + + rc = cam_cpas_get_cpas_hw_version(&hw_version); + if (!rc) { + switch (hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + case CAM_CPAS_TITAN_175_V120: + case CAM_CPAS_TITAN_175_V130: + case CAM_CPAS_TITAN_480_V100: + if (hw_idx == 0) + return CAM_ISP_IFE0_HW; + else if (hw_idx == 1) + return CAM_ISP_IFE1_HW; + else if (hw_idx == 2) + return CAM_ISP_IFE0_LITE_HW; + else if (hw_idx == 3) + return CAM_ISP_IFE1_LITE_HW; + else if (hw_idx == 4) + return CAM_ISP_IFE2_LITE_HW; + break; + default: + CAM_ERR(CAM_ISP, "Invalid hw_version: 0x%X", + hw_version); + rc = -EINVAL; + break; + } + } + + return rc; } -static int cam_convert_res_id_to_hw_path(int path, bool acquire_lcr) +static int cam_convert_res_id_to_hw_path(int res_id) { - if (path == CAM_IFE_PIX_PATH_RES_IPP && acquire_lcr) + if (res_id == CAM_ISP_HW_VFE_IN_LCR) return CAM_ISP_LCR_PATH; - else if (path == CAM_IFE_PIX_PATH_RES_PPP) + else if (res_id == CAM_ISP_HW_VFE_IN_PDLIB) return CAM_ISP_PPP_PATH; - else if (path == CAM_IFE_PIX_PATH_RES_IPP) + else if (res_id == CAM_ISP_HW_VFE_IN_CAMIF) return CAM_ISP_PXL_PATH; - else if (path == CAM_IFE_PIX_PATH_RES_RDI_0) + else if (res_id == CAM_ISP_HW_VFE_IN_RDI0) return CAM_ISP_RDI0_PATH; - else if (path == CAM_IFE_PIX_PATH_RES_RDI_1) + else if (res_id == CAM_ISP_HW_VFE_IN_RDI1) return CAM_ISP_RDI1_PATH; - else if (path == CAM_IFE_PIX_PATH_RES_RDI_2) + else if (res_id == CAM_ISP_HW_VFE_IN_RDI2) return CAM_ISP_RDI2_PATH; - else if (path == CAM_IFE_PIX_PATH_RES_RDI_3) + else if (res_id == CAM_ISP_HW_VFE_IN_RDI3) return CAM_ISP_RDI3_PATH; return 0; } @@ -1480,7 +1502,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( } acquired_hw_path[i] |= cam_convert_res_id_to_hw_path( - ife_src_res->hw_res[i]->res_id, acquire_lcr); + ife_src_res->hw_res[i]->res_id); CAM_DBG(CAM_ISP, "acquire success IFE:%d res type :0x%x res id:0x%x", -- GitLab From 72eeacf17aa5cf2d6c76b06e1511a270ae4c7bdc Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 23 Aug 2019 17:28:48 -0700 Subject: [PATCH 077/410] msm: camera: common: Change log type to WARN When a request setting could not be applied by any device on the link, it does not indicate a fatal error. It only leads to a frame drop. Changing the apply failure logs to warn as opposed to error. CRs-Fixed: 2514752 Change-Id: Idbca2dbb06b0bbb4c380264cf31b665188306396 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/cam_isp_context.c | 4 ++-- drivers/cam_req_mgr/cam_req_mgr_core.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 4144bfc62a64..718c01ec8ee5 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3841,14 +3841,14 @@ static int __cam_isp_ctx_apply_req(struct cam_context *ctx, if (ctx_ops->crm_ops.apply_req) { rc = ctx_ops->crm_ops.apply_req(ctx, apply); } else { - CAM_ERR_RATE_LIMIT(CAM_ISP, + CAM_WARN_RATE_LIMIT(CAM_ISP, "No handle function in activated substate %d", ctx_isp->substate_activated); rc = -EFAULT; } if (rc) - CAM_ERR_RATE_LIMIT(CAM_ISP, + CAM_WARN_RATE_LIMIT(CAM_ISP, "Apply failed in active substate %d rc %d", ctx_isp->substate_activated, rc); return rc; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 6a8e5fed6e67..cce35d45b581 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -631,7 +631,7 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, } } if (rc < 0) { - CAM_ERR_RATE_LIMIT(CAM_CRM, "APPLY FAILED pd %d req_id %lld", + CAM_WARN_RATE_LIMIT(CAM_CRM, "APPLY FAILED pd %d req_id %lld", dev->dev_info.p_delay, apply_req.request_id); /* Apply req failed notify already applied devs */ for (; i >= 0; i--) { -- GitLab From e8bc3c7cbca4ce790fdc8171d63e1a658cdda8c6 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 28 Aug 2019 16:05:02 -0700 Subject: [PATCH 078/410] msm: camera: ife: Add event count in error log This change adds event count in the error log that is printed when difference between the counts for the two full IFEs is greater than one in dual IFE mode. CRs-Fixed: 2513939 Change-Id: I4346406f36eae72e55f07bdb185a7f85566a4f37 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 708390b72db8..ad07052d7345 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6182,8 +6182,9 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( (event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "One of the VFE could not generate hw event %d", - hw_event_type); + "One of the VFE could not generate hw event %d core_0_cnt %d core_1_cnt %d", + hw_event_type, event_cnt[core_idx0], + event_cnt[core_idx1]); rc = -1; return rc; } -- GitLab From 19d814458b6d2093a65801e16b948ac8b3fe8023 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 28 Aug 2019 15:51:07 -0700 Subject: [PATCH 079/410] msm: camera: isp: Send notification to userspace ISP driver must notify the userspace when any hardware error occurs so that the userspace knows when to use the register dump. CRs-Fixed: 2513939 Change-Id: I0d9ba9a22c6f2494ba3cc837513b8989c6cc1119 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 718c01ec8ee5..bdce837a0da3 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1206,10 +1206,6 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, uint32_t error_type = error_event_data->error_type; CAM_DBG(CAM_ISP, "Enter error_type = %d", error_type); - if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) || - (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW)) - notify.error = CRM_KMD_ERR_OVERFLOW; - if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) || (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW) || @@ -1397,7 +1393,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, * and to dump relevant info */ - if (notify.error == CRM_KMD_ERR_OVERFLOW) { + if (notify.error == CRM_KMD_ERR_FATAL) { req_msg.session_hdl = ctx_isp->base->session_hdl; req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; req_msg.u.err_msg.error_type = -- GitLab From 99709eacd22fcc1e0ae840281b552b42135b4dea Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Mon, 2 Sep 2019 23:24:07 +0800 Subject: [PATCH 080/410] msm: camera: isp: Reset rdi only context flag Reset rdi only context flag during releasing device, otherwise it will affect non-rdi context at next time. CRs-Fixed: 2519406 Change-Id: I904f0cae664a7530b2b85342c9a6daba579cbccc Signed-off-by: Depeng Shao --- drivers/cam_isp/cam_isp_context.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index bdce837a0da3..c27df2ce7a93 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -2750,6 +2750,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; + ctx_isp->rdi_only_context = false; atomic64_set(&ctx_isp->state_monitor_head, -1); -- GitLab From c51b7ee477654fea9b2048bd7e118bad1bd8bdb7 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 29 Aug 2019 23:32:09 -0700 Subject: [PATCH 081/410] msm: camera: isp: Clear only the IRQ bits that are being handled Do not clear the irq bits that are not handled by the bus irq controller. Clearing all bits by buf_done irq controller may clear RUP bit without handling, resulting missing RUP. CRs-Fixed: 2519423 Change-Id: I65c5efeafbda8f5face50e8c17078269daa37767 Signed-off-by: Pavan Kumar Chilamkurthi --- .../cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 16767270a272..9cdaeaa834c9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -3800,7 +3800,7 @@ int cam_vfe_bus_ver3_init( rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, &ver3_hw_info->common_reg.irq_reg_info, - &bus_priv->common_data.bus_irq_controller, true); + &bus_priv->common_data.bus_irq_controller, false); if (rc) { CAM_ERR(CAM_ISP, "Init bus_irq_controller failed"); goto free_bus_priv; -- GitLab From 6d4c852953eca72b950d9899904331e0c5571b01 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Tue, 20 Aug 2019 14:31:19 +0530 Subject: [PATCH 082/410] msm: camera: csiphy: Update cphy 3-phase registers for lito Update register settings for 3-phase cphy operation as per hpg. CRs-Fixed: 2505587 Change-Id: Ib9392f8055f7b74044edb9634d705b9c92b0ec0d Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 119 ++++++++---------- 1 file changed, 55 insertions(+), 64 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index d99c4ee3758a..ca3d1b2e0974 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,20 +12,19 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 5, + .csiphy_common_array_size = 4, .csiphy_reset_array_size = 4, .csiphy_2ph_config_array_size = 21, - .csiphy_3ph_config_array_size = 32, + .csiphy_3ph_config_array_size = 34, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; struct csiphy_reg_t csiphy_common_reg_1_2[] = { - {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0814, 0x2A, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2[] = { @@ -290,7 +289,7 @@ struct csiphy_reg_t struct csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { - {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -322,9 +321,11 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09AC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -356,9 +357,11 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0AB0, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { - {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -390,6 +393,8 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0BB0, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -399,82 +404,68 @@ struct data_rate_settings_t data_rate_delta_table = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 12, + .data_rate_reg_array_size = 9, .csiphy_data_rate_regs = { - {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { /* (3.5 * 10**3 * 2.28) rounded value */ .bandwidth = 7980000000, - .data_rate_reg_array_size = 24, + .data_rate_reg_array_size = 18, .csiphy_data_rate_regs = { - {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, }, { /* (4.5 * 10**3 * 2.28) rounded value */ .bandwidth = 10260000000, - .data_rate_reg_array_size = 24, + .data_rate_reg_array_size = 18, .csiphy_data_rate_regs = { - {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, }, } } -- GitLab From 9653879d63607e4cd6c72f20115e55e7d1b44c6e Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Tue, 20 Aug 2019 14:53:43 +0530 Subject: [PATCH 083/410] msm: camera: csiphy: Update dphy 2-phase registers for lito Update register settings for 2-phase and 2-phase combo mode dphy as per hpg. CRs-Fixed: 2505587 Change-Id: I348c1ee3b5618e1439ab87cc33f366eda89f0f82 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 151 +++++++----------- 1 file changed, 61 insertions(+), 90 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index ca3d1b2e0974..2cf988ac0094 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,19 +12,20 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 4, + .csiphy_common_array_size = 5, .csiphy_reset_array_size = 4, - .csiphy_2ph_config_array_size = 21, + .csiphy_2ph_config_array_size = 18, .csiphy_3ph_config_array_size = 34, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; struct csiphy_reg_t csiphy_common_reg_1_2[] = { - {0x0814, 0x2A, 0x00, CSIPHY_LANE_ENABLE}, + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2[] = { @@ -52,12 +53,6 @@ struct csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -65,22 +60,19 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -88,22 +80,19 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -111,22 +100,19 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -134,22 +120,19 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -157,13 +140,16 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -171,12 +157,6 @@ struct csiphy_reg_t csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -184,22 +164,19 @@ struct csiphy_reg_t {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -207,22 +184,19 @@ struct csiphy_reg_t {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -230,22 +204,19 @@ struct csiphy_reg_t {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -253,22 +224,19 @@ struct csiphy_reg_t {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -276,13 +244,16 @@ struct csiphy_reg_t {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; -- GitLab From f648ceeca6fa7f462a885b5ad22211b34f180746 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Thu, 22 Aug 2019 16:47:48 +0530 Subject: [PATCH 084/410] msm: camera: req_mgr: Increase v4l2 queue length EIS have 6 fences per request and uses 15 frame window. On camera close it signals ~90 fences at once. This can overflow v4l2 event queue. Increase v4l2 queue length for sync events to prevent overflow. CRs-Fixed: 2498880 Change-Id: Ie886318168e326c1525b4f8be5cacc5f70d0c477 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_sync/cam_sync_private.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sync/cam_sync_private.h b/drivers/cam_sync/cam_sync_private.h index 68a9804adf45..a8612fdcd7c5 100644 --- a/drivers/cam_sync/cam_sync_private.h +++ b/drivers/cam_sync/cam_sync_private.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef __CAM_SYNC_PRIVATE_H__ @@ -25,7 +25,7 @@ #define CAM_SYNC_OBJ_NAME_LEN 64 #define CAM_SYNC_MAX_OBJS 1024 -#define CAM_SYNC_MAX_V4L2_EVENTS 50 +#define CAM_SYNC_MAX_V4L2_EVENTS 100 #define CAM_SYNC_DEBUG_FILENAME "cam_debug" #define CAM_SYNC_DEBUG_BASEDIR "cam" #define CAM_SYNC_DEBUG_BUF_SIZE 32 -- GitLab From e4be9ecbfe0f4725a215662cb278763777cfd211 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Tue, 6 Aug 2019 15:24:57 -0700 Subject: [PATCH 085/410] msm: camera: utils: Add command buffer validation for reg dump The command buffer obtained from user has several offsets and sizes that need to be validated before accessing data. Also, out buffer offsets need to be checked before writing data. Add validation checks for parameters in command buffer for reg dump. CRs-Fixed: 2501003 Change-Id: I65b37befcefbd7f739663b6142d5d0eedcab25b4 Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_utils/cam_soc_util.c | 276 ++++++++++++++++++++++--------- 1 file changed, 202 insertions(+), 74 deletions(-) diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 99e349a66c61..04f2f80b82ba 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -1830,53 +1830,81 @@ int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, static int cam_soc_util_dump_cont_reg_range( struct cam_hw_soc_info *soc_info, struct cam_reg_range_read_desc *reg_read, uint32_t base_idx, - struct cam_reg_dump_out_buffer *dump_out_buf, size_t max_out_size) + struct cam_reg_dump_out_buffer *dump_out_buf, uintptr_t cmd_buf_end) { - int i = 0; + int i = 0, rc = 0; uint32_t write_idx = 0; - if (!soc_info || !dump_out_buf) { + if (!soc_info || !dump_out_buf || !reg_read || !cmd_buf_end) { CAM_ERR(CAM_UTIL, - "Invalid input args soc_info: %pK, dump_out_buffer: %pK", - soc_info, dump_out_buf); - return -EINVAL; + "Invalid input args soc_info: %pK, dump_out_buffer: %pK reg_read: %pK cmd_buf_end: %pK", + soc_info, dump_out_buf, reg_read, cmd_buf_end); + rc = -EINVAL; + goto end; } - if (reg_read->num_values >= ((max_out_size - - (size_t)dump_out_buf->bytes_written) / sizeof(uint32_t))) { + if ((reg_read->num_values) && ((reg_read->num_values > U32_MAX / 2) || + (sizeof(uint32_t) > ((U32_MAX - + sizeof(struct cam_reg_dump_out_buffer) - + dump_out_buf->bytes_written) / + (reg_read->num_values * 2))))) { CAM_ERR(CAM_UTIL, - "Invalid num values to read: %d max values: %d bytes written: %d", - reg_read->num_values, (max_out_size / - sizeof(uint32_t)), dump_out_buf->bytes_written); - return -EINVAL; + "Integer Overflow bytes_written: [%u] num_values: [%u]", + dump_out_buf->bytes_written, reg_read->num_values); + rc = -EOVERFLOW; + goto end; + } + + if ((cmd_buf_end - (uintptr_t)dump_out_buf) <= + (uintptr_t)(sizeof(struct cam_reg_dump_out_buffer) + - sizeof(uint32_t) + dump_out_buf->bytes_written + + (reg_read->num_values * 2 * sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, + "Insufficient space in out buffer num_values: [%d] cmd_buf_end: %pK dump_out_buf: %pK", + reg_read->num_values, cmd_buf_end, + (uintptr_t)dump_out_buf); + rc = -EINVAL; + goto end; } write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); for (i = 0; i < reg_read->num_values; i++) { + if ((reg_read->offset + (i * sizeof(uint32_t))) > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + (reg_read->offset + (i * sizeof(uint32_t))), + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + dump_out_buf->dump_data[write_idx++] = reg_read->offset + - (i * 4); + (i * sizeof(uint32_t)); dump_out_buf->dump_data[write_idx++] = cam_soc_util_r(soc_info, base_idx, - (reg_read->offset + (i * 4))); + (reg_read->offset + (i * sizeof(uint32_t)))); dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); } - return 0; +end: + return rc; } static int cam_soc_util_dump_dmi_reg_range( struct cam_hw_soc_info *soc_info, struct cam_dmi_read_desc *dmi_read, uint32_t base_idx, - struct cam_reg_dump_out_buffer *dump_out_buf, size_t max_out_size) + struct cam_reg_dump_out_buffer *dump_out_buf, uintptr_t cmd_buf_end) { - int i = 0; + int i = 0, rc = 0; uint32_t write_idx = 0; - if (!soc_info || !dump_out_buf) { + if (!soc_info || !dump_out_buf || !dmi_read || !cmd_buf_end) { CAM_ERR(CAM_UTIL, "Invalid input args soc_info: %pK, dump_out_buffer: %pK", soc_info, dump_out_buf); - return -EINVAL; + rc = -EINVAL; + goto end; } if (dmi_read->num_pre_writes > CAM_REG_DUMP_DMI_CONFIG_MAX || @@ -1884,20 +1912,55 @@ static int cam_soc_util_dump_dmi_reg_range( CAM_ERR(CAM_UTIL, "Invalid number of requested writes, pre: %d post: %d", dmi_read->num_pre_writes, dmi_read->num_post_writes); - return -EINVAL; + rc = -EINVAL; + goto end; } - if (dmi_read->dmi_data_read.num_values >= ((max_out_size - - (size_t)dump_out_buf->bytes_written) / sizeof(uint32_t))) { + if ((dmi_read->num_pre_writes + dmi_read->dmi_data_read.num_values) + && ((dmi_read->num_pre_writes > U32_MAX / 2) || + (dmi_read->dmi_data_read.num_values > U32_MAX / 2) || + ((dmi_read->num_pre_writes * 2) > U32_MAX - + (dmi_read->dmi_data_read.num_values * 2)) || + (sizeof(uint32_t) > ((U32_MAX - + sizeof(struct cam_reg_dump_out_buffer) - + dump_out_buf->bytes_written) / ((dmi_read->num_pre_writes + + dmi_read->dmi_data_read.num_values) * 2))))) { CAM_ERR(CAM_UTIL, - "Invalid num values to read: %d max values: %d bytes written: %d", - dmi_read->dmi_data_read.num_values, (max_out_size / - sizeof(uint32_t)), dump_out_buf->bytes_written); - return -EINVAL; + "Integer Overflow bytes_written: [%u] num_pre_writes: [%u] num_values: [%u]", + dump_out_buf->bytes_written, dmi_read->num_pre_writes, + dmi_read->dmi_data_read.num_values); + rc = -EOVERFLOW; + goto end; + } + + if ((cmd_buf_end - (uintptr_t)dump_out_buf) <= + (uintptr_t)( + sizeof(struct cam_reg_dump_out_buffer) - sizeof(uint32_t) + + (dump_out_buf->bytes_written + + (dmi_read->num_pre_writes * 2 * sizeof(uint32_t)) + + (dmi_read->dmi_data_read.num_values * 2 * + sizeof(uint32_t))))) { + CAM_ERR(CAM_UTIL, + "Insufficient space in out buffer num_read_val: [%d] num_write_val: [%d] cmd_buf_end: %pK dump_out_buf: %pK", + dmi_read->dmi_data_read.num_values, + dmi_read->num_pre_writes, cmd_buf_end, + (uintptr_t)dump_out_buf); + rc = -EINVAL; + goto end; } write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); for (i = 0; i < dmi_read->num_pre_writes; i++) { + if (dmi_read->pre_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->pre_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + cam_soc_util_w_mb(soc_info, base_idx, dmi_read->pre_read_config[i].offset, dmi_read->pre_read_config[i].value); @@ -1908,6 +1971,16 @@ static int cam_soc_util_dump_dmi_reg_range( dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); } + if (dmi_read->dmi_data_read.offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->dmi_data_read.offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) { dump_out_buf->dump_data[write_idx++] = dmi_read->dmi_data_read.offset; @@ -1918,12 +1991,23 @@ static int cam_soc_util_dump_dmi_reg_range( } for (i = 0; i < dmi_read->num_post_writes; i++) { + if (dmi_read->post_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->post_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + cam_soc_util_w_mb(soc_info, base_idx, dmi_read->post_read_config[i].offset, dmi_read->post_read_config[i].value); } - return 0; +end: + return rc; } int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, @@ -1937,7 +2021,6 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, uintptr_t cmd_buf_end = 0; uint32_t reg_base_type = 0; size_t buf_size = 0, remain_len = 0; - size_t max_out_size = 0; struct cam_reg_dump_input_info *reg_input_info = NULL; struct cam_reg_dump_desc *reg_dump_desc = NULL; struct cam_reg_dump_out_buffer *dump_out_buf = NULL; @@ -1961,7 +2044,7 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, if (rc || !cpu_addr || (buf_size == 0)) { CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK", rc, (void *)cpu_addr); - return rc; + goto end; } CAM_DBG(CAM_UTIL, "Get cpu buf success req_id: %llu buf_size: %zu", @@ -1970,74 +2053,114 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, ((size_t)cmd_desc->offset > (buf_size - sizeof(uint32_t)))) { CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", (size_t)cmd_desc->offset); - return -EINVAL; + rc = -EINVAL; + goto end; } remain_len = buf_size - (size_t)cmd_desc->offset; - if (remain_len < (size_t)cmd_desc->length) { - CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", - (size_t)cmd_desc->length); - return -EINVAL; + if ((remain_len < (size_t)cmd_desc->size) || (cmd_desc->size < + cmd_desc->length)) { + CAM_ERR(CAM_UTIL, + "Invalid params for cmd buf len: %zu size: %zu remain_len: %zu", + (size_t)cmd_desc->length, (size_t)cmd_desc->length, + remain_len); + rc = -EINVAL; + goto end; } - cmd_buf_start = (uintptr_t)(((uint8_t *)cpu_addr) + cmd_desc->offset); - cmd_in_data_end = (uintptr_t)(((uint8_t *)cmd_buf_start) + - cmd_desc->length); - cmd_buf_end = (uintptr_t)(((uint8_t *)cmd_buf_start) + - cmd_desc->size); - if (cmd_buf_end < cmd_in_data_end) { + cmd_buf_start = cpu_addr + (uintptr_t)cmd_desc->offset; + cmd_in_data_end = cmd_buf_start + (uintptr_t)cmd_desc->length; + cmd_buf_end = cmd_buf_start + (uintptr_t)cmd_desc->size; + if ((cmd_buf_end <= cmd_buf_start) || + (cmd_in_data_end <= cmd_buf_start)) { CAM_ERR(CAM_UTIL, - "Invalid length and size for cmd buf: [%zu] [%zu]", + "Invalid length or size for cmd buf: [%zu] [%zu]", (size_t)cmd_desc->length, (size_t)cmd_desc->size); - return -EINVAL; + rc = -EINVAL; + goto end; } CAM_DBG(CAM_UTIL, "Buffer params start [%pK] input_end [%pK] buf_end [%pK]", cmd_buf_start, cmd_in_data_end, cmd_buf_end); reg_input_info = (struct cam_reg_dump_input_info *) cmd_buf_start; - if (!reg_input_info->num_dump_sets) { - CAM_ERR(CAM_UTIL, "Zero dump sets found in input info"); - return -EINVAL; + if ((reg_input_info->num_dump_sets > 1) && (sizeof(uint32_t) > + ((U32_MAX - sizeof(struct cam_reg_dump_input_info)) / + (reg_input_info->num_dump_sets - 1)))) { + CAM_ERR(CAM_UTIL, + "Integer Overflow req_id: [%llu] num_dump_sets: [%u]", + req_id, reg_input_info->num_dump_sets); + rc = -EOVERFLOW; + goto end; + } + + if ((!reg_input_info->num_dump_sets) || + ((cmd_in_data_end - cmd_buf_start) <= (uintptr_t) + (sizeof(struct cam_reg_dump_input_info) + + ((reg_input_info->num_dump_sets - 1) * sizeof(uint32_t))))) { + CAM_ERR(CAM_UTIL, + "Invalid number of dump sets, req_id: [%llu] num_dump_sets: [%u]", + req_id, reg_input_info->num_dump_sets); + rc = -EINVAL; + goto end; } CAM_DBG(CAM_UTIL, "reg_input_info req_id: %llu ctx %pK num_dump_sets: %d", req_id, ctx, reg_input_info->num_dump_sets); for (i = 0; i < reg_input_info->num_dump_sets; i++) { - if ((remain_len - sizeof(uint32_t)) <= - (size_t)reg_input_info->dump_set_offsets[i]) { + if ((cmd_in_data_end - cmd_buf_start) <= (uintptr_t) + reg_input_info->dump_set_offsets[i]) { CAM_ERR(CAM_UTIL, - "Invalid dump set offset: [%zu], remain len: [%zu]", - (size_t)reg_input_info->dump_set_offsets[i], - remain_len); - return -EINVAL; + "Invalid dump set offset: [%pK], cmd_buf_start: [%pK] cmd_in_data_end: [%pK]", + (uintptr_t)reg_input_info->dump_set_offsets[i], + cmd_buf_start, cmd_in_data_end); + rc = -EINVAL; + goto end; } reg_dump_desc = (struct cam_reg_dump_desc *) - ((uint8_t *)cmd_buf_start + - reg_input_info->dump_set_offsets[i]); - if (!reg_dump_desc->num_read_range) { - CAM_ERR(CAM_UTIL, "Zero ranges found in input info"); - return -EINVAL; + (cmd_buf_start + + (uintptr_t)reg_input_info->dump_set_offsets[i]); + if ((reg_dump_desc->num_read_range > 1) && + (sizeof(struct cam_reg_read_info) > ((U32_MAX - + sizeof(struct cam_reg_dump_desc)) / + (reg_dump_desc->num_read_range - 1)))) { + CAM_ERR(CAM_UTIL, + "Integer Overflow req_id: [%llu] num_read_range: [%u]", + req_id, reg_dump_desc->num_read_range); + rc = -EOVERFLOW; + goto end; } - if ((remain_len - sizeof(uint32_t)) - <= (size_t)reg_dump_desc->dump_buffer_offset) { + if ((!reg_dump_desc->num_read_range) || + ((cmd_in_data_end - (uintptr_t)reg_dump_desc) <= + (uintptr_t)(sizeof(struct cam_reg_dump_desc) + + ((reg_dump_desc->num_read_range - 1) * + sizeof(struct cam_reg_read_info))))) { CAM_ERR(CAM_UTIL, - "Invalid out buffer offset: [%zu], remain len: [%zu]", - (size_t)reg_dump_desc->dump_buffer_offset, - remain_len); - return -EINVAL; + "Invalid number of read ranges, req_id: [%llu] num_read_range: [%d]", + req_id, reg_dump_desc->num_read_range); + rc = -EINVAL; + goto end; + } + + if ((cmd_buf_end - cmd_buf_start) <= (uintptr_t) + (reg_dump_desc->dump_buffer_offset + + sizeof(struct cam_reg_dump_out_buffer))) { + CAM_ERR(CAM_UTIL, + "Invalid out buffer offset: [%pK], cmd_buf_start: [%pK] cmd_buf_end: [%pK]", + (uintptr_t)reg_dump_desc->dump_buffer_offset, + cmd_buf_start, cmd_buf_end); + rc = -EINVAL; + goto end; } dump_out_buf = (struct cam_reg_dump_out_buffer *) - ((uint8_t *)cmd_buf_start + - reg_dump_desc->dump_buffer_offset); + (cmd_buf_start + + (uintptr_t)reg_dump_desc->dump_buffer_offset); dump_out_buf->req_id = req_id; dump_out_buf->bytes_written = 0; - max_out_size = (size_t)(cmd_desc->size - - reg_dump_desc->dump_buffer_offset); reg_base_type = reg_dump_desc->reg_base_type; if (reg_base_type == 0 || reg_base_type > @@ -2045,7 +2168,8 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, CAM_ERR(CAM_UTIL, "Invalid Reg dump base type: %d", reg_base_type); - return -EINVAL; + rc = -EINVAL; + goto end; } rc = reg_data_cb(reg_base_type, ctx, &soc_info, ®_base_idx); @@ -2053,14 +2177,16 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, CAM_ERR(CAM_UTIL, "Reg space data callback failed rc: %d soc_info: [%pK]", rc, soc_info); - return -EINVAL; + rc = -EINVAL; + goto end; } if (reg_base_idx > soc_info->num_reg_map) { CAM_ERR(CAM_UTIL, "Invalid reg base idx: %d num reg map: %d", reg_base_idx, soc_info->num_reg_map); - return -EINVAL; + rc = -EINVAL; + goto end; } CAM_DBG(CAM_UTIL, @@ -2076,27 +2202,29 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, CAM_REG_DUMP_READ_TYPE_CONT_RANGE) { rc = cam_soc_util_dump_cont_reg_range(soc_info, ®_read_info->reg_read, reg_base_idx, - dump_out_buf, max_out_size); + dump_out_buf, cmd_buf_end); } else if (reg_read_info->type == CAM_REG_DUMP_READ_TYPE_DMI) { rc = cam_soc_util_dump_dmi_reg_range(soc_info, ®_read_info->dmi_read, reg_base_idx, - dump_out_buf, max_out_size); + dump_out_buf, cmd_buf_end); } else { CAM_ERR(CAM_UTIL, "Invalid Reg dump read type: %d", reg_read_info->type); - return -EINVAL; + rc = -EINVAL; + goto end; } if (rc) { CAM_ERR(CAM_UTIL, "Reg range read failed rc: %d reg_base_idx: %d dump_out_buf: %pK", rc, reg_base_idx, dump_out_buf); - return rc; + goto end; } } } - return 0; +end: + return rc; } -- GitLab From 4329af66bd34c6a263e48ec95b900717192fca52 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Wed, 7 Aug 2019 14:10:45 -0700 Subject: [PATCH 086/410] msm: camera: isp: Add per request reg dump to command buffer For debugging, user space may request a specified register range values to be dumped to a command buffer every request. Add support for reg dump every request during cdm callback. Add debugfs flag for making sure per request dump is not enabled by mistake. CRs-Fixed: 2501003 Change-Id: I01a0f3bb00dd122b8037d513ec331c5c08fdf372 Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 257 ++++++++++-------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 2 + .../hw_utils/cam_isp_packet_parser.c | 2 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 7 + 4 files changed, 157 insertions(+), 111 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index ad07052d7345..21e8dd00a3ca 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -58,6 +58,117 @@ static int cam_ife_hw_mgr_event_handler( uint32_t evt_id, void *evt_info); +static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, + void *hw_mgr_ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ife_hw_mgr_ctx *ctx = + (struct cam_ife_hw_mgr_ctx *) hw_mgr_ctx; + + *soc_info_ptr = NULL; + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + continue; + + switch (reg_base_type) { + case CAM_REG_DUMP_BASE_TYPE_CAMNOC: + case CAM_REG_DUMP_BASE_TYPE_ISP_LEFT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_LEFT, rc); + return rc; + } + + if (reg_base_type == CAM_REG_DUMP_BASE_TYPE_ISP_LEFT) + *reg_base_idx = 0; + else + *reg_base_idx = 1; + + *soc_info_ptr = soc_info; + break; + case CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_RIGHT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_RIGHT, rc); + return rc; + } + + *reg_base_idx = 0; + *soc_info_ptr = soc_info; + break; + default: + CAM_ERR(CAM_ISP, + "Unrecognized reg base type: %u", + reg_base_type); + return -EINVAL; + } + + break; + } + + return rc; +} + +static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, + struct cam_cmd_buf_desc *reg_dump_buf_desc, uint32_t num_reg_dump_buf, + uint32_t meta_type) +{ + int rc = 0, i; + + if (!num_reg_dump_buf || !reg_dump_buf_desc) { + CAM_DBG(CAM_ISP, + "Invalid args for reg dump req_id: [%llu] ctx idx: [%u] meta_type: [%u]", + ctx->applied_req_id, ctx->ctx_index, meta_type); + return rc; + } + + if (!atomic_read(&ctx->cdm_done)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "Reg dump values might be from more than one request"); + + for (i = 0; i < num_reg_dump_buf; i++) { + CAM_DBG(CAM_ISP, "Reg dump cmd meta data: %u req_type: %u", + reg_dump_buf_desc[i].meta_data, meta_type); + if (reg_dump_buf_desc[i].meta_data == meta_type) { + rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, + ®_dump_buf_desc[i], + ctx->applied_req_id, + cam_ife_mgr_regspace_data_cb); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u", + i, rc, ctx->applied_req_id, meta_type); + return rc; + } + } + } + + return rc; +} + static int cam_ife_notify_safe_lut_scm(bool safe_trigger) { uint32_t camera_hw_version, rc = 0; @@ -2289,6 +2400,7 @@ static int cam_ife_mgr_acquire_hw_for_ctx( void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, enum cam_cdm_cb_status status, uint64_t cookie) { + struct cam_isp_prepare_hw_update_data *hw_update_data = NULL; struct cam_ife_hw_mgr_ctx *ctx = NULL; if (!userdata) { @@ -2296,11 +2408,18 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, return; } - ctx = userdata; + hw_update_data = (struct cam_isp_prepare_hw_update_data *)userdata; + ctx = (struct cam_ife_hw_mgr_ctx *)hw_update_data->ife_mgr_ctx; if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { complete_all(&ctx->config_done_complete); atomic_set(&ctx->cdm_done, 1); + if (g_ife_hw_mgr.debug_cfg.per_req_reg_dump) + cam_ife_mgr_handle_reg_dump(ctx, + hw_update_data->reg_dump_buf_desc, + hw_update_data->num_reg_dump_buf, + CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST); + CAM_DBG(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", handle, userdata, status, cookie, ctx->ctx_index); @@ -3237,6 +3356,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, return -EINVAL; hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; + hw_update_data->ife_mgr_ctx = ctx; CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld", ctx, ctx->ctx_index, cfg->request_id); @@ -3282,7 +3402,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries; cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; cdm_cmd->flag = true; - cdm_cmd->userdata = ctx; + cdm_cmd->userdata = hw_update_data; cdm_cmd->cookie = cfg->request_id; for (i = 0 ; i <= cfg->num_hw_update_entries; i++) { @@ -5374,8 +5494,18 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, } goto end; - } else + } else { prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_UPDATE_DEV; + prepare_hw_data->num_reg_dump_buf = prepare->num_reg_dump_buf; + if ((prepare_hw_data->num_reg_dump_buf) && + (prepare_hw_data->num_reg_dump_buf < + CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + memcpy(prepare_hw_data->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare_hw_data->num_reg_dump_buf); + } + } /* add reg update commands */ for (i = 0; i < ctx->num_base; i++) { @@ -5529,112 +5659,6 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, } } -static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, - void *hw_mgr_ctx, struct cam_hw_soc_info **soc_info_ptr, - uint32_t *reg_base_idx) -{ - int rc = 0; - struct cam_ife_hw_mgr_res *hw_mgr_res; - struct cam_hw_soc_info *soc_info = NULL; - struct cam_ife_hw_mgr_ctx *ctx = - (struct cam_ife_hw_mgr_ctx *) hw_mgr_ctx; - - *soc_info_ptr = NULL; - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) - continue; - - switch (reg_base_type) { - case CAM_REG_DUMP_BASE_TYPE_CAMNOC: - case CAM_REG_DUMP_BASE_TYPE_ISP_LEFT: - if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]) - continue; - - rc = hw_mgr_res->hw_res[ - CAM_ISP_HW_SPLIT_LEFT]->process_cmd( - hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT], - CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, - sizeof(void *)); - if (rc) { - CAM_ERR(CAM_ISP, - "Failed in regspace data query split idx: %d rc : %d", - CAM_ISP_HW_SPLIT_LEFT, rc); - return rc; - } - - if (reg_base_type == CAM_REG_DUMP_BASE_TYPE_ISP_LEFT) - *reg_base_idx = 0; - else - *reg_base_idx = 1; - - *soc_info_ptr = soc_info; - break; - case CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT: - if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]) - continue; - - rc = hw_mgr_res->hw_res[ - CAM_ISP_HW_SPLIT_RIGHT]->process_cmd( - hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT], - CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, - sizeof(void *)); - if (rc) { - CAM_ERR(CAM_ISP, - "Failed in regspace data query split idx: %d rc : %d", - CAM_ISP_HW_SPLIT_RIGHT, rc); - return rc; - } - - *reg_base_idx = 0; - *soc_info_ptr = soc_info; - break; - default: - CAM_ERR(CAM_ISP, - "Unrecognized reg base type: %d", - reg_base_type); - return -EINVAL; - } - } - - return rc; -} - -static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, - uint32_t meta_type) -{ - int rc, i; - - if (!ctx->num_reg_dump_buf) { - CAM_DBG(CAM_ISP, - "Zero command buffers for reg dump req_id: [%llu] ctx idx: [%llu] meta_type: %d", - ctx->applied_req_id, ctx->ctx_index, meta_type); - return 0; - } - - if (!atomic_read(&ctx->cdm_done)) - CAM_WARN_RATE_LIMIT(CAM_ISP, - "Reg dump values might be from more than one request"); - - for (i = 0; i < ctx->num_reg_dump_buf; i++) { - CAM_DBG(CAM_ISP, "Reg dump cmd meta data: %d req_type: %d", - ctx->reg_dump_buf_desc[i].meta_data, meta_type); - if (ctx->reg_dump_buf_desc[i].meta_data == meta_type) { - rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, - &ctx->reg_dump_buf_desc[i], - ctx->applied_req_id, - cam_ife_mgr_regspace_data_cb); - if (rc) { - CAM_ERR(CAM_ISP, - "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %d", - i, rc, ctx->applied_req_id, meta_type); - return -EINVAL; - } - } - } - - return 0; -} - static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -5713,7 +5737,8 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) } ctx->last_dump_flush_req_id = ctx->applied_req_id; - rc = cam_ife_mgr_handle_reg_dump(ctx, + rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, + ctx->num_reg_dump_buf, CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH); if (rc) { CAM_ERR(CAM_ISP, @@ -5728,7 +5753,8 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) return 0; ctx->last_dump_err_req_id = ctx->applied_req_id; - rc = cam_ife_mgr_handle_reg_dump(ctx, + rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, + ctx->num_reg_dump_buf, CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR); if (rc) { CAM_ERR(CAM_ISP, @@ -6544,6 +6570,15 @@ static int cam_ife_hw_mgr_debug_register(void) CAM_ERR(CAM_ISP, "failed to create cam_ife_camif_debug"); goto err; } + + if (!debugfs_create_bool("per_req_reg_dump", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.per_req_reg_dump)) { + CAM_ERR(CAM_ISP, "failed to create per_req_reg_dump entry"); + goto err; + } + g_ife_hw_mgr.debug_cfg.enable_recovery = 0; return 0; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 05ee264e93c9..7e6b91bab916 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -83,6 +83,7 @@ struct ctx_base_info { * @enable_recovery: enable recovery * @enable_diag_sensor_status: enable sensor diagnosis status * @enable_req_dump: Enable request dump on HW errors + * @per_req_reg_dump: Enable per request reg dump * */ struct cam_ife_hw_mgr_debug { @@ -91,6 +92,7 @@ struct cam_ife_hw_mgr_debug { uint32_t enable_recovery; uint32_t camif_debug; bool enable_req_dump; + bool per_req_reg_dump; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 48928bccc472..b57500c16653 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -422,6 +422,7 @@ int cam_isp_add_command_buffers( break; case CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH: case CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR: + case CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST: if (split_id == CAM_ISP_HW_SPLIT_LEFT) { if (prepare->num_reg_dump_buf >= CAM_REG_DUMP_MAX_BUF_ENTRIES) { @@ -430,6 +431,7 @@ int cam_isp_add_command_buffers( prepare->num_reg_dump_buf); return -EINVAL; } + prepare->reg_dump_buf_desc[ prepare->num_reg_dump_buf] = cmd_desc[i]; diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index fb39c02e25c8..6d5d0fd61c88 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -115,6 +115,7 @@ struct cam_isp_bw_config_internal { /** * struct cam_isp_prepare_hw_update_data - hw prepare data * + * @ife_mgr_ctx: IFE HW manager Context for current request * @packet_opcode_type: Packet header opcode in the packet header * this opcode defines, packet is init packet or * update packet @@ -123,14 +124,20 @@ struct cam_isp_bw_config_internal { * @bw_config_v2: BW config info for AXI bw voting v2 * @bw_config_valid: Flag indicating whether the bw_config at the index * is valid or not + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc * */ struct cam_isp_prepare_hw_update_data { + struct cam_ife_hw_mgr_ctx *ife_mgr_ctx; uint32_t packet_opcode_type; uint32_t bw_config_version; struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; struct cam_isp_bw_config_internal_v2 bw_config_v2[CAM_IFE_HW_NUM_MAX]; bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; }; -- GitLab From 3ef8ba0db6d1c3921e8e8803ce9ff3893176f318 Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Thu, 25 Apr 2019 21:18:33 +0530 Subject: [PATCH 087/410] msm: camera: common: Add validation check for cpu buffers before accessing Add validation check before accessing the packets and configs from the buffers. CRs-Fixed: 2360223, 2416463 Change-Id: I9a09bc7064fd7e7914f91576542181c301db926d Signed-off-by: Abhilash Kumar Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_cdm/cam_cdm_hw_core.c | 11 +++++++++++ drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 12 +++++++++++- drivers/cam_icp/cam_icp_context.c | 18 ++++++++++++++++++ .../cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 14 ++++++++++++++ drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 8 ++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index bf251a823819..3e84e2049554 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -473,6 +473,17 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if ((!rc) && (hw_vaddr_ptr) && (len) && (len >= cdm_cmd->cmd[i].offset)) { + + if ((len - cdm_cmd->cmd[i].offset) < + cdm_cmd->cmd[i].len) { + CAM_ERR(CAM_CDM, + "Not enough buffer cmd offset: %u cmd length: %u", + cdm_cmd->cmd[i].offset, + cdm_cmd->cmd[i].len); + rc = -EINVAL; + break; + } + CAM_DBG(CAM_CDM, "Got the HW VA"); if (core->bl_tag >= (CAM_CDM_HWFIFO_SIZE - 1)) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index fad7caff6437..b33dfa699647 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -582,13 +582,23 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, iommu_hdl, &io_addr[plane], &size); if (rc) { CAM_ERR(CAM_FD, - "Invalid io buf %d %d %d %d", + "Failed to get io buf %u %u %u %d", io_cfg[i].direction, io_cfg[i].resource_type, plane, rc); return -ENOMEM; } + if (io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_FD, + "Invalid io buf %u %u %u %d %u %zu", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + i, io_cfg[i].offsets[plane], + size); + return -EINVAL; + } + io_addr[plane] += io_cfg[i].offsets[plane]; } diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index ec23a6ee9d96..34c5a60fe826 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -129,6 +129,7 @@ static int __cam_icp_config_dev_in_ready(struct cam_context *ctx, size_t len; uintptr_t packet_addr; struct cam_packet *packet; + size_t remain_len = 0; rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, &packet_addr, &len); @@ -139,9 +140,26 @@ static int __cam_icp_config_dev_in_ready(struct cam_context *ctx, return rc; } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, + "Invalid offset, len: %zu cmd offset: %llu sizeof packet: %zu", + len, cmd->offset, sizeof(struct cam_packet)); + return -EINVAL; + } + + remain_len -= (size_t)cmd->offset; packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); + rc = cam_packet_util_validate_packet(packet, remain_len); + if (rc) { + CAM_ERR(CAM_CTXT, "Invalid packet params, remain length: %zu", + remain_len); + return rc; + } + if (((packet->header.op_code & 0xff) == CAM_ICP_OPCODE_IPE_SETTINGS) || ((packet->header.op_code & 0xff) == 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 c1ec110ea1d5..a63c7f72bb31 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 @@ -3853,6 +3853,9 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + rc = cam_packet_util_validate_cmd_desc(cmd_desc); + if (rc) + return rc; *fw_cmd_buf_iova_addr = 0; for (i = 0; i < packet->num_cmd_buf; i++, num_cmd_buf++) { @@ -3868,6 +3871,17 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, return rc; } *fw_cmd_buf_iova_addr = addr; + + if ((cmd_desc[i].offset >= len) || + ((len - cmd_desc[i].offset) < + cmd_desc[i].size)){ + CAM_ERR(CAM_ICP, + "Invalid offset, i: %d offset: %u len: %zu size: %zu", + i, cmd_desc[i].offset, + len, cmd_desc[i].size); + return -EINVAL; + } + *fw_cmd_buf_iova_addr = (*fw_cmd_buf_iova_addr + cmd_desc[i].offset); rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index b395bc396c70..c9ec8d1b39f1 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -149,6 +149,14 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) cmd_buf_kaddr = (uint32_t *)kaddr; + if ((p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset / + sizeof(uint32_t)) >= cmd_buf_len) { + CAM_ERR(CAM_JPEG, "Invalid offset: %u cmd buf len: %zu", + p_cfg_req->hw_cfg_args.hw_update_entries[ + CAM_JPEG_PARAM].offset, cmd_buf_len); + return -EINVAL; + } + cmd_buf_kaddr = (cmd_buf_kaddr + (p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset -- GitLab From b8e35c3397f09696cc87e6f2625d3ada6782e87e Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 20 Aug 2019 15:07:50 -0700 Subject: [PATCH 088/410] msm: camera: common: Update AHB vote for camera drivers As part of cpas start, all drivers will now request for LOW_SVS as opposed to SVS. The drivers also scale the AHB vote based on the corresponding HW's src clk voltage. CRs-Fixed: 2507919 Change-Id: I7fd35e9dd298deb1603812f39d50e4e9390b3aac Signed-off-by: Karthik Anantha Ram --- drivers/cam_cdm/cam_cdm_core_common.c | 2 +- drivers/cam_cdm/cam_cdm_hw_core.c | 2 +- drivers/cam_cpas/cam_cpas_hw.c | 47 ++++++++++++++++--- drivers/cam_cpas/cam_cpas_hw.h | 7 ++- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c | 2 +- drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 7 ++- drivers/cam_icp/icp_hw/bps_hw/bps_core.c | 16 ++++++- drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c | 17 +++++-- .../isp_hw/ife_csid_hw/cam_ife_csid_soc.c | 2 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c | 2 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 25 ++++++++-- .../jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c | 2 +- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 2 +- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c | 2 +- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 2 +- .../cam_csiphy/cam_csiphy_core.c | 2 +- 16 files changed, 112 insertions(+), 27 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index 5401945c0e23..e903dc805ed0 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -274,7 +274,7 @@ int cam_cdm_stream_ops_internal(void *hw_priv, struct cam_axi_vote axi_vote = {0}; ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 3e84e2049554..7d0515b747a4 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -942,7 +942,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) cdm_core->cpas_handle = cpas_parms.client_handle; ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 1a7a5e2b053e..c6dddff25e2c 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -932,12 +932,14 @@ static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw, CAM_DBG(CAM_CPAS, "Required highest_level[%d]", highest_level); - rc = cam_cpas_util_vote_bus_client_level(ahb_bus_client, - highest_level); - if (rc) { - CAM_ERR(CAM_CPAS, "Failed in ahb vote, level=%d, rc=%d", - highest_level, rc); - goto unlock_bus_client; + if (cpas_core->ahb_bus_scaling_enable) { + rc = cam_cpas_util_vote_bus_client_level(ahb_bus_client, + highest_level); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in ahb vote, level=%d, rc=%d", + highest_level, rc); + goto unlock_bus_client; + } } rc = cam_soc_util_set_clk_rate_level(&cpas_hw->soc_info, highest_level); @@ -1661,6 +1663,33 @@ static int cam_cpas_util_get_internal_ops(struct platform_device *pdev, return rc; } +static int cam_cpas_util_create_debugfs( + struct cam_cpas *cpas_core) +{ + int rc = 0; + + cpas_core->dentry = debugfs_create_dir("camera_cpas", NULL); + if (!cpas_core->dentry) + return -ENOMEM; + + if (!debugfs_create_bool("ahb_bus_scaling_enable", + 0644, + cpas_core->dentry, + &cpas_core->ahb_bus_scaling_enable)) { + CAM_ERR(CAM_CPAS, + "failed to create ahb_bus_scaling_enable entry"); + rc = -ENOMEM; + goto err; + } + + return 0; + +err: + debugfs_remove_recursive(cpas_core->dentry); + cpas_core->dentry = NULL; + return rc; +} + int cam_cpas_hw_probe(struct platform_device *pdev, struct cam_hw_intf **hw_intf) { @@ -1803,6 +1832,10 @@ int cam_cpas_hw_probe(struct platform_device *pdev, if (rc) goto axi_cleanup; + rc = cam_cpas_util_create_debugfs(cpas_core); + if (rc) + CAM_WARN(CAM_CPAS, "Failed to create dentry"); + *hw_intf = cpas_hw_intf; return 0; @@ -1854,6 +1887,8 @@ int cam_cpas_hw_remove(struct cam_hw_intf *cpas_hw_intf) cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client); cam_cpas_util_client_cleanup(cpas_hw); cam_cpas_soc_deinit_resources(&cpas_hw->soc_info); + debugfs_remove_recursive(cpas_core->dentry); + cpas_core->dentry = NULL; flush_workqueue(cpas_core->work_queue); destroy_workqueue(cpas_core->work_queue); mutex_destroy(&cpas_hw->hw_mutex); diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index 7b1eda841488..2b02fc411ff4 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -181,7 +181,10 @@ struct cam_cpas_axi_port { * @axi_port: AXI port info for a specific axi index * @internal_ops: CPAS HW internal ops * @work_queue: Work queue handle - * + * @irq_count: atomic irq count + * @irq_count_wq: wait variable to ensure all irq's are handled + * @dentry: debugfs file entry + * @ahb_bus_scaling_enable: ahb scaling based on src clk corner for bus */ struct cam_cpas { struct cam_cpas_hw_caps hw_caps; @@ -199,6 +202,8 @@ struct cam_cpas { struct workqueue_struct *work_queue; atomic_t irq_count; wait_queue_head_t irq_count_wq; + struct dentry *dentry; + bool ahb_bus_scaling_enable; }; int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c index 56635aa6bce4..d05530ae4e17 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c @@ -143,7 +143,7 @@ int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info) int rc; ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 2; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index 8c15000c791e..e4cb645b7af0 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -262,7 +262,7 @@ int cam_a5_init_hw(void *device_priv, a5_soc_info = soc_info->soc_private; cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; - cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE; cpas_vote.axi_vote.num_paths = 1; cpas_vote.axi_vote.axi_path[0].path_data_type = CAM_ICP_DEFAULT_AXI_PATH; @@ -521,6 +521,7 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, } case CAM_ICP_A5_CMD_CLK_UPDATE: { int32_t clk_level = 0; + struct cam_ahb_vote ahb_vote; if (!cmd_args) { CAM_ERR(CAM_ICP, "Invalid args"); @@ -536,6 +537,10 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, "Failed to update clk to level: %d rc: %d", clk_level, rc); + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_level; + cam_cpas_update_ahb_vote( + core_info->cpas_handle, &ahb_vote); break; } default: diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c index 73075a4ec379..232f29c81db6 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c @@ -70,7 +70,7 @@ int cam_bps_init_hw(void *device_priv, } cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; - cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE; cpas_vote.axi_vote.num_paths = 1; cpas_vote.axi_vote.axi_path[0].path_data_type = CAM_BPS_DEFAULT_AXI_PATH; @@ -366,7 +366,9 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ICP_BPS_CMD_UPDATE_CLK: { struct cam_a5_clk_update_cmd *clk_upd_cmd = (struct cam_a5_clk_update_cmd *)cmd_args; + struct cam_ahb_vote ahb_vote; uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + int32_t clk_level = 0, err = 0; CAM_DBG(CAM_ICP, "bps_src_clk rate = %d", (int)clk_rate); @@ -392,8 +394,20 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_bps_update_clk_rate(soc_info, clk_rate); if (rc) CAM_ERR(CAM_ICP, "Failed to update clk"); + + err = cam_soc_util_get_clk_level(soc_info, + clk_rate, soc_info->src_clk_idx, + &clk_level); + + if (!err) { + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_level; + cam_cpas_update_ahb_vote( + core_info->cpas_handle, + &ahb_vote); } break; + } case CAM_ICP_BPS_CMD_DISABLE_CLK: if (core_info->clk_enable == true) cam_bps_toggle_clk(soc_info, false); diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c index 9ea8f51bb914..a0de07833b72 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -68,7 +68,7 @@ int cam_ipe_init_hw(void *device_priv, } cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; - cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE; cpas_vote.axi_vote.num_paths = 1; cpas_vote.axi_vote.axi_path[0].path_data_type = CAM_IPE_DEFAULT_AXI_PATH; @@ -360,6 +360,7 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ICP_IPE_CMD_UPDATE_CLK: { struct cam_a5_clk_update_cmd *clk_upd_cmd = (struct cam_a5_clk_update_cmd *)cmd_args; + struct cam_ahb_vote ahb_vote; uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; int32_t clk_level = 0, err = 0; @@ -389,11 +390,17 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, CAM_ERR(CAM_ICP, "Failed to update clk"); err = cam_soc_util_get_clk_level(soc_info, - clk_rate, soc_info->src_clk_idx, - &clk_level); - if (err == 0) - clk_upd_cmd->clk_level = clk_level; + clk_rate, soc_info->src_clk_idx, + &clk_level); + if (!err) { + clk_upd_cmd->clk_level = clk_level; + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_level; + cam_cpas_update_ahb_vote( + core_info->cpas_handle, + &ahb_vote); + } break; } case CAM_ICP_IPE_CMD_DISABLE_CLK: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c index ede6dbc5ea6e..7abcc64068ee 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -125,7 +125,7 @@ int cam_ife_csid_enable_soc_resources( soc_private = soc_info->soc_private; ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c index cf899e97f326..77e2a059af57 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -232,7 +232,7 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) soc_private = soc_info->soc_private; ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; if (strnstr(soc_info->compatible, "lite", strlen(soc_info->compatible))) { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index a4fbe67aa955..743950bd01bc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -82,10 +82,14 @@ static int cam_vfe_top_ver3_set_hw_clk_rate( struct cam_vfe_top_ver3_priv *top_priv) { struct cam_hw_soc_info *soc_info = NULL; - int i, rc = 0; + struct cam_vfe_soc_private *soc_private = NULL; + struct cam_ahb_vote ahb_vote; + int i, rc = 0, clk_lvl = -1; unsigned long max_clk_rate = 0; soc_info = top_priv->common_data.soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; for (i = 0; i < top_priv->top_common.num_mux; i++) { if (top_priv->req_clk_rate[i] > max_clk_rate) @@ -100,11 +104,26 @@ static int cam_vfe_top_ver3_set_hw_clk_rate( rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); - if (!rc) + if (!rc) { top_priv->hw_clk_rate = max_clk_rate; - else + rc = cam_soc_util_get_clk_level(soc_info, max_clk_rate, + soc_info->src_clk_idx, &clk_lvl); + if (rc) { + CAM_WARN(CAM_ISP, + "Failed to get clk level for %s with clk_rate %llu src_idx %d rc %d", + soc_info->dev_name, max_clk_rate, + soc_info->src_clk_idx, rc); + rc = 0; + goto end; + } + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_lvl; + cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote); + } else { CAM_ERR(CAM_PERF, "Set Clock rate failed, rc=%d", rc); + } +end: return rc; } diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c index 31b116cc7698..1304bbc71d38 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c @@ -55,7 +55,7 @@ int cam_jpeg_dma_init_hw(void *device_priv, } ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 2; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 0b7bb7386553..4830bf58e89e 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -66,7 +66,7 @@ int cam_jpeg_enc_init_hw(void *device_priv, } ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 2; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c index ba227d2223eb..5ef984cba883 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c @@ -24,7 +24,7 @@ int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw) int rc = 0; ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 2; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index 633196c983aa..092f42bbe0d9 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -73,7 +73,7 @@ int cam_cci_init(struct v4l2_subdev *sd, } ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index f4bdfff2cb97..6755eb2954ca 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -900,7 +900,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, } ahb_vote.type = CAM_VOTE_ABSOLUTE; - ahb_vote.vote.level = CAM_SVS_VOTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; -- GitLab From 2d76f4238072adc0b2aa52318bb9b9b90d48b0a8 Mon Sep 17 00:00:00 2001 From: Prakasha Nayak Date: Fri, 13 Sep 2019 15:19:54 +0530 Subject: [PATCH 089/410] msm: camera: isp: Fix page fault dump for first request In case of page fault for first request, page fault information is not dumped since we are not initializing member variable in case of init request. CRs-Fixed: 2498880 Change-Id: Ie9ecda7434028e396392f3ac905ae80ae6ad6376 Signed-off-by: Prakasha Nayak --- drivers/cam_isp/cam_isp_context.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index c27df2ce7a93..0df3b063ce63 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -294,6 +294,9 @@ static int __cam_isp_ctx_enqueue_init_request( req_isp_new->num_cfg); req_isp_old->num_cfg += req_isp_new->num_cfg; + memcpy(&req_old->pf_data, &req->pf_data, + sizeof(struct cam_hw_mgr_dump_pf_data)); + req_old->request_id = req->request_id; list_add_tail(&req->list, &ctx->free_req_list); -- GitLab From 184ed6286f2bcc0c3532171aa5a2999a1631a655 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 19 Aug 2019 13:22:56 -0700 Subject: [PATCH 090/410] msm: camera: ife: Add support for RDI crop in dual IFE This change adds support for RDI crop in dual IFE usecases. The crop window for RDI is obtained by combining left and right IFE crop windows and width is calculated based on the crop window. If crop or drop is needed on RDI, decode format should not be programmed as payload only in order to enable RPP subpath. CRs-Fixed: 2513939 Change-Id: Iaaf64784372ef918802a684b33e16845fd7d2b3b Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 7 +- .../isp_hw/ife_csid_hw/cam_ife_csid175_200.h | 1 + .../isp_hw/ife_csid_hw/cam_ife_csid480.h | 1 + .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 108 ++++++++++++------ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 1 + 5 files changed, 82 insertions(+), 36 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 21e8dd00a3ca..8e8da8753235 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2028,7 +2028,6 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( csid_acquire.cid = cid_res->hw_res[0]->res_id; csid_acquire.in_port = in_port; csid_acquire.out_port = out_port; - csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; csid_acquire.node_res = NULL; /* @@ -2036,12 +2035,12 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( * ver 480 HW to allow userspace to control pixel drop pattern. */ csid_acquire.drop_enable = true; + csid_acquire.crop_enable = true; - /* Enable RDI crop for single ife use case only */ if (in_port->usage_type) - csid_acquire.crop_enable = false; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_MASTER; else - csid_acquire.crop_enable = true; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; hw_intf = cid_res->hw_res[0]->hw_intf; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h index 869fd8cd61c9..612379ec4bdd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h @@ -331,6 +331,7 @@ static struct cam_ife_csid_common_reg_offset .path_rst_stb_all = 0x7f, .path_rst_done_shift_val = 1, .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, .dt_id_shift_val = 27, .vc_shift_val = 22, .dt_shift_val = 16, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h index cfa8e152b4c3..66c1b32d51b0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h @@ -349,6 +349,7 @@ static struct cam_ife_csid_common_reg_offset .path_rst_stb_all = 0x7f, .path_rst_done_shift_val = 1, .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, .dt_id_shift_val = 27, .vc_shift_val = 22, .dt_shift_val = 16, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index ec41759cf50c..f3a4d967deaa 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -72,8 +72,8 @@ static int cam_ife_csid_is_ipp_ppp_format_supported( } static int cam_ife_csid_get_format_rdi( - uint32_t in_format, uint32_t out_format, - uint32_t *decode_fmt, uint32_t *plain_fmt) + uint32_t in_format, uint32_t out_format, uint32_t *decode_fmt, + uint32_t *plain_fmt, uint32_t *packing_fmt, bool rpp) { int rc = 0; @@ -82,6 +82,10 @@ static int cam_ife_csid_get_format_rdi( switch (out_format) { case CAM_FORMAT_MIPI_RAW_6: *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x0; + *packing_fmt = 0x1; + } break; case CAM_FORMAT_PLAIN8: *decode_fmt = 0x0; @@ -97,6 +101,10 @@ static int cam_ife_csid_get_format_rdi( case CAM_FORMAT_MIPI_RAW_8: case CAM_FORMAT_PLAIN128: *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x1; + *packing_fmt = 0x1; + } break; case CAM_FORMAT_PLAIN8: *decode_fmt = 0x1; @@ -112,6 +120,10 @@ static int cam_ife_csid_get_format_rdi( case CAM_FORMAT_MIPI_RAW_10: case CAM_FORMAT_PLAIN128: *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x2; + *packing_fmt = 0x1; + } break; case CAM_FORMAT_PLAIN16_10: *decode_fmt = 0x2; @@ -126,6 +138,10 @@ static int cam_ife_csid_get_format_rdi( switch (out_format) { case CAM_FORMAT_MIPI_RAW_12: *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x3; + *packing_fmt = 0x1; + } break; case CAM_FORMAT_PLAIN16_12: *decode_fmt = 0x3; @@ -140,6 +156,10 @@ static int cam_ife_csid_get_format_rdi( switch (out_format) { case CAM_FORMAT_MIPI_RAW_14: *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x4; + *packing_fmt = 0x1; + } break; case CAM_FORMAT_PLAIN16_14: *decode_fmt = 0x4; @@ -154,6 +174,10 @@ static int cam_ife_csid_get_format_rdi( switch (out_format) { case CAM_FORMAT_MIPI_RAW_16: *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x5; + *packing_fmt = 0x1; + } break; case CAM_FORMAT_PLAIN16_16: *decode_fmt = 0x5; @@ -168,6 +192,10 @@ static int cam_ife_csid_get_format_rdi( switch (out_format) { case CAM_FORMAT_MIPI_RAW_20: *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x6; + *packing_fmt = 0x1; + } break; case CAM_FORMAT_PLAIN32_20: *decode_fmt = 0x6; @@ -947,6 +975,7 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, int rc = 0, i, id; struct cam_ife_csid_path_cfg *path_data; struct cam_isp_resource_node *res; + bool is_rdi = false; /* CSID CSI2 v2.0 supports 31 vc */ if (reserve->sync_mode >= CAM_ISP_HW_SYNC_MAX) { @@ -1042,6 +1071,7 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, "CSID:%d RDI resource:%d acquire success", csid_hw->hw_intf->hw_idx, res->res_id); + is_rdi = true; } break; @@ -1113,12 +1143,21 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->start_pixel = reserve->in_port->left_start; path_data->end_pixel = reserve->in_port->left_stop; path_data->width = reserve->in_port->left_width; - CAM_DBG(CAM_ISP, "CSID:%d master:startpixel 0x%x endpixel:0x%x", - csid_hw->hw_intf->hw_idx, path_data->start_pixel, - path_data->end_pixel); - CAM_DBG(CAM_ISP, "CSID:%d master:line start:0x%x line end:0x%x", - csid_hw->hw_intf->hw_idx, path_data->start_line, - path_data->end_line); + + if (is_rdi) { + path_data->end_pixel = reserve->in_port->right_stop; + path_data->width = path_data->end_pixel - + path_data->start_pixel + 1; + } + + CAM_DBG(CAM_ISP, + "CSID:%d res:%d master:startpixel 0x%x endpixel:0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_pixel, path_data->end_pixel); + CAM_DBG(CAM_ISP, + "CSID:%d res:%d master:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_line, path_data->end_line); } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { path_data->master_idx = reserve->master_idx; CAM_DBG(CAM_ISP, "CSID:%d master_idx=%d", @@ -1126,23 +1165,29 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->start_pixel = reserve->in_port->right_start; path_data->end_pixel = reserve->in_port->right_stop; path_data->width = reserve->in_port->right_width; - CAM_DBG(CAM_ISP, "CSID:%d slave:start:0x%x end:0x%x width 0x%x", - csid_hw->hw_intf->hw_idx, path_data->start_pixel, - path_data->end_pixel, path_data->width); - CAM_DBG(CAM_ISP, "CSID:%d slave:line start:0x%x line end:0x%x", - csid_hw->hw_intf->hw_idx, path_data->start_line, - path_data->end_line); + CAM_DBG(CAM_ISP, + "CSID:%d res:%d slave:start:0x%x end:0x%x width 0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_pixel, path_data->end_pixel, + path_data->width); + CAM_DBG(CAM_ISP, + "CSID:%d res:%d slave:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_line, path_data->end_line); } else { path_data->width = reserve->in_port->left_width; path_data->start_pixel = reserve->in_port->left_start; path_data->end_pixel = reserve->in_port->left_stop; - CAM_DBG(CAM_ISP, "Res id: %d left width %d start: %d stop:%d", - reserve->res_id, reserve->in_port->left_width, + CAM_DBG(CAM_ISP, + "CSID:%d res:%d left width %d start: %d stop:%d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + reserve->in_port->left_width, reserve->in_port->left_start, reserve->in_port->left_stop); } - CAM_DBG(CAM_ISP, "Res %d width %d height %d", reserve->res_id, + CAM_DBG(CAM_ISP, "CSID:%d res:%d width %d height %d", + csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->width, path_data->height); reserve->node_res = res; @@ -2077,8 +2122,7 @@ static int cam_ife_csid_init_config_rdi_path( const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; uint32_t path_format = 0, plain_fmt = 0, val = 0, id; - uint32_t format_measure_addr; - uint32_t camera_hw_version; + uint32_t format_measure_addr, camera_hw_version, packing_fmt = 0; path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -2092,14 +2136,11 @@ static int cam_ife_csid_init_config_rdi_path( } rc = cam_ife_csid_get_format_rdi(path_data->in_format, - path_data->out_format, &path_format, &plain_fmt); + path_data->out_format, &path_format, &plain_fmt, &packing_fmt, + path_data->crop_enable || path_data->drop_enable); if (rc) return rc; - /* if path decode format is payload only then RDI crop is not applied */ - if (path_format == 0xF) - path_data->crop_enable = 0; - /* * RDI path config and enable the time stamp capture * Enable the measurement blocks @@ -2122,11 +2163,15 @@ static int cam_ife_csid_init_config_rdi_path( } CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); - if (camera_hw_version == CAM_CPAS_TITAN_480_V100) + if (camera_hw_version == CAM_CPAS_TITAN_480_V100 || + camera_hw_version == CAM_CPAS_TITAN_175_V130) { val |= (path_data->drop_enable << csid_reg->cmn_reg->drop_h_en_shift_val) | (path_data->drop_enable << - csid_reg->cmn_reg->drop_v_en_shift_val); + csid_reg->cmn_reg->drop_v_en_shift_val) | + (packing_fmt << + csid_reg->cmn_reg->packing_fmt_shift_val); + } cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); @@ -2268,7 +2313,7 @@ static int cam_ife_csid_init_config_udi_path( const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; uint32_t path_format = 0, plain_fmt = 0, val = 0, val1, id; - uint32_t format_measure_addr; + uint32_t format_measure_addr, packing_fmt = 0; path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -2282,7 +2327,8 @@ static int cam_ife_csid_init_config_udi_path( } rc = cam_ife_csid_get_format_rdi(path_data->in_format, - path_data->out_format, &path_format, &plain_fmt); + path_data->out_format, &path_format, &plain_fmt, &packing_fmt, + path_data->crop_enable || path_data->drop_enable); if (rc) { CAM_ERR(CAM_ISP, "Failed to get format in_format: %u out_format: %u rc: %d", @@ -2290,10 +2336,6 @@ static int cam_ife_csid_init_config_udi_path( return rc; } - /* if path decode format is payload only then UDI crop is not applied */ - if (path_format == 0xF) - path_data->crop_enable = false; - /* * UDI path config and enable the time stamp capture * Enable the measurement blocks @@ -2309,6 +2351,8 @@ static int cam_ife_csid_init_config_udi_path( csid_reg->cmn_reg->crop_v_en_shift_val) | (1 << 2) | 3; + val |= (packing_fmt << csid_reg->cmn_reg->packing_fmt_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index e4c8bafb6303..7bfb0dac4231 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -352,6 +352,7 @@ struct cam_ife_csid_common_reg_offset { uint32_t path_rst_stb_all; uint32_t path_rst_done_shift_val; uint32_t path_en_shift_val; + uint32_t packing_fmt_shift_val; uint32_t dt_id_shift_val; uint32_t vc_shift_val; uint32_t dt_shift_val; -- GitLab From 36765c90e872dc80252fa652ea64efd4de186628 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Thu, 5 Sep 2019 16:47:51 +0530 Subject: [PATCH 091/410] msm: camera: csiphy: Update combo-mode dphy registers for csiphy 1.2 Update register settings for combo-mode dphy to fix UNBOUNDED_FRAME csid error observed on combo-mode sensor. CRs-Fixed: 2521347 Change-Id: I363ad48fc534aa95cc810bf03a0e4704aff6d07b Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 2cf988ac0094..83260c670448 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -14,7 +14,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 5, .csiphy_reset_array_size = 4, - .csiphy_2ph_config_array_size = 18, + .csiphy_2ph_config_array_size = 19, .csiphy_3ph_config_array_size = 34, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -63,6 +63,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -83,6 +84,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -103,6 +105,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -123,6 +126,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -143,6 +147,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0600, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -167,6 +172,7 @@ struct csiphy_reg_t {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -187,6 +193,7 @@ struct csiphy_reg_t {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -207,6 +214,7 @@ struct csiphy_reg_t {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -227,6 +235,7 @@ struct csiphy_reg_t {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -247,6 +256,7 @@ struct csiphy_reg_t {0x0600, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, -- GitLab From 70c486722f5c2d4da67147b458281aaf21da1997 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Fri, 13 Sep 2019 15:52:38 -0700 Subject: [PATCH 092/410] msm: camera: common: Fix cpas register for custom hw The client handle is obtained by providing client identifier to cpas. Add identifier in custom hw registration for cpas to recognize client. Also, improve identifier string validation in cpas register client. CRs-Fixed: 2528679 Change-Id: I924f5c98a8affa26753710fa542c1bb651d0af13 Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_cpas/cam_cpas_hw.c | 6 ++++++ .../cam_custom_hw1/cam_custom_sub_mod_soc.c | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index c6dddff25e2c..dc7435516875 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1369,6 +1369,12 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + if ((!register_params) || + (strlen(register_params->identifier) < 1)) { + CAM_ERR(CAM_CPAS, "Invalid cpas client identifier"); + return -EINVAL; + } + CAM_DBG(CAM_CPAS, "Register params : identifier=%s, cell_index=%d", register_params->identifier, register_params->cell_index); diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c index 0b517b93c6c0..9011ac9d5291 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c @@ -41,17 +41,20 @@ int cam_custom_hw_sub_mod_init_soc_resources(struct cam_hw_soc_info *soc_info, memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "custom", + CAM_HW_IDENTIFIER_LENGTH); cpas_register_param.cell_index = soc_info->index; cpas_register_param.dev = soc_info->dev; cpas_register_param.cam_cpas_client_cb = NULL; cpas_register_param.userdata = soc_info; - soc_private->cpas_handle = - cpas_register_param.client_handle; rc = cam_cpas_register_client(&cpas_register_param); if (rc < 0) goto release_soc; + soc_private->cpas_handle = + cpas_register_param.client_handle; + return rc; release_soc: -- GitLab From 3aac10c09fcf9cb7e4530e0db6cb42a026e30768 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Fri, 20 Sep 2019 16:58:11 -0700 Subject: [PATCH 093/410] msm: camera: sensor: Update the flash init structure Currently there is mismatch of the cmd type byte position for the flash init structure, which casue the cmd type parsing failure for early PCR. This change move to cmd type to sixth byte to support the unificaiton with other flash uapi structures. Also, update respective header change with respect to uapi change. CRs-Fixed: 2432102 Change-Id: Ic4899b483b35013c5ad77a8894eb3bb4831de811 Signed-off-by: Jigarkumar Zala --- drivers/cam_sensor_module/cam_flash/cam_flash_dev.h | 4 ++-- include/uapi/media/cam_sensor.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index 43ed13406e3d..29e352e47ce9 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -86,7 +86,7 @@ struct cam_flash_intf_params { struct cam_flash_common_attr { bool is_settings_valid; uint64_t request_id; - uint16_t count; + uint32_t count; uint8_t cmd_type; }; @@ -97,7 +97,7 @@ struct cam_flash_common_attr { */ struct cam_flash_init_packet { struct cam_flash_common_attr cmn_attr; - uint8_t flash_type; + uint32_t flash_type; }; /** diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h index 514e8bd946cd..cc86f2706c63 100644 --- a/include/uapi/media/cam_sensor.h +++ b/include/uapi/media/cam_sensor.h @@ -401,9 +401,10 @@ struct cam_sensor_streamon_dev { * @cmd_type : command buffer type */ struct cam_flash_init { - uint8_t flash_type; - uint16_t reserved; + uint32_t flash_type; + uint8_t reserved; uint8_t cmd_type; + uint16_t reserved1; } __attribute__((packed)); /** -- GitLab From 921bdca4b05bf169195b442561d1ee825e9698d9 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Fri, 13 Sep 2019 16:03:28 +0530 Subject: [PATCH 094/410] msm: camera: isp: Skip reapply of DMI config on bubble recovery Updating same DMI bank, which is consumed by HW, can result in violations so during bubble recvery skip updating DMI config. CRs-Fixed: 2511286 Change-Id: I1af2dbf2f1b49afcd4276d3f5759e5ba6d8da637 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_core/cam_hw_mgr_intf.h | 2 ++ drivers/cam_isp/cam_isp_context.c | 7 +++++ drivers/cam_isp/cam_isp_context.h | 2 ++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 24 ++++++++++++----- .../hw_utils/cam_isp_packet_parser.c | 27 ++++++++++++------- .../hw_utils/include/cam_isp_packet_parser.h | 10 ++++++- 6 files changed, 55 insertions(+), 17 deletions(-) diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 462b30119b50..33c306b2e6dc 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -234,6 +234,7 @@ struct cam_hw_stream_setttings { * @num_out_map_entries: Number of out map entries * @priv: Private pointer * @request_id: Request ID + * @reapply True if reapplying after bubble * */ struct cam_hw_config_args { @@ -245,6 +246,7 @@ struct cam_hw_config_args { void *priv; uint64_t request_id; bool init_packet; + bool reapply; }; /** diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 0df3b063ce63..0af4a5157343 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -633,6 +633,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); + req_isp->reapply = false; CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", @@ -969,6 +970,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + req_isp->reapply = true; CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); if (req_isp->bubble_report && ctx->ctx_crm_intf && @@ -1121,6 +1123,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + req_isp->reapply = true; if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { @@ -1891,6 +1894,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state( cfg.num_hw_update_entries = req_isp->num_cfg; cfg.priv = &req_isp->hw_update_data; cfg.init_packet = 0; + cfg.reapply = req_isp->reapply; rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); if (rc) { @@ -2037,6 +2041,7 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, req_isp->fence_map_out[i].sync_id = -1; } } + req_isp->reapply = false; list_add_tail(&req->list, &ctx->free_req_list); } @@ -2336,6 +2341,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + req_isp->reapply = true; CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); if (req_isp->bubble_report && ctx->ctx_crm_intf && @@ -3516,6 +3522,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, start_isp.hw_config.num_hw_update_entries = req_isp->num_cfg; start_isp.hw_config.priv = &req_isp->hw_update_data; start_isp.hw_config.init_packet = 1; + start_isp.hw_config.reapply = 0; start_isp.start_only = false; atomic_set(&ctx_isp->process_bubble, 0); diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 5aefa690697a..92db4433b429 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -108,6 +108,7 @@ struct cam_isp_ctx_irq_ops { * @bubble_report: Flag to track if bubble report is active on * current request * @hw_update_data: HW update data for this request + * @reapply: True if reapplying after bubble * */ struct cam_isp_ctx_req { @@ -124,6 +125,7 @@ struct cam_isp_ctx_req { int32_t bubble_report; struct cam_isp_prepare_hw_update_data hw_update_data; bool bubble_detected; + bool reapply; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 8e8da8753235..174b022fe004 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -3327,7 +3327,7 @@ static int cam_isp_blob_bw_update( static int cam_ife_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) { - int rc = -1, i; + int rc = -1, i, skip = 0; struct cam_hw_config_args *cfg; struct cam_hw_update_entry *cmd; struct cam_cdm_bl_request *cdm_cmd; @@ -3398,18 +3398,30 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, if (cfg->num_hw_update_entries > 0) { cdm_cmd = ctx->cdm_cmd; - cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries; cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; cdm_cmd->flag = true; cdm_cmd->userdata = hw_update_data; cdm_cmd->cookie = cfg->request_id; - for (i = 0 ; i <= cfg->num_hw_update_entries; i++) { + for (i = 0 ; i < cfg->num_hw_update_entries; i++) { cmd = (cfg->hw_update_entries + i); - cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle; - cdm_cmd->cmd[i].offset = cmd->offset; - cdm_cmd->cmd[i].len = cmd->len; + + if (cfg->reapply && + cmd->flags == CAM_ISP_IQ_BL) { + skip++; + continue; + } + + if (cmd->flags == CAM_ISP_UNUSED_BL || + cmd->flags >= CAM_ISP_BL_MAX) + CAM_ERR(CAM_ISP, "Unexpected BL type %d", + cmd->flags); + + cdm_cmd->cmd[i - skip].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i - skip].offset = cmd->offset; + cdm_cmd->cmd[i - skip].len = cmd->len; } + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip; reinit_completion(&ctx->config_done_complete); ctx->applied_req_id = cfg->request_id; diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index b57500c16653..9c95b587df26 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -63,6 +63,9 @@ int cam_isp_add_change_base( hw_entry[num_ent].handle = kmd_buf_info->handle; hw_entry[num_ent].len = get_base.cmd.used_bytes; hw_entry[num_ent].offset = kmd_buf_info->offset; + + /* Marking change base as IOCFG to reapply on bubble */ + hw_entry[num_ent].flags = CAM_ISP_IOCFG_BL; CAM_DBG(CAM_ISP, "num_ent=%d handle=0x%x, len=%u, offset=%u", num_ent, @@ -303,10 +306,8 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle, hw_entry[num_ent].len, hw_entry[num_ent].offset); - - if (cmd_meta_data == - CAM_ISP_PACKET_META_DMI_LEFT) - hw_entry[num_ent].flags = 0x1; + hw_entry[num_ent].flags = + CAM_ISP_IQ_BL; num_ent++; } @@ -324,10 +325,8 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle, hw_entry[num_ent].len, hw_entry[num_ent].offset); - - if (cmd_meta_data == - CAM_ISP_PACKET_META_DMI_RIGHT) - hw_entry[num_ent].flags = 0x1; + hw_entry[num_ent].flags = + CAM_ISP_IQ_BL; num_ent++; } break; @@ -343,8 +342,7 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle, hw_entry[num_ent].len, hw_entry[num_ent].offset); - if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON) - hw_entry[num_ent].flags = 0x1; + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; num_ent++; break; @@ -375,6 +373,7 @@ int cam_isp_add_command_buffers( rc); return rc; } + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; num_ent = prepare->num_hw_update_entries; } break; @@ -397,6 +396,7 @@ int cam_isp_add_command_buffers( rc); return rc; } + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; num_ent = prepare->num_hw_update_entries; } break; @@ -417,6 +417,7 @@ int cam_isp_add_command_buffers( "Failed in processing blobs %d", rc); return rc; } + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; num_ent = prepare->num_hw_update_entries; } break; @@ -819,6 +820,8 @@ int cam_isp_add_io_buffers( prepare->hw_update_entries[num_ent].len = io_cfg_used_bytes; prepare->hw_update_entries[num_ent].offset = kmd_buf_info->offset; + prepare->hw_update_entries[num_ent].flags = + CAM_ISP_IOCFG_BL; CAM_DBG(CAM_ISP, "num_ent=%d handle=0x%x, len=%u, offset=%u", num_ent, @@ -919,6 +922,10 @@ int cam_isp_add_reg_update( prepare->hw_update_entries[num_ent].len = reg_update_size; prepare->hw_update_entries[num_ent].offset = kmd_buf_info->offset; + + /* Marking reg update as IOCFG to reapply on bubble */ + prepare->hw_update_entries[num_ent].flags = + CAM_ISP_IOCFG_BL; CAM_DBG(CAM_ISP, "num_ent=%d handle=0x%x, len=%u, offset=%u", num_ent, diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h index 50161ea001f5..c9bd4c4430e9 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_PARSER_H_ @@ -13,6 +13,14 @@ #include "cam_hw_intf.h" #include "cam_packet_util.h" +/* enum cam_isp_cdm_bl_type - isp cdm packet type*/ +enum cam_isp_cdm_bl_type { + CAM_ISP_UNUSED_BL, + CAM_ISP_IQ_BL, + CAM_ISP_IOCFG_BL, + CAM_ISP_BL_MAX, +}; + /* * struct cam_isp_generic_blob_info * -- GitLab From 68c8d11ebac1a1b7851f0fd77eb6bab8e9cedf28 Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Wed, 21 Aug 2019 11:32:15 +0530 Subject: [PATCH 095/410] msm: camera: config: Add support for BENGAL target Add camera config support for BENGAL target. CRs-Fixed: 2531589 Change-Id: Ie0afa4acdcdcde2286a56f802b4f8246e711503f Signed-off-by: Suresh Vankadara --- Makefile | 9 +++++++++ config/bengalcamera.conf | 4 ++++ config/bengalcameraconf.h | 7 +++++++ 3 files changed, 20 insertions(+) create mode 100644 config/bengalcamera.conf create mode 100644 config/bengalcameraconf.h diff --git a/Makefile b/Makefile index b7c0d7853cc7..9e0b13785b58 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,10 @@ ifeq ($(CONFIG_ARCH_LITO), y) include $(srctree)/techpack/camera/config/litocamera.conf endif +ifeq ($(CONFIG_ARCH_BENGAL), y) +include $(srctree)/techpack/camera/config/bengalcamera.conf +endif + ifeq ($(CONFIG_ARCH_KONA), y) LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/konacameraconf.h @@ -19,6 +23,11 @@ LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/litocameraconf.h endif +ifeq ($(CONFIG_ARCH_BENGAL), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/bengalcameraconf.h +endif + ifdef CONFIG_SPECTRA_CAMERA # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE += \ diff --git a/config/bengalcamera.conf b/config/bengalcamera.conf new file mode 100644 index 000000000000..451723eebce3 --- /dev/null +++ b/config/bengalcamera.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2019, The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA=y diff --git a/config/bengalcameraconf.h b/config/bengalcameraconf.h new file mode 100644 index 000000000000..1a7714018004 --- /dev/null +++ b/config/bengalcameraconf.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 + -- GitLab From af2756b88fba34d61367476d23421ab10eac229a Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Mon, 9 Sep 2019 20:26:37 -0700 Subject: [PATCH 096/410] msm: camera: jpeg: Fix jpeg hw hang after flush Add block formatter reset bit missing from reset cmd. CRs-Fixed: 2525580 Change-Id: I17afb362d945952ae63c50621058f1c5748281df Signed-off-by: Suraj Dongre --- .../jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h index 79b0805d0348..e610a9e7ee03 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_ENC_HW_INFO_TITAN170_H @@ -58,7 +58,7 @@ static struct cam_jpeg_enc_device_hw_info cam_jpeg_enc_hw_info = { .int_mask_disable_all = 0x00000000, .int_mask_enable_all = 0xFFFFFFFF, .hw_cmd_start = 0x00000001, - .reset_cmd = 0x00032093, + .reset_cmd = 0x200320D3, .hw_cmd_stop = 0x00000002, }, .int_status = { -- GitLab From 68b30510379236b1e9e9949a152fd73152849ea1 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Thu, 19 Sep 2019 14:35:02 +0800 Subject: [PATCH 097/410] msm: camera: reqmgr: Add initial sync support Do the initial sync by SOF timestamp, if the gap between the initial SOF of link and the last SOF of sync link is less than half of frame druation, CRM should abandon this frame since this frame should sync with next frame of sync link. CRs-Fixed: 2492019 Change-Id: I204e3ed49bcf4ac7424aaf5109ad5ce3bc3a2789 Signed-off-by: Depeng Shao --- drivers/cam_isp/cam_isp_context.c | 6 ++ drivers/cam_req_mgr/cam_req_mgr_core.c | 93 ++++++++++++++++++++- drivers/cam_req_mgr/cam_req_mgr_core.h | 7 ++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 2 + 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 0af4a5157343..a9dc2663b96f 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -787,6 +787,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", @@ -1461,6 +1462,7 @@ static int __cam_isp_ctx_fs2_sof_in_sof_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -1637,6 +1639,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -2249,6 +2252,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -2440,6 +2444,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", @@ -2510,6 +2515,7 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index cce35d45b581..4b872824041f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -43,6 +43,9 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) link->in_msync_mode = false; link->retry_cnt = 0; link->is_shutdown = false; + link->initial_skip = true; + link->sof_timestamp = 0; + link->prev_sof_timestamp = 0; } void cam_req_mgr_handle_core_shutdown(void) @@ -689,6 +692,19 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, traverse_data.validate_only = validate_only; traverse_data.open_req_cnt = link->open_req_cnt; + /* + * Some no-sync mode requests are processed after link config, + * then process the sync mode requests after no-sync mode requests + * are handled, the initial_skip should be false when processing + * the sync mode requests. + */ + if (link->initial_skip) { + CAM_DBG(CAM_CRM, + "Set initial_skip to false for link %x", + link->link_hdl); + link->initial_skip = false; + } + /* * Traverse through all pd tables, if result is success, * apply the settings @@ -982,6 +998,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( int64_t req_id = 0; int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; + uint64_t sync_frame_duration = 0; bool ready = true, sync_ready = true; if (!link->sync_link) { @@ -997,6 +1014,57 @@ static int __cam_req_mgr_check_sync_req_is_ready( "link_hdl %x req %lld frame_skip_flag %d ", link->link_hdl, req_id, link->sync_link_sof_skip); + if (sync_link->initial_skip) { + link->initial_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "sync link %x not streamed on", + sync_link->link_hdl); + return -EAGAIN; + } + + if (sync_link->prev_sof_timestamp) + sync_frame_duration = sync_link->sof_timestamp - + sync_link->prev_sof_timestamp; + else + sync_frame_duration = DEFAULT_FRAME_DURATION; + + CAM_DBG(CAM_CRM, + "sync link %x last frame_duration is %d ns", + sync_link->link_hdl, sync_frame_duration); + + if (link->initial_skip) { + link->initial_skip = false; + + if ((link->sof_timestamp > sync_link->sof_timestamp) && + (sync_link->sof_timestamp > 0) && + (link->sof_timestamp - sync_link->sof_timestamp) < + (sync_frame_duration / 2)) { + /* + * If this frame sync with the previous frame of sync + * link, then we need to skip this frame, since the + * previous frame of sync link is also skipped. + */ + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "This frame sync with previous sync_link %x frame", + sync_link->link_hdl); + return -EAGAIN; + } else if (link->sof_timestamp <= sync_link->sof_timestamp) { + /* + * Sometimes, link receives the SOF event is eariler + * than sync link in IFE CSID side, but link's SOF + * event is processed later than sync link's, then + * we need to skip this SOF event since the sync + * link's SOF event is also skipped. + */ + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "The previous frame of sync link is skipped"); + return -EAGAIN; + } + } + if (sync_link->sync_link_sof_skip) { CAM_DBG(CAM_REQ, "No req applied on corresponding SOF on sync link: %x", @@ -1097,10 +1165,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( * */ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, - uint32_t trigger) + struct cam_req_mgr_trigger_notify *trigger_data) { int rc = 0, idx; int reset_step = 0; + uint32_t trigger = trigger_data->trigger; struct cam_req_mgr_slot *slot = NULL; struct cam_req_mgr_req_queue *in_q; struct cam_req_mgr_core_session *session; @@ -1139,6 +1208,13 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, } if (trigger == CAM_TRIGGER_POINT_SOF) { + /* + * Update the timestamp in session lock protection + * to avoid timing issue. + */ + link->prev_sof_timestamp = link->sof_timestamp; + link->sof_timestamp = trigger_data->sof_timestamp_val; + if (link->trigger_mask) { CAM_ERR_RATE_LIMIT(CAM_CRM, "Applying for last EOF fails"); @@ -2225,7 +2301,7 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); } - rc = __cam_req_mgr_process_req(link, trigger_data->trigger); + rc = __cam_req_mgr_process_req(link, trigger_data); release_lock: mutex_unlock(&link->req.lock); @@ -2456,6 +2532,7 @@ static int cam_req_mgr_cb_notify_trigger( notify_trigger->link_hdl = trigger_data->link_hdl; notify_trigger->dev_hdl = trigger_data->dev_hdl; notify_trigger->trigger = trigger_data->trigger; + notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val; task->process_cb = &cam_req_mgr_process_trigger; rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); @@ -3215,8 +3292,6 @@ int cam_req_mgr_sync_config( link1->is_master = false; link2->is_master = false; - link1->initial_skip = false; - link2->initial_skip = false; link1->in_msync_mode = false; link2->in_msync_mode = false; @@ -3227,6 +3302,16 @@ int cam_req_mgr_sync_config( link1->sync_link = link2; link2->sync_link = link1; __cam_req_mgr_set_master_link(link1, link2); + } else { + /* + * Reset below info after the mode is configured + * to NO-SYNC mode since they may be overridden + * if the sync config is invoked after SOF comes. + */ + link1->initial_skip = true; + link2->initial_skip = true; + link1->sof_timestamp = 0; + link2->sof_timestamp = 0; } cam_session->sync_mode = sync_info->sync_mode; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 3837c1cd8061..c790ce824244 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -25,6 +25,9 @@ #define MAX_SYNC_COUNT 65535 +/* Default frame rate is 30 */ +#define DEFAULT_FRAME_DURATION 33333333 + #define SYNC_LINK_SOF_CNT_MAX_LMT 1 #define MAXIMUM_LINKS_PER_SESSION 4 @@ -334,6 +337,8 @@ struct cam_req_mgr_connected_device { * the same req * @is_shutdown : Flag to indicate if link needs to be disconnected * as part of shutdown. + * @sof_timestamp_value : SOF timestamp value + * @prev_sof_timestamp : Previous SOF timestamp value */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -362,6 +367,8 @@ struct cam_req_mgr_core_link { int64_t initial_sync_req; uint32_t retry_cnt; bool is_shutdown; + uint64_t sof_timestamp; + uint64_t prev_sof_timestamp; }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index 551bc85ae73c..f4b662dd4138 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -196,12 +196,14 @@ enum cam_req_mgr_link_evt_type { * @frame_id : frame id for internal tracking * @trigger : trigger point of this notification, CRM will send apply * only to the devices which subscribe to this point. + * @sof_timestamp_val: Captured time stamp value at sof hw event */ struct cam_req_mgr_trigger_notify { int32_t link_hdl; int32_t dev_hdl; int64_t frame_id; uint32_t trigger; + uint64_t sof_timestamp_val; }; /** -- GitLab From 6b38f7e1bf78b68bb47a472c08ae944409abd2a6 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Thu, 19 Sep 2019 14:44:53 +0800 Subject: [PATCH 098/410] msm: camera: reqmgr: Verify the req of two links The req of two links should be same if current frame sync with previous frame of sync link, CRM can do self-correction based on this condition. CRs-Fixed: 2492019 Change-Id: Idb208958a850ec1fe12f12443e7ecc2e126970d8 Signed-off-by: Depeng Shao --- drivers/cam_req_mgr/cam_req_mgr_core.c | 53 ++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 4b872824041f..97e1dce27f8d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -995,7 +995,8 @@ static int __cam_req_mgr_check_sync_req_is_ready( struct cam_req_mgr_slot *slot) { struct cam_req_mgr_core_link *sync_link = NULL; - int64_t req_id = 0; + struct cam_req_mgr_slot *sync_rd_slot = NULL; + int64_t req_id = 0, sync_req_id = 0; int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; uint64_t sync_frame_duration = 0; @@ -1009,6 +1010,9 @@ static int __cam_req_mgr_check_sync_req_is_ready( sync_link = link->sync_link; req_id = slot->req_id; sync_num_slots = sync_link->req.in_q->num_slots; + sync_rd_idx = sync_link->req.in_q->rd_idx; + sync_rd_slot = &sync_link->req.in_q->slot[sync_rd_idx]; + sync_req_id = sync_rd_slot->req_id; CAM_DBG(CAM_REQ, "link_hdl %x req %lld frame_skip_flag %d ", @@ -1091,12 +1095,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( return -EAGAIN; } - sync_rd_idx = sync_link->req.in_q->rd_idx; if ((sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED) && (((sync_slot_idx - sync_rd_idx + sync_num_slots) % sync_num_slots) >= 1) && - (sync_link->req.in_q->slot[sync_rd_idx].status != + (sync_rd_slot->status != CRM_SLOT_STATUS_REQ_APPLIED)) { CAM_DBG(CAM_CRM, "Req: %lld [other link] not next req to be applied on link: %x", @@ -1129,7 +1132,14 @@ static int __cam_req_mgr_check_sync_req_is_ready( CAM_DBG(CAM_CRM, "Req: %lld ready %d sync_ready %d, ignore sync link next SOF", req_id, ready, sync_ready); - link->sync_link_sof_skip = true; + + /* + * Only skip the frames if current frame sync with + * next frame of sync link. + */ + if (link->sof_timestamp - sync_link->sof_timestamp > + sync_frame_duration / 2) + link->sync_link_sof_skip = true; return -EINVAL; } else if (ready == false) { CAM_DBG(CAM_CRM, @@ -1138,6 +1148,41 @@ static int __cam_req_mgr_check_sync_req_is_ready( return -EINVAL; } + /* + * Do the self-correction when the frames are sync, + * we consider that the frames are synced if the + * difference of two SOF timestamp less than + * (sync_frame_duration / 5). + */ + if ((link->sof_timestamp > sync_link->sof_timestamp) && + (sync_link->sof_timestamp > 0) && + (link->sof_timestamp - sync_link->sof_timestamp < + sync_frame_duration / 5) && + (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { + + /* + * This means current frame should sync with next + * frame of sync link, then the request id of in + * rd slot of two links should be same. + */ + CAM_DBG(CAM_CRM, + "link %x req_id %lld, sync_link %x req_id %lld", + link->link_hdl, req_id, + sync_link->link_hdl, sync_req_id); + + if (req_id > sync_req_id) { + CAM_DBG(CAM_CRM, + "link %x too quickly, skip this frame", + link->link_hdl); + return -EAGAIN; + } else if (req_id < sync_req_id) { + CAM_DBG(CAM_CRM, + "sync link %x too quickly, skip next frame of sync link", + sync_link->link_hdl); + link->sync_link_sof_skip = true; + } + } + CAM_DBG(CAM_REQ, "Req: %lld ready to apply on link: %x [validation successful]", req_id, link->link_hdl); -- GitLab From 2424e34228bd5cb4c3b0e02d406488ca406ec674 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Thu, 19 Sep 2019 14:20:15 +0530 Subject: [PATCH 099/410] msm: camera: isp: Register only one irq handler for rdi only context If RDI only context has two rdi ports enabled, then register single irq handler for both ports. This change help registering only one irq handlers for rdi only context. CRs-Fixed: 2521064 Change-Id: I201cf62b73dbfb20636821213afc7f2a4d6cf13c Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 18 ++++++++++++++++-- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 2 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 174b022fe004..598a836134ac 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -335,8 +335,6 @@ static int cam_ife_hw_mgr_start_hw_res( continue; hw_intf = isp_hw_res->hw_res[i]->hw_intf; if (hw_intf->hw_ops.start) { - isp_hw_res->hw_res[i]->rdi_only_ctx = - ctx->is_rdi_only_context; rc = hw_intf->hw_ops.start(hw_intf->hw_priv, isp_hw_res->hw_res[i], sizeof(struct cam_isp_resource_node)); @@ -3843,6 +3841,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) struct cam_ife_hw_mgr_res *hw_mgr_res; struct cam_isp_resource_node *rsrc_node = NULL; uint32_t i, camif_debug; + bool res_rdi_context_set = false; if (!hw_mgr_priv || !start_isp) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -3967,6 +3966,21 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) ctx->ctx_index); /* Start the IFE mux in devices */ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + switch (hw_mgr_res->res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (!res_rdi_context_set) { + hw_mgr_res->hw_res[0]->rdi_only_ctx = + ctx->is_rdi_only_context; + res_rdi_context_set = true; + } + break; + default: + break; + } + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); if (rc) { CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)", diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index 0fe61247055a..fba9f2afca21 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -225,7 +225,7 @@ int cam_vfe_camif_lite_ver3_acquire_resource( camif_lite_data->sync_mode = acquire_data->vfe_in.sync_mode; camif_lite_data->event_cb = acquire_data->event_cb; camif_lite_data->priv = acquire_data->priv; - + camif_lite_res->rdi_only_ctx = 0; CAM_DBG(CAM_ISP, "Acquired VFE:%d CAMIF LITE:%d sync_mode=%d", camif_lite_res->hw_intf->hw_idx, camif_lite_res->res_id, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 381de6b48fe9..7aaacde775f4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -201,6 +201,7 @@ int cam_vfe_rdi_ver2_acquire_resource( rdi_data->event_cb = acquire_data->event_cb; rdi_data->priv = acquire_data->priv; rdi_data->sync_mode = acquire_data->vfe_in.sync_mode; + rdi_res->rdi_only_ctx = 0; return 0; } -- GitLab From 6761d7b872b77b8e1a1caa3e34a377ea64c43974 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 20 Sep 2019 11:12:33 -0700 Subject: [PATCH 100/410] msm: camera: cpas: Change to enable bus scaling for AHB This change scales BW voting with src clock voltage corner. Adds a debugfs to disable this scaling. CRs-Fixed: 2531856 Change-Id: I266e34ca81f635954e60648366bcc4792f90fdb6 Signed-off-by: Karthik Anantha Ram --- drivers/cam_cpas/cam_cpas_hw.c | 9 +++++---- drivers/cam_cpas/cam_cpas_hw.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index dc7435516875..7ee738da4748 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -932,7 +932,7 @@ static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw, CAM_DBG(CAM_CPAS, "Required highest_level[%d]", highest_level); - if (cpas_core->ahb_bus_scaling_enable) { + if (!cpas_core->ahb_bus_scaling_disable) { rc = cam_cpas_util_vote_bus_client_level(ahb_bus_client, highest_level); if (rc) { @@ -1678,12 +1678,12 @@ static int cam_cpas_util_create_debugfs( if (!cpas_core->dentry) return -ENOMEM; - if (!debugfs_create_bool("ahb_bus_scaling_enable", + if (!debugfs_create_bool("ahb_bus_scaling_disable", 0644, cpas_core->dentry, - &cpas_core->ahb_bus_scaling_enable)) { + &cpas_core->ahb_bus_scaling_disable)) { CAM_ERR(CAM_CPAS, - "failed to create ahb_bus_scaling_enable entry"); + "failed to create ahb_bus_scaling_disable entry"); rc = -ENOMEM; goto err; } @@ -1735,6 +1735,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev, cpas_hw->soc_info.dev = &pdev->dev; cpas_hw->soc_info.dev_name = pdev->name; cpas_hw->open_count = 0; + cpas_core->ahb_bus_scaling_disable = false; mutex_init(&cpas_hw->hw_mutex); spin_lock_init(&cpas_hw->hw_lock); init_completion(&cpas_hw->hw_complete); diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index 2b02fc411ff4..b3c01b3ee737 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -184,7 +184,7 @@ struct cam_cpas_axi_port { * @irq_count: atomic irq count * @irq_count_wq: wait variable to ensure all irq's are handled * @dentry: debugfs file entry - * @ahb_bus_scaling_enable: ahb scaling based on src clk corner for bus + * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus */ struct cam_cpas { struct cam_cpas_hw_caps hw_caps; @@ -203,7 +203,7 @@ struct cam_cpas { atomic_t irq_count; wait_queue_head_t irq_count_wq; struct dentry *dentry; - bool ahb_bus_scaling_enable; + bool ahb_bus_scaling_disable; }; int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); -- GitLab From f7d89d9bed88cf60f91c712b7cc3dd8cc1b535f9 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 23 Sep 2019 15:23:30 -0700 Subject: [PATCH 101/410] msm: camera: isp: Disable tasklet once This changes avoids disabling and killing inactive tasklet. CRs-Fixed: 2530034 Change-Id: If1b0b04684f9425f742b51e5eb4b6ec8107f2c75 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index a8ff7ff01e11..458894f96a1b 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -296,6 +296,9 @@ void cam_tasklet_stop(void *tasklet_info) { struct cam_tasklet_info *tasklet = tasklet_info; + if (!atomic_read(&tasklet->tasklet_active)) + return; + atomic_set(&tasklet->tasklet_active, 0); tasklet_kill(&tasklet->tasklet); tasklet_disable(&tasklet->tasklet); -- GitLab From 00abd8fedadfa547403789512d1e7a89a84dd5d6 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 11 Sep 2019 15:54:56 -0700 Subject: [PATCH 102/410] msm: camera: isp: Add check for last flush request ID This change adds a check for last flush request ID before adding bubbled request to pending list. This prevents the request from sitting in pending list indefinitely. CRs-Fixed: 2533433 Change-Id: I82d641d42fe507e8eabf0bee0e9a2f0b98d9a802 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index a9dc2663b96f..cfb6a0accd7f 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -619,12 +619,26 @@ static int __cam_isp_ctx_handle_buf_done_for_request( req_isp->num_acked = 0; req_isp->bubble_detected = false; list_del_init(&req->list); - list_add(&req->list, &ctx->pending_req_list); atomic_set(&ctx_isp->process_bubble, 0); - CAM_DBG(CAM_REQ, - "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", - req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + if (buf_done_req_id <= ctx->last_flush_req) { + for (i = 0; i < req_isp->num_fence_map_out; i++) + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", + buf_done_req_id, ctx_isp->active_req_cnt, + ctx->ctx_id); + } else { + list_add(&req->list, &ctx->pending_req_list); + CAM_DBG(CAM_REQ, + "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", + req->request_id, ctx_isp->active_req_cnt, + ctx->ctx_id); + } } else { if (ctx_isp->reported_req_id < buf_done_req_id) { ctx_isp->reported_req_id = buf_done_req_id; -- GitLab From 0eee5ccc3f77e56063cc8652c8b6a1c1fab12a32 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 17 Sep 2019 15:49:27 -0700 Subject: [PATCH 103/410] msm: camera: icp: Handle RT/NRT flags for IPE/BPS device types The device type is only needed to create the handle with FW, internally to the KMD we can unify the different device types. CRs-Fixed: 2534504 Change-Id: I92b77f54556d840f49136ea187df939350951078 Signed-off-by: Karthik Anantha Ram --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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 a63c7f72bb31..91d87ecb3f6a 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 @@ -5061,6 +5061,9 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) goto acquire_info_failed; icp_dev_acquire_info = ctx_data->icp_dev_acquire_info; + dev_type = icp_dev_acquire_info->dev_type; + icp_dev_acquire_info->dev_type = + cam_icp_unify_dev_type(dev_type); CAM_DBG(CAM_ICP, "acquire io buf handle %d", icp_dev_acquire_info->io_config_cmd_handle); @@ -5109,7 +5112,7 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } CAM_DBG(CAM_ICP, "ping ack received"); - rc = cam_icp_mgr_create_handle(icp_dev_acquire_info->dev_type, + rc = cam_icp_mgr_create_handle(dev_type, ctx_data); if (rc) { CAM_ERR(CAM_ICP, "create handle failed"); @@ -5118,7 +5121,7 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) CAM_DBG(CAM_ICP, "created stream handle for dev_type %u", - icp_dev_acquire_info->dev_type); + dev_type); cmd_mem_region.num_regions = 1; cmd_mem_region.map_info_array[0].mem_handle = @@ -5179,13 +5182,11 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) /* Start context timer*/ cam_icp_ctx_timer_start(ctx_data); hw_mgr->ctxt_cnt++; - dev_type = cam_icp_unify_dev_type(icp_dev_acquire_info->dev_type); - icp_dev_acquire_info->dev_type = dev_type; mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_DBG(CAM_ICP, "Acquire Done for ctx_id %u dev type %d", ctx_data->ctx_id, - icp_dev_acquire_info->dev_type); + ctx_data->icp_dev_acquire_info->dev_type); return 0; -- GitLab From 3d8cdd5b7a702109caac471196fcea4edb82ec61 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 26 Sep 2019 17:46:39 -0700 Subject: [PATCH 104/410] msm: camera: ife: Assign primary RDI during start HW This change sets primary RDI source and out resources for a particular RDI only Context. This information is utilized during start HW resource to tell the driver if it should subscribe to IRQs. CRs-Fixed: 2521064 Change-Id: Ia5567b4432603db993c4783e60721be144c619f9 Signed-off-by: Vishalsingh Hajeri --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 52 ++++++++++++++----- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 1 + 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 598a836134ac..aad24ae88cc2 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1471,6 +1471,19 @@ static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx) return rc; } +static int cam_convert_rdi_out_res_id_to_src(int res_id) +{ + if (res_id == CAM_ISP_IFE_OUT_RES_RDI_0) + return CAM_ISP_HW_VFE_IN_RDI0; + else if (res_id == CAM_ISP_IFE_OUT_RES_RDI_1) + return CAM_ISP_HW_VFE_IN_RDI1; + else if (res_id == CAM_ISP_IFE_OUT_RES_RDI_2) + return CAM_ISP_HW_VFE_IN_RDI2; + else if (res_id == CAM_ISP_IFE_OUT_RES_RDI_3) + return CAM_ISP_HW_VFE_IN_RDI3; + return CAM_ISP_HW_VFE_IN_MAX; +} + static int cam_convert_res_id_to_hw_path(int res_id) { if (res_id == CAM_ISP_HW_VFE_IN_LCR) @@ -3842,6 +3855,11 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) struct cam_isp_resource_node *rsrc_node = NULL; uint32_t i, camif_debug; bool res_rdi_context_set = false; + uint32_t primary_rdi_src_res; + uint32_t primary_rdi_out_res; + + primary_rdi_src_res = CAM_ISP_HW_VFE_IN_MAX; + primary_rdi_out_res = CAM_ISP_IFE_OUT_RES_MAX; if (!hw_mgr_priv || !start_isp) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -3941,6 +3959,22 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) ctx->ctx_index); /* start the IFE out devices */ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + hw_mgr_res = &ctx->res_list_ife_out[i]; + switch (hw_mgr_res->res_id) { + case CAM_ISP_IFE_OUT_RES_RDI_0: + case CAM_ISP_IFE_OUT_RES_RDI_1: + case CAM_ISP_IFE_OUT_RES_RDI_2: + case CAM_ISP_IFE_OUT_RES_RDI_3: + if (!res_rdi_context_set && ctx->is_rdi_only_context) { + hw_mgr_res->hw_res[0]->rdi_only_ctx = + ctx->is_rdi_only_context; + res_rdi_context_set = true; + primary_rdi_out_res = hw_mgr_res->res_id; + } + break; + default: + break; + } rc = cam_ife_hw_mgr_start_hw_res( &ctx->res_list_ife_out[i], ctx); if (rc) { @@ -3962,23 +3996,17 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } } + if (primary_rdi_out_res < CAM_ISP_IFE_OUT_RES_MAX) + primary_rdi_src_res = + cam_convert_rdi_out_res_id_to_src(primary_rdi_out_res); + CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index); /* Start the IFE mux in devices */ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - switch (hw_mgr_res->res_id) { - case CAM_ISP_HW_VFE_IN_RDI0: - case CAM_ISP_HW_VFE_IN_RDI1: - case CAM_ISP_HW_VFE_IN_RDI2: - case CAM_ISP_HW_VFE_IN_RDI3: - if (!res_rdi_context_set) { - hw_mgr_res->hw_res[0]->rdi_only_ctx = + if (primary_rdi_src_res == hw_mgr_res->res_id) { + hw_mgr_res->hw_res[0]->rdi_only_ctx = ctx->is_rdi_only_context; - res_rdi_context_set = true; - } - break; - default: - break; } rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 9cdaeaa834c9..09407894b52a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -1971,6 +1971,7 @@ static int cam_vfe_bus_ver3_acquire_vfe_out(void *bus_priv, void *acquire_args, ver3_bus_priv->tasklet_info = acq_args->tasklet; rsrc_data->num_wm = num_wm; + rsrc_node->rdi_only_ctx = 0; rsrc_node->res_id = out_acquire_args->out_port_info->res_type; rsrc_node->tasklet_info = acq_args->tasklet; rsrc_node->cdm_ops = out_acquire_args->cdm_ops; -- GitLab From a5dc6c6caca6579ad4d846f58b7ebf6845abad3b Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 15 Aug 2019 13:07:05 -0700 Subject: [PATCH 105/410] msm: camera: ife: Do not enable CAMIF by default This change removes enabling CAMIF and CAMIF Lite module config programming by default. Henceforth these settings must be programmed by the userspace by adding them in command buffers. CRs-Fixed: 2513939 Change-Id: I739a57a392974056f358820f77bc2ae40451d9d6 Signed-off-by: Venkat Chinta --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 4 ---- .../isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 9 --------- 2 files changed, 13 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index fba9f2afca21..495e4afbd50a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -294,10 +294,6 @@ static int cam_vfe_camif_lite_resource_start( rsrc_data->camif_lite_reg->lite_epoch_irq); skip_core_cfg: - /* Enable Camif */ - cam_io_w_mb(0x1, - rsrc_data->mem_base + - rsrc_data->camif_lite_reg->lite_module_config); camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 8cf2fa9f7f93..c390b6f542d4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -377,15 +377,6 @@ static int cam_vfe_camif_ver3_resource_start( cam_io_w_mb(rsrc_data->reg_data->top_debug_cfg_en, rsrc_data->mem_base + rsrc_data->common_reg->top_debug_cfg); - /*config vfe core*/ - val = (rsrc_data->pix_pattern << - rsrc_data->reg_data->pixel_pattern_shift); - val |= (1 << rsrc_data->reg_data->pp_camif_cfg_en_shift); - val |= (1 << rsrc_data->reg_data->pp_camif_cfg_ife_out_en_shift); - cam_io_w_mb(val, - rsrc_data->mem_base + rsrc_data->camif_reg->module_cfg); - CAM_DBG(CAM_ISP, "write module_cfg val = 0x%X", val); - val = cam_io_r_mb(rsrc_data->mem_base + rsrc_data->common_reg->core_cfg_0); -- GitLab From 92a98f613795187d826ce0e2d012fbc1e1648b17 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 26 Sep 2019 19:24:40 -0700 Subject: [PATCH 106/410] msm: camera: ife: Add packing format support This change adds packing format field for CSID in IFE Lite for version 480 hardware. CRs-Fixed: 2537287 Change-Id: Ifa46b07218fefe46721f99e65291837500c413de Signed-off-by: Venkat Chinta --- .../cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h index 7d9a53567ee6..b77f2dfa350e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h @@ -305,6 +305,7 @@ static struct cam_ife_csid_common_reg_offset .path_rst_stb_all = 0x7f, .path_rst_done_shift_val = 1, .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, .dt_id_shift_val = 27, .vc_shift_val = 22, .dt_shift_val = 16, -- GitLab From aaab1ef87ebf45190016cdd36b6178795897d9d0 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Fri, 2 Aug 2019 16:03:51 -0700 Subject: [PATCH 107/410] msm: camera: isp: Stop HW immediately in flush When the userspace issues flush, ISP driver needs to ensure that wait and active list requests are flushed and corresponding buffer fences are signaled with error. For active and wait lists IFE hardware is stopped immediately. Therefore IFE must also be reset to ensure that VFE BUS FIFOs are cleared. Start IFE HW after receiving init packet again. CRs-Fixed: 2513939 Change-Id: I9a35ce05c24d6b63016e264a870d376eabb2b56f Signed-off-by: Venkat Chinta --- drivers/cam_core/cam_context.h | 5 +- drivers/cam_core/cam_hw_mgr_intf.h | 12 ++ drivers/cam_cust/cam_custom_context.c | 2 + drivers/cam_fd/cam_fd_context.c | 2 + drivers/cam_icp/cam_icp_context.c | 2 + drivers/cam_isp/cam_isp_context.c | 129 +++++++++++++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 70 ++++++++-- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 22 +-- drivers/cam_lrme/cam_lrme_context.c | 2 + 9 files changed, 216 insertions(+), 30 deletions(-) diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 854ea0067a27..2c1c685e76b8 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -32,8 +32,9 @@ enum cam_context_state { CAM_CTX_AVAILABLE = 1, CAM_CTX_ACQUIRED = 2, CAM_CTX_READY = 3, - CAM_CTX_ACTIVATED = 4, - CAM_CTX_STATE_MAX = 5, + CAM_CTX_FLUSHED = 4, + CAM_CTX_ACTIVATED = 5, + CAM_CTX_STATE_MAX = 6, }; /** diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 33c306b2e6dc..28426b8dc757 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -287,6 +287,16 @@ struct cam_hw_dump_pf_args { bool *mem_found; }; +/** + * struct cam_hw_reset_args -hw reset arguments + * + * @ctxt_to_hw_map: HW context from the acquire + * + */ +struct cam_hw_reset_args { + void *ctxt_to_hw_map; +}; + /* enum cam_hw_mgr_command - Hardware manager command type */ enum cam_hw_mgr_command { CAM_HW_MGR_CMD_INTERNAL, @@ -341,6 +351,7 @@ struct cam_hw_cmd_args { * @hw_open: Function pointer for HW init * @hw_close: Function pointer for HW deinit * @hw_flush: Function pointer for HW flush + * @hw_reset: Function pointer for HW reset * */ struct cam_hw_mgr_intf { @@ -361,6 +372,7 @@ struct cam_hw_mgr_intf { int (*hw_open)(void *hw_priv, void *fw_download_args); int (*hw_close)(void *hw_priv, void *hw_close_args); int (*hw_flush)(void *hw_priv, void *hw_flush_args); + int (*hw_reset)(void *hw_priv, void *hw_reset_args); }; #endif /* _CAM_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index 5709530f7bf3..7f38392a7d57 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/drivers/cam_cust/cam_custom_context.c @@ -874,6 +874,8 @@ static struct cam_ctx_ops .irq_ops = NULL, .pagefault_ops = NULL, }, + /* Flushed */ + {}, /* Activated */ { .ioctl_ops = { diff --git a/drivers/cam_fd/cam_fd_context.c b/drivers/cam_fd/cam_fd_context.c index 8805859abb00..ec6468f85dc0 100644 --- a/drivers/cam_fd/cam_fd_context.c +++ b/drivers/cam_fd/cam_fd_context.c @@ -189,6 +189,8 @@ static struct cam_ctx_ops .crm_ops = {}, .irq_ops = NULL, }, + /* Flushed */ + {}, /* Activated */ { .ioctl_ops = { diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 34c5a60fe826..7d2ef39e0aeb 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -250,6 +250,8 @@ static struct cam_ctx_ops .irq_ops = __cam_icp_handle_buf_done_in_ready, .pagefault_ops = cam_icp_context_dump_active_request, }, + /* Flushed */ + {}, /* Activated */ { .ioctl_ops = {}, diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index cfb6a0accd7f..2a3c6dbfcc61 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -31,6 +31,9 @@ static struct cam_isp_ctx_debug isp_ctx_debug; static int cam_isp_context_dump_active_request(void *data, unsigned long iova, uint32_t buf_info); +static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + static void __cam_isp_ctx_update_state_monitor_array( struct cam_isp_context *ctx_isp, enum cam_isp_state_change_trigger trigger_type, @@ -2072,13 +2075,15 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, } static int __cam_isp_ctx_flush_req_in_top_state( - struct cam_context *ctx, + struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) { - int rc = 0; - struct cam_isp_context *ctx_isp; - struct cam_hw_cmd_args hw_cmd_args; - + int rc = 0; + struct cam_isp_context *ctx_isp; + struct cam_isp_stop_args stop_isp; + struct cam_hw_stop_args stop_args; + struct cam_hw_reset_args reset_args; + struct cam_hw_cmd_args hw_cmd_args; ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { @@ -2087,7 +2092,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( ctx->last_flush_req = flush_req->req_id; } - CAM_DBG(CAM_ISP, "try to flush pending list"); + CAM_DBG(CAM_ISP, "Flush pending list"); spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); @@ -2102,6 +2107,47 @@ static int __cam_isp_ctx_flush_req_in_top_state( rc = 0; } + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + if (ctx->state <= CAM_CTX_READY) { + ctx->state = CAM_CTX_ACQUIRED; + goto end; + } + + stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + stop_isp.stop_only = true; + stop_args.args = (void *)&stop_isp; + rc = ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop_args); + if (rc) + CAM_ERR(CAM_ISP, "Failed to stop HW in Flush rc: %d", + rc); + + CAM_DBG(CAM_ISP, "Flush wait and active lists"); + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->wait_req_list)) + rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, + flush_req); + + if (!list_empty(&ctx->active_req_list)) + rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, + flush_req); + + ctx_isp->active_req_cnt = 0; + spin_unlock_bh(&ctx->lock); + + reset_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + rc = ctx->hw_mgr_intf->hw_reset(ctx->hw_mgr_intf->hw_mgr_priv, + &reset_args); + if (rc) + CAM_ERR(CAM_ISP, "Failed to reset HW rc: %d", rc); + + ctx->state = CAM_CTX_FLUSHED; + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; + ctx_isp->init_received = false; + } + +end: atomic_set(&ctx_isp->process_bubble, 0); return rc; } @@ -3454,6 +3500,55 @@ static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_isp_ctx_config_dev_in_flushed(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_start_stop_dev_cmd start_cmd; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + if (!ctx_isp->hw_acquired) { + CAM_ERR(CAM_ISP, "HW is not acquired, reject packet"); + return -EINVAL; + } + + rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd); + if (rc) + return rc; + + if (!ctx_isp->init_received) { + CAM_WARN(CAM_ISP, + "Received update packet in flushed state, skip start"); + goto end; + } + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_RESUME_HW; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to resume HW rc: %d", rc); + return rc; + } + + start_cmd.dev_handle = cmd->dev_handle; + start_cmd.session_handle = cmd->session_handle; + rc = __cam_isp_ctx_start_dev_in_ready(ctx, &start_cmd); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to re-start HW after flush rc: %d", rc); + +end: + CAM_DBG(CAM_ISP, "next state %d sub_state:%d", ctx->state, + ctx_isp->substate_activated); + return rc; +} + static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *link) { @@ -3543,7 +3638,11 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, start_isp.hw_config.priv = &req_isp->hw_update_data; start_isp.hw_config.init_packet = 1; start_isp.hw_config.reapply = 0; - start_isp.start_only = false; + + if (ctx->state == CAM_CTX_FLUSHED) + start_isp.start_only = true; + else + start_isp.start_only = false; atomic_set(&ctx_isp->process_bubble, 0); ctx_isp->frame_id = 0; @@ -3966,6 +4065,22 @@ static struct cam_ctx_ops .pagefault_ops = cam_isp_context_dump_active_request, .dumpinfo_ops = cam_isp_context_info_dump, }, + /* Flushed */ + { + .ioctl_ops = { + .stop_dev = __cam_isp_ctx_stop_dev_in_activated, + .release_dev = __cam_isp_ctx_release_dev_in_activated, + .config_dev = __cam_isp_ctx_config_dev_in_flushed, + .release_hw = __cam_isp_ctx_release_hw_in_activated, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_ready, + .process_evt = __cam_isp_ctx_process_evt, + }, + .irq_ops = NULL, + .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, + }, /* Activated */ { .ioctl_ops = { diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index aad24ae88cc2..b9150e818dc5 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -368,6 +368,11 @@ static void cam_ife_hw_mgr_stop_hw_res( if (!isp_hw_res->hw_res[i]) continue; hw_intf = isp_hw_res->hw_res[i]->hw_intf; + + if (isp_hw_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING) + continue; + if (hw_intf->hw_ops.stop) hw_intf->hw_ops.stop(hw_intf->hw_priv, isp_hw_res->hw_res[i], @@ -794,7 +799,9 @@ static int cam_ife_mgr_csid_stop_hw( cnt = 0; list_for_each_entry(hw_mgr_res, stop_list, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!hw_mgr_res->hw_res[i]) + if (!hw_mgr_res->hw_res[i] || + (hw_mgr_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING)) continue; isp_res = hw_mgr_res->hw_res[i]; @@ -2722,6 +2729,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) cdm_acquire.handle); ife_ctx->cdm_handle = cdm_acquire.handle; ife_ctx->cdm_ops = cdm_acquire.ops; + atomic_set(&ife_ctx->cdm_done, 1); acquire_hw_info = (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; @@ -2910,6 +2918,7 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) cdm_acquire.handle); ife_ctx->cdm_handle = cdm_acquire.handle; ife_ctx->cdm_ops = cdm_acquire.ops; + atomic_set(&ife_ctx->cdm_done, 1); isp_resource = (struct cam_isp_resource *)acquire_args->acquire_info; @@ -3623,13 +3632,6 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index); stop_isp = (struct cam_isp_stop_args *)stop_args->args; - if ((stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_IMMEDIATELY) && - (stop_isp->stop_only)) { - CAM_ERR(CAM_ISP, "Invalid params hw_stop_cmd:%d stop_only:%d", - stop_isp->hw_stop_cmd, stop_isp->stop_only); - return -EPERM; - } - /* Set the csid halt command */ if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY; @@ -3663,7 +3665,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) /* Stop the master CSID path first */ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, - master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + master_base_idx, csid_halt_type); /* stop rest of the CSID paths */ for (i = 0; i < ctx->num_base; i++) { @@ -3673,7 +3675,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) ctx->base[i].idx, i, master_base_idx); cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, - ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); + ctx->base[i].idx, csid_halt_type); } CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx); @@ -3714,6 +3716,8 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) cam_ife_mgr_pause_hw(ctx); + wait_for_completion(&ctx->config_done_complete); + if (stop_isp->stop_only) goto end; @@ -3945,6 +3949,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) goto safe_disable; } +start_only: /* Apply initial configuration */ CAM_DBG(CAM_ISP, "Config HW"); rc = cam_ife_mgr_config_hw(hw_mgr_priv, &start_isp->hw_config); @@ -3953,8 +3958,6 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) goto cdm_streamoff; } -start_only: - CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", ctx->ctx_index); /* start the IFE out devices */ @@ -4081,6 +4084,48 @@ static int cam_ife_mgr_write(void *hw_mgr_priv, void *write_args) return -EPERM; } +static int cam_ife_mgr_reset(void *hw_mgr_priv, void *hw_reset_args) +{ + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_reset_args *reset_args = hw_reset_args; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr_res *hw_mgr_res; + int rc = 0, i = 0; + + if (!hw_mgr_priv || !hw_reset_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)reset_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Reset CSID and VFE"); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to reset CSID:%d rc: %d", + hw_mgr_res->res_id, rc); + goto end; + } + } + + for (i = 0; i < ctx->num_base; i++) { + rc = cam_ife_mgr_reset_vfe_hw(hw_mgr, ctx->base[i].idx); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to reset VFE:%d rc: %d", + ctx->base[i].idx, rc); + goto end; + } + } + +end: + return rc; +} + static int cam_ife_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) { @@ -6807,6 +6852,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update; hw_mgr_intf->hw_config = cam_ife_mgr_config_hw; hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd; + hw_mgr_intf->hw_reset = cam_ife_mgr_reset; if (iommu_hdl) *iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index f3a4d967deaa..256fea2e5bbd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -657,10 +657,6 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, init_completion(complete); reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all; - /* Enable the Test gen before reset */ - cam_io_w_mb(1, csid_hw->hw_info->soc_info.reg_map[0].mem_base + - csid_reg->tpg_reg->csid_tpg_ctrl_addr); - /* Reset the corresponding ife csid path */ cam_io_w_mb(reset_strb_val, soc_info->reg_map[0].mem_base + reset_strb_addr); @@ -675,10 +671,6 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, rc = -ETIMEDOUT; } - /* Disable Test Gen after reset*/ - cam_io_w_mb(0, soc_info->reg_map[0].mem_base + - csid_reg->tpg_reg->csid_tpg_ctrl_addr); - end: return rc; @@ -2101,7 +2093,7 @@ static int cam_ife_csid_disable_pxl_path( if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { - /* configure Halt */ + /* configure Halt for master */ val = cam_io_r_mb(soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_ctrl_addr); val &= ~0x3; @@ -2110,6 +2102,18 @@ static int cam_ife_csid_disable_pxl_path( pxl_reg->csid_pxl_ctrl_addr); } + if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE && + stop_cmd == CAM_CSID_HALT_IMMEDIATELY) { + /* configure Halt for slave */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0xF; + val |= stop_cmd; + val |= (CSID_HALT_MODE_MASTER << 2); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + return rc; } diff --git a/drivers/cam_lrme/cam_lrme_context.c b/drivers/cam_lrme/cam_lrme_context.c index ae8f93c500ef..fa544c7a089e 100644 --- a/drivers/cam_lrme/cam_lrme_context.c +++ b/drivers/cam_lrme/cam_lrme_context.c @@ -190,6 +190,8 @@ static struct cam_ctx_ops .crm_ops = {}, .irq_ops = NULL, }, + /* Flushed */ + {}, /* Activate */ { .ioctl_ops = { -- GitLab From 102db1e4e53d1cc4281e67db64a462e5045b55c8 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Fri, 27 Sep 2019 15:24:07 -0700 Subject: [PATCH 108/410] msm: camera: isp: Fix no reg dump when EPCR is enabled During second init request of EPCR, number of reg dump buffers was set to zero causing no reg dump. Add fix to ensure value is updated to ife ctx when it is non zero. CRs-Fixed: 2532096, 2532101 Change-Id: Ic16001314522cc5b227fc3c33d899c719fbaeacd Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index b9150e818dc5..fd6ead740ddd 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -140,8 +140,9 @@ static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, if (!num_reg_dump_buf || !reg_dump_buf_desc) { CAM_DBG(CAM_ISP, - "Invalid args for reg dump req_id: [%llu] ctx idx: [%u] meta_type: [%u]", - ctx->applied_req_id, ctx->ctx_index, meta_type); + "Invalid args for reg dump req_id: [%llu] ctx idx: [%u] meta_type: [%u] num_reg_dump_buf: [%u] reg_dump_buf_desc: [%pK]", + ctx->applied_req_id, ctx->ctx_index, meta_type, + num_reg_dump_buf, reg_dump_buf_desc); return rc; } @@ -5582,9 +5583,9 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, if (((prepare->packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_INIT_DEV) { prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV; - ctx->num_reg_dump_buf = prepare->num_reg_dump_buf; - if ((ctx->num_reg_dump_buf) && (ctx->num_reg_dump_buf < + if ((prepare->num_reg_dump_buf) && (prepare->num_reg_dump_buf < CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + ctx->num_reg_dump_buf = prepare->num_reg_dump_buf; memcpy(ctx->reg_dump_buf_desc, prepare->reg_dump_buf_desc, sizeof(struct cam_cmd_buf_desc) * -- GitLab From 83aa86fe7929883b4c45735d37dbbd3aef24971f Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Fri, 27 Sep 2019 12:02:41 +0530 Subject: [PATCH 109/410] msm: camera: csiphy: Sensor: Update cphy 3-phase registers for lito Update register settings for CPHY mode as per the latest HPG (revision H). CRs-Fixed: 2534885 Change-Id: I4caade811792467ef7f3eeba85c4a4f5b9050b11 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 83260c670448..c9cbe845cc1b 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -15,7 +15,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .csiphy_common_array_size = 5, .csiphy_reset_array_size = 4, .csiphy_2ph_config_array_size = 19, - .csiphy_3ph_config_array_size = 34, + .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -302,8 +302,7 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09AC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -338,8 +337,7 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0AB0, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -374,8 +372,7 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0BB0, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From aa2e549641ae81405431c5243bfcee897bae9adf Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Fri, 16 Aug 2019 17:39:19 -0700 Subject: [PATCH 110/410] msm: camera: ife: Program RDI clients in line based mode Gralloc allocated buffers are aligned before calculating stride, which can lead to corruption in frame based mode. This change programs RDI clients in line based mode when the output format is PLAIN_16 to prevent this. RDI clients support only PLAIN128 packing format and this change also enforces that. CRs-Fixed: 2513939 Change-Id: Ic079e4cfd34cb4a9a0edc1152ff40565cdab2a81 Signed-off-by: Venkat Chinta --- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 09407894b52a..cae125315895 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -1127,11 +1127,8 @@ static int cam_vfe_bus_ver3_acquire_wm( CAM_DBG(CAM_ISP, "WM:%d width %d height %d", rsrc_data->index, rsrc_data->width, rsrc_data->height); - if (ver3_bus_priv->common_data.is_lite) - goto rdi_config; - - if (rsrc_data->index > 22) { -rdi_config: + if (ver3_bus_priv->common_data.is_lite || (rsrc_data->index > 22)) { + rsrc_data->pack_fmt = 0x0; /* WM 23-25 refers to RDI 0/ RDI 1/RDI 2 */ switch (rsrc_data->format) { case CAM_FORMAT_MIPI_RAW_6: @@ -1142,31 +1139,28 @@ static int cam_vfe_bus_ver3_acquire_wm( case CAM_FORMAT_MIPI_RAW_16: case CAM_FORMAT_MIPI_RAW_20: case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PLAIN32_20: rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; rsrc_data->height = 0; rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; - rsrc_data->pack_fmt = 0x0; rsrc_data->en_cfg = (0x1 << 16) | 0x1; break; case CAM_FORMAT_PLAIN8: rsrc_data->en_cfg = 0x1; - rsrc_data->pack_fmt = 0x1; rsrc_data->stride = rsrc_data->width * 2; break; case CAM_FORMAT_PLAIN16_10: case CAM_FORMAT_PLAIN16_12: case CAM_FORMAT_PLAIN16_14: case CAM_FORMAT_PLAIN16_16: - case CAM_FORMAT_PLAIN32_20: - rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; - rsrc_data->height = 0; - rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; - rsrc_data->pack_fmt = 0x0; - rsrc_data->en_cfg = (0x1 << 16) | 0x1; + rsrc_data->width = + ALIGNUP(rsrc_data->width * 2, 16) / 16; + rsrc_data->en_cfg = 0x1; break; case CAM_FORMAT_PLAIN64: + rsrc_data->width = + ALIGNUP(rsrc_data->width * 8, 16) / 16; rsrc_data->en_cfg = 0x1; - rsrc_data->pack_fmt = 0xA; break; default: CAM_ERR(CAM_ISP, "Unsupported RDI format %d", @@ -1376,16 +1370,6 @@ static int cam_vfe_bus_ver3_start_wm(struct cam_isp_resource_node *wm_res) cam_io_w(rsrc_data->pack_fmt, common_data->mem_base + rsrc_data->hw_regs->packer_cfg); - /* Configure stride for RDIs on full IFE */ - if (!common_data->is_lite && rsrc_data->index > 22) - cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + - rsrc_data->hw_regs->image_cfg_2)); - - /* Configure stride for RDIs on IFE lite */ - if (common_data->is_lite) - cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + - rsrc_data->hw_regs->image_cfg_2)); - /* enable ubwc if needed*/ if (rsrc_data->en_ubwc) { val = cam_io_r_mb(common_data->mem_base + ubwc_regs->mode_cfg); @@ -3076,10 +3060,7 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, CAM_WARN(CAM_ISP, "Warning stride %u expected %u", io_cfg->planes[i].plane_stride, val); - if ((wm_data->stride != val || - !wm_data->init_cfg_done) && - (!bus_priv->common_data.is_lite && - wm_data->index < 23)) { + if (wm_data->stride != val || !wm_data->init_cfg_done) { CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_cfg_2, io_cfg->planes[i].plane_stride); -- GitLab From 8c91109b74c7c4dee048cc4b901a842b1a2a1f1d Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 11 Sep 2019 15:00:07 -0700 Subject: [PATCH 111/410] msm: camera: core: Change return type Return different error number when new requests and update packets are rejected due to bad request ID. This allows userspace to differentiate this specific reason for failure. CRs-Fixed: 2518451 Change-Id: I0400c6f2b2e0baf99bee4b4a3736bb1eab646627 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 2 +- drivers/cam_req_mgr/cam_req_mgr_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 2a3c6dbfcc61..088ba4d1b504 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -2920,7 +2920,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( CAM_INFO(CAM_ISP, "request %lld has been flushed, reject packet", packet->header.request_id); - rc = -EINVAL; + rc = -EBADR; goto free_req; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 97e1dce27f8d..4ca666beab0e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3209,7 +3209,7 @@ int cam_req_mgr_schedule_request( CAM_INFO(CAM_CRM, "request %lld is flushed, last_flush_id to flush %d", sched_req->req_id, link->last_flush_id); - rc = -EINVAL; + rc = -EBADR; goto end; } -- GitLab From 5c2bb432418960c0e9d7ed0f597b0e30b348e850 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Mon, 30 Sep 2019 16:43:18 -0700 Subject: [PATCH 112/410] msm: camera: isp: Re-apply Bubble request In certain scenario Buf_done failures are observed for the request which is in bubble state. Since we never get bufdone we inadvertently are stuck in Bubble state. This change will wait for a period of two frames to receive bufdone and recover from bubble state. If any bufdone IRQ is never generated within this time period, we remove the request from active list and add it back to pending request list. CRs-Fixed: 2506159 Change-Id: Ibcce21a1a87d0a64e49c6454391ca139fc7d1fa7 Signed-off-by: Vishalsingh Hajeri --- drivers/cam_isp/cam_isp_context.c | 48 +++++++++++++++++++++++++++++++ drivers/cam_isp/cam_isp_context.h | 2 ++ 2 files changed, 50 insertions(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 088ba4d1b504..3ffb623f0d6d 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -637,6 +637,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request( ctx->ctx_id); } else { list_add(&req->list, &ctx->pending_req_list); + ctx_isp->bubble_frame_cnt = 0; CAM_DBG(CAM_REQ, "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", req->request_id, ctx_isp->active_req_cnt, @@ -788,6 +789,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( struct cam_req_mgr_trigger_notify notify; struct cam_context *ctx = ctx_isp->base; struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; uint64_t request_id = 0; /* @@ -797,6 +799,48 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( * In this case, we need to skip the current notification. This * helps the state machine to catch up the delay. */ + + if (atomic_read(&ctx_isp->process_bubble)) { + + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_ISP, + "No available active req in bubble"); + atomic_set(&ctx_isp->process_bubble, 0); + rc = -EINVAL; + return rc; + } + + spin_lock_bh(&ctx->lock); + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + spin_unlock_bh(&ctx->lock); + + if (ctx_isp->bubble_frame_cnt >= 1 && + req_isp->bubble_detected) { + req_isp->num_acked = 0; + ctx_isp->bubble_frame_cnt = 0; + req_isp->bubble_detected = false; + spin_lock_bh(&ctx->lock); + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + spin_unlock_bh(&ctx->lock); + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->active_req_cnt--; + CAM_DBG(CAM_REQ, + "Move active req: %lld to pending list(cnt = %d) [bubble re-apply], ctx %u", + req->request_id, + ctx_isp->active_req_cnt, ctx->ctx_id); + } else if (req_isp->bubble_detected) { + ctx_isp->bubble_frame_cnt++; + CAM_DBG(CAM_ISP, + "Waiting on bufdone for bubble req: %lld, since frame_cnt = %lld", + req->request_id, ctx_isp->bubble_frame_cnt); + } else + CAM_DBG(CAM_ISP, "Delayed bufdone for req: %lld", + req->request_id); + } + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && ctx_isp->active_req_cnt <= 2) { if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { @@ -2148,6 +2192,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( } end: + ctx_isp->bubble_frame_cnt = 0; atomic_set(&ctx_isp->process_bubble, 0); return rc; } @@ -3648,6 +3693,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; + ctx_isp->bubble_frame_cnt = 0; ctx_isp->substate_activated = ctx_isp->rdi_only_context ? CAM_ISP_CTX_ACTIVATED_APPLIED : (req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH : @@ -3791,6 +3837,7 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; + ctx_isp->bubble_frame_cnt = 0; atomic_set(&ctx_isp->process_bubble, 0); atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -4243,6 +4290,7 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->frame_id = 0; ctx->active_req_cnt = 0; ctx->reported_req_id = 0; + ctx->bubble_frame_cnt = 0; ctx->hw_ctx = NULL; ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; ctx->substate_machine = cam_isp_ctx_activated_state_machine; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 92db4433b429..1151ca78c052 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -156,6 +156,7 @@ struct cam_isp_context_state_monitor { * @substate_actiavted: Current substate for the activated state. * @process_bubble: Atomic variable to check if ctx is still * processing bubble. + * @bubble_frame_cnt: Count number of frames since the req is in bubble * @substate_machine: ISP substate machine for external interface * @substate_machine_irq: ISP substate machine for irq handling * @req_base: Common request object storage @@ -184,6 +185,7 @@ struct cam_isp_context { int64_t frame_id; uint32_t substate_activated; atomic_t process_bubble; + uint32_t bubble_frame_cnt; struct cam_ctx_ops *substate_machine; struct cam_isp_ctx_irq_ops *substate_machine_irq; -- GitLab From f3af79222b16f1c18ce319edab4b33cd0c9c34e8 Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Tue, 24 Sep 2019 12:12:14 +0530 Subject: [PATCH 113/410] msm: camera: icp: Dump IOCONFIG during io config failure This change dumps IOCONFIG command for IPE and BPS in case of io config failure. CRs-Fixed: 2430046 Change-Id: Iae730f46e4b3f2e327ac10587896a4e755f96a38 Signed-off-by: Suresh Vankadara Signed-off-by: Abhilash Kumar --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) 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 91d87ecb3f6a..289a6d2662d8 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 @@ -57,6 +57,37 @@ static struct cam_icp_hw_mgr icp_hw_mgr; static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl); +static int cam_icp_dump_io_cfg(struct cam_icp_hw_ctx_data *ctx_data, + int32_t buf_handle) +{ + uintptr_t vaddr_ptr; + uint32_t *ptr; + size_t len; + int rc, i; + char buf[512]; + int used = 0; + + rc = cam_mem_get_cpu_buf(buf_handle, &vaddr_ptr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get io_cfg buf address for %d", + ctx_data->ctx_id); + return rc; + } + + len = len / sizeof(uint32_t); + ptr = (uint32_t *)vaddr_ptr; + for (i = 0; i < len; i++) { + used += snprintf(buf + used, + sizeof(buf) - used, "0X%08X-", ptr[i]); + if (!(i % 8)) { + CAM_INFO(CAM_ICP, "%s: %s", __func__, buf); + used = 0; + } + } + + return rc; +} + static const char *cam_icp_dev_type_to_name( uint32_t dev_type) { @@ -5142,6 +5173,8 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) rc = cam_icp_mgr_send_config_io(ctx_data, io_buf_addr); if (rc) { CAM_ERR(CAM_ICP, "IO Config command failed %d", rc); + cam_icp_dump_io_cfg(ctx_data, + icp_dev_acquire_info->io_config_cmd_handle); goto ioconfig_failed; } -- GitLab From 259e6f55d0fb0de8bf6d426d228ef48dd12b6ab6 Mon Sep 17 00:00:00 2001 From: Mangalaram ARCHANA Date: Thu, 3 Oct 2019 10:49:52 +0530 Subject: [PATCH 114/410] msm: camera: req_mgr: Increase device handles in hdl_tbl Increasing device handles to 128 in handle table. CRs-Fixed: 2532741 Change-Id: I58278026d08865cd7935bf4f0dd04f6a594c6dbc Signed-off-by: Mangalaram ARCHANA --- drivers/cam_req_mgr/cam_req_mgr_util.c | 14 +++++++------- drivers/cam_req_mgr/cam_req_mgr_util.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index ce83e64363f5..88b6bf079e9c 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -45,7 +45,7 @@ int cam_req_mgr_util_init(void) hdl_tbl = hdl_tbl_local; spin_unlock_bh(&hdl_tbl_lock); - bitmap_size = BITS_TO_LONGS(CAM_REQ_MGR_MAX_HANDLES) * sizeof(long); + bitmap_size = BITS_TO_LONGS(CAM_REQ_MGR_MAX_HANDLES_V2) * sizeof(long); hdl_tbl->bitmap = kzalloc(bitmap_size, GFP_KERNEL); if (!hdl_tbl->bitmap) { rc = -ENOMEM; @@ -92,7 +92,7 @@ int cam_req_mgr_util_free_hdls(void) return -EINVAL; } - for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES; i++) { + for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES_V2; i++) { if (hdl_tbl->hdl[i].state == HDL_ACTIVE) { CAM_WARN(CAM_CRM, "Dev handle = %x session_handle = %x", hdl_tbl->hdl[i].hdl_value, @@ -101,7 +101,7 @@ int cam_req_mgr_util_free_hdls(void) clear_bit(i, hdl_tbl->bitmap); } } - bitmap_zero(hdl_tbl->bitmap, CAM_REQ_MGR_MAX_HANDLES); + bitmap_zero(hdl_tbl->bitmap, CAM_REQ_MGR_MAX_HANDLES_V2); spin_unlock_bh(&hdl_tbl_lock); return 0; @@ -113,7 +113,7 @@ static int32_t cam_get_free_handle_index(void) idx = find_first_zero_bit(hdl_tbl->bitmap, hdl_tbl->bits); - if (idx >= CAM_REQ_MGR_MAX_HANDLES || idx < 0) + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2 || idx < 0) return -ENOSR; set_bit(idx, hdl_tbl->bitmap); @@ -201,7 +201,7 @@ void *cam_get_device_priv(int32_t dev_hdl) } idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); - if (idx >= CAM_REQ_MGR_MAX_HANDLES) { + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2) { CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid idx"); goto device_priv_fail; } @@ -245,7 +245,7 @@ void *cam_get_device_ops(int32_t dev_hdl) } idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); - if (idx >= CAM_REQ_MGR_MAX_HANDLES) { + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2) { CAM_ERR(CAM_CRM, "Invalid idx"); goto device_ops_fail; } @@ -288,7 +288,7 @@ static int cam_destroy_hdl(int32_t dev_hdl, int dev_hdl_type) } idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); - if (idx >= CAM_REQ_MGR_MAX_HANDLES) { + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2) { CAM_ERR(CAM_CRM, "Invalid idx %d", idx); goto destroy_hdl_fail; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.h b/drivers/cam_req_mgr/cam_req_mgr_util.h index f22c6cbae8ef..c0e339eedd9b 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.h +++ b/drivers/cam_req_mgr/cam_req_mgr_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_UTIL_API_H_ @@ -54,7 +54,7 @@ struct handle { * @bits: size of bit map in bits */ struct cam_req_mgr_util_hdl_tbl { - struct handle hdl[CAM_REQ_MGR_MAX_HANDLES]; + struct handle hdl[CAM_REQ_MGR_MAX_HANDLES_V2]; void *bitmap; size_t bits; }; -- GitLab From 1aadfe80e81403d76bba0eaed3437ff330584087 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Wed, 9 Oct 2019 17:21:41 -0700 Subject: [PATCH 115/410] msm: camera: isp: Remove redundant use of spin lock Interrupts in activated state machine are already protected with spin_lock for context. No need to reuse the spin_lock in interrupt handling routine. CRs-Fixed: 2538876 Change-Id: Id86e7dc3419861cb8bce143c56923126a3dc3d3e Signed-off-by: Vishalsingh Hajeri --- drivers/cam_isp/cam_isp_context.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 3ffb623f0d6d..53521e79b388 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -810,21 +810,17 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( return rc; } - spin_lock_bh(&ctx->lock); req = list_first_entry(&ctx->active_req_list, struct cam_ctx_request, list); req_isp = (struct cam_isp_ctx_req *) req->req_priv; - spin_unlock_bh(&ctx->lock); if (ctx_isp->bubble_frame_cnt >= 1 && req_isp->bubble_detected) { req_isp->num_acked = 0; ctx_isp->bubble_frame_cnt = 0; req_isp->bubble_detected = false; - spin_lock_bh(&ctx->lock); list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); - spin_unlock_bh(&ctx->lock); atomic_set(&ctx_isp->process_bubble, 0); ctx_isp->active_req_cnt--; CAM_DBG(CAM_REQ, -- GitLab From af27416f683b8f0985c2a4fdf8ade46d43afa777 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 11 Sep 2019 10:43:51 -0700 Subject: [PATCH 116/410] msm: camera: isp: Correct acquire dump log Print the split id correctly as part of the acquire failure dump. CRs-Fixed: 2541667 Change-Id: Ie7156e35458027e24cea1993e487bfe38fcc2324 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index fd6ead740ddd..0b224ade013e 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -778,7 +778,7 @@ static void cam_ife_hw_mgr_dump_acq_data( if (hw_res && hw_res->hw_intf) CAM_INFO(CAM_ISP, "IFE out split_id: %d res_id: 0x%x hw_idx: %u state: %s", - i, hw_res->res_id, + j, hw_res->res_id, hw_res->hw_intf->hw_idx, cam_ife_hw_mgr_get_res_state (hw_res->res_state)); -- GitLab From 3619ae634bffed9c1b8f812d8f66fea89e2e2b1a Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 10 Sep 2019 17:18:47 +0530 Subject: [PATCH 117/410] msm: camera: reqmgr: Logs v4l2 event queue failure Kernel uses v4l2 events to communicate with userspace. If userspace is not dequeuing events and kernel is pushing more events then v4l2_event_queue fails silently. This change uses v4l2 callbacks to log v4l2_event_queue failure. CRs-Fixed: 2541894 Change-Id: I98f8f609f615104ec6dde569bf1f39de1eb368fc Signed-off-by: Trishansh Bhardwaj --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 3 +- drivers/cam_req_mgr/cam_mem_mgr.c | 4 +- drivers/cam_req_mgr/cam_req_mgr_dev.c | 45 ++++++++++++++++++- drivers/cam_sync/cam_sync.c | 17 ++++++- 4 files changed, 64 insertions(+), 5 deletions(-) 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 289a6d2662d8..994310f84b10 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 @@ -4437,7 +4437,8 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], mmu_hdl, &iova_addr, &src_buf_size); if (rc < 0) { - CAM_ERR(CAM_UTIL, "get src buf address fail"); + CAM_ERR(CAM_UTIL, + "get src buf address fail rc %d", rc); continue; } if (iova_addr >> 32) { diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index b7f77506d004..49b7e09b2228 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -188,10 +188,10 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle); if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) - return -EINVAL; + return -ENOENT; if (!tbl.bufq[idx].active) - return -EINVAL; + return -EAGAIN; mutex_lock(&tbl.bufq[idx].q_lock); if (buf_handle != tbl.bufq[idx].buf_handle) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index d567dec91519..f2452d9c340c 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -197,10 +197,53 @@ static struct v4l2_file_operations g_cam_fops = { #endif }; +static void cam_v4l2_event_queue_notify_error(const struct v4l2_event *old, + struct v4l2_event *new) +{ + struct cam_req_mgr_message *ev_header; + + ev_header = CAM_REQ_MGR_GET_PAYLOAD_PTR((*old), + struct cam_req_mgr_message); + switch (old->id) { + case V4L_EVENT_CAM_REQ_MGR_SOF: + CAM_ERR(CAM_CRM, "Failed to notify SOF event"); + CAM_ERR(CAM_CRM, "Sess %X FrameId %lld ReqId %lld link %X", + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); + break; + case V4L_EVENT_CAM_REQ_MGR_ERROR: + CAM_ERR(CAM_CRM, "Failed to notify ERROR"); + CAM_ERR(CAM_CRM, "Sess %X ReqId %d Link %X Type %d", + ev_header->u.err_msg.error_type, + ev_header->u.err_msg.request_id, + ev_header->u.err_msg.link_hdl, + ev_header->u.err_msg.error_type); + break; + case V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS: + CAM_ERR(CAM_CRM, "Failed to notify BOOT_TS event"); + CAM_ERR(CAM_CRM, "Sess %X FrameId %lld ReqId %lld link %X", + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); + break; + default: + CAM_ERR(CAM_CRM, "Failed to notify crm event id %d", + old->id); + } +} + +static struct v4l2_subscribed_event_ops g_cam_v4l2_ops = { + .merge = cam_v4l2_event_queue_notify_error, +}; + static int cam_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_subscribe(fh, sub, CAM_REQ_MGR_EVENT_MAX, NULL); + return v4l2_event_subscribe(fh, sub, CAM_REQ_MGR_EVENT_MAX, + &g_cam_v4l2_ops); } static int cam_unsubscribe_event(struct v4l2_fh *fh, diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 10ed0cdecebf..45d2793fb671 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -847,10 +847,25 @@ static int cam_sync_close(struct file *filep) return rc; } +static void cam_sync_event_queue_notify_error(const struct v4l2_event *old, + struct v4l2_event *new) +{ + struct cam_sync_ev_header *ev_header; + + ev_header = CAM_SYNC_GET_HEADER_PTR((*old)); + CAM_ERR(CAM_CRM, "Failed to notify event id %d fence %d statue %d", + old->id, ev_header->sync_obj, ev_header->status); +} + +static struct v4l2_subscribed_event_ops cam_sync_v4l2_ops = { + .merge = cam_sync_event_queue_notify_error, +}; + int cam_sync_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_subscribe(fh, sub, CAM_SYNC_MAX_V4L2_EVENTS, NULL); + return v4l2_event_subscribe(fh, sub, CAM_SYNC_MAX_V4L2_EVENTS, + &cam_sync_v4l2_ops); } int cam_sync_unsubscribe_event(struct v4l2_fh *fh, -- GitLab From f8c60957192f77d1ed331bc2a8ed9e06d09ba6b5 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 10 Oct 2019 17:36:37 -0700 Subject: [PATCH 118/410] msm: camera: isp: Add log in flush This change adds a log in flush to indicate stop/restart HW complete. CRs-Fixed: 2545140 Change-Id: I0068f239c5efeb536d60a9de27577d46bdc66edd Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 53521e79b388..d7e243678a12 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -2163,6 +2163,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( CAM_ERR(CAM_ISP, "Failed to stop HW in Flush rc: %d", rc); + CAM_INFO(CAM_ISP, "Stop HW complete. Reset HW next."); CAM_DBG(CAM_ISP, "Flush wait and active lists"); spin_lock_bh(&ctx->lock); if (!list_empty(&ctx->wait_req_list)) @@ -3553,12 +3554,13 @@ static int __cam_isp_ctx_config_dev_in_flushed(struct cam_context *ctx, if (!ctx_isp->hw_acquired) { CAM_ERR(CAM_ISP, "HW is not acquired, reject packet"); - return -EINVAL; + rc = -EINVAL; + goto end; } rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd); if (rc) - return rc; + goto end; if (!ctx_isp->init_received) { CAM_WARN(CAM_ISP, @@ -3574,7 +3576,7 @@ static int __cam_isp_ctx_config_dev_in_flushed(struct cam_context *ctx, &hw_cmd_args); if (rc) { CAM_ERR(CAM_ISP, "Failed to resume HW rc: %d", rc); - return rc; + goto end; } start_cmd.dev_handle = cmd->dev_handle; @@ -3583,6 +3585,9 @@ static int __cam_isp_ctx_config_dev_in_flushed(struct cam_context *ctx, if (rc) CAM_ERR(CAM_ISP, "Failed to re-start HW after flush rc: %d", rc); + else + CAM_INFO(CAM_ISP, + "Received init after flush. Re-start HW complete."); end: CAM_DBG(CAM_ISP, "next state %d sub_state:%d", ctx->state, -- GitLab From 49d6a1b3c60a3fd4537c945013a33ed9f3c8db23 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 10 Oct 2019 15:21:53 -0700 Subject: [PATCH 119/410] msm: camera: isp: Add tasklet index to logs This change adds tasklet index to logs which shares a one-one mapping with ife hardware manager context ID. CRs-Fixed: 2545140 Change-Id: I879662c9d90e98c604d20d975b4973369ac7a41e Signed-off-by: Venkat Chinta --- .../isp_hw_mgr/hw_utils/cam_tasklet_util.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index 458894f96a1b..356c9a0a8919 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -88,14 +88,16 @@ int cam_tasklet_get_cmd( } if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet idx:%d is not active", + tasklet->index); rc = -EPIPE; return rc; } spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->free_cmd_list)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd idx:%d", + tasklet->index); rc = -ENODEV; goto spin_unlock; } else { @@ -158,7 +160,7 @@ static int cam_tasklet_dequeue_cmd( *tasklet_cmd = NULL; - CAM_DBG(CAM_ISP, "Dequeue before lock."); + CAM_DBG(CAM_ISP, "Dequeue before lock tasklet idx:%d", tasklet->index); spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->used_cmd_list)) { CAM_DBG(CAM_ISP, "End of list reached. Exit"); @@ -198,11 +200,12 @@ void cam_tasklet_enqueue_cmd( } if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active\n"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active idx:%d", + tasklet->index); return; } - CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); + CAM_DBG(CAM_ISP, "Enqueue tasklet cmd idx:%d", tasklet->index); tasklet_cmd->bottom_half_handler = bottom_half_handler; tasklet_cmd->payload = evt_payload_priv; tasklet_cmd->handler_priv = handler_priv; @@ -273,7 +276,7 @@ int cam_tasklet_start(void *tasklet_info) int i = 0; if (atomic_read(&tasklet->tasklet_active)) { - CAM_ERR(CAM_ISP, "Tasklet already active. idx = %d", + CAM_ERR(CAM_ISP, "Tasklet already active idx:%d", tasklet->index); return -EBUSY; } -- GitLab From 11e7f2175420b10fe7c5ce229f785104ed29c3dd Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 10 Oct 2019 13:42:10 -0700 Subject: [PATCH 120/410] msm: camera: isp: Set error type to fatal This change sets error type to fatal by default when hardware errors occur. CRs-Fixed: 2545140 Change-Id: Ic530fe460e67b6d5ec26a6d9d5735f4c8b34affc Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index d7e243678a12..67e6c7d05160 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1405,7 +1405,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, end: do { if (list_empty(&ctx->pending_req_list)) { - error_request_id = ctx_isp->last_applied_req_id + 1; + error_request_id = ctx_isp->last_applied_req_id; req_isp = NULL; break; } @@ -1436,13 +1436,11 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, notify.link_hdl = ctx->link_hdl; notify.dev_hdl = ctx->dev_hdl; notify.req_id = error_request_id; + notify.error = CRM_KMD_ERR_FATAL; - if (req_isp_to_report && req_isp_to_report->bubble_report) { + if (req_isp_to_report && req_isp_to_report->bubble_report) if (error_event_data->recovery_enabled) notify.error = CRM_KMD_ERR_BUBBLE; - } else { - notify.error = CRM_KMD_ERR_FATAL; - } CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld ctx %u, error %d", -- GitLab From 1dfd3efd17c1e8a4410e859baa615fbe51332425 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 7 Oct 2019 12:03:49 -0700 Subject: [PATCH 121/410] msm: camera: ife: Disable early eof strobe This change disables early eof strobe for version 480 hardware due to hardware limitation. CRs-Fixed: 2545140 Change-Id: I727ba5950911caac76cd2046e9e7c1e6d7ca6d96 Signed-off-by: Venkat Chinta --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 256fea2e5bbd..af9f67286d82 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1773,8 +1773,11 @@ static int cam_ife_csid_init_config_pxl_path( CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x", csid_hw->hw_intf->hw_idx, val); - /* Enable generating early eof strobe based on crop config */ - if (!(csid_hw->csid_debug & CSID_DEBUG_DISABLE_EARLY_EOF)) { + /* Enable generating early eof strobe based on crop config. + * Skip for version 480 HW due to HW limitation. + */ + if (!(csid_hw->csid_debug & CSID_DEBUG_DISABLE_EARLY_EOF) && + (camera_hw_version != CAM_CPAS_TITAN_480_V100)) { val = cam_io_r_mb(soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_cfg0_addr); val |= (1 << pxl_reg->early_eof_en_shift_val); -- GitLab From 388c4f7280bd4d09b6f7726427ca554dcdc3586f Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 10 Oct 2019 11:26:39 -0700 Subject: [PATCH 122/410] msm: camera: reqmgr: Reset the pd tables as part of flush As part of flush only the request slots were reset, we need to reset the slots in each of the pd tables. CRs-Fixed: 2545130 Change-Id: I34054dea2e5849739df9dd0a77d908a9af9fe3be Signed-off-by: Karthik Anantha Ram --- drivers/cam_req_mgr/cam_req_mgr_core.c | 54 +++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 4ca666beab0e..be08f48a5f72 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -416,6 +416,50 @@ static void __cam_req_mgr_tbl_set_all_skip_cnt( } while (tbl != NULL); } +/** + * __cam_req_mgr_flush_req_slot() + * + * @brief : reset all the slots/pd tables when flush is + * invoked + * @link : link pointer + * + */ +static void __cam_req_mgr_flush_req_slot( + struct cam_req_mgr_core_link *link) +{ + int idx = 0; + struct cam_req_mgr_slot *slot; + struct cam_req_mgr_req_tbl *tbl; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + + for (idx = 0; idx < in_q->num_slots; idx++) { + slot = &in_q->slot[idx]; + tbl = link->req.l_tbl; + CAM_DBG(CAM_CRM, + "RESET idx: %d req_id: %lld slot->status: %d", + idx, slot->req_id, slot->status); + + /* Reset input queue slot */ + slot->req_id = -1; + slot->skip_idx = 1; + slot->recover = 0; + slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->status = CRM_SLOT_STATUS_NO_REQ; + + /* Reset all pd table slot */ + while (tbl != NULL) { + CAM_DBG(CAM_CRM, "pd: %d: idx %d state %d", + tbl->pd, idx, tbl->slot[idx].state); + tbl->slot[idx].req_ready_map = 0; + tbl->slot[idx].state = CRM_REQ_STATE_EMPTY; + tbl = tbl->next; + } + } + + in_q->wr_idx = 0; + in_q->rd_idx = 0; +} + /** * __cam_req_mgr_reset_req_slot() * @@ -1966,15 +2010,7 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) link->last_flush_id = flush_info->req_id; CAM_INFO(CAM_CRM, "Last request id to flush is %lld", flush_info->req_id); - for (i = 0; i < in_q->num_slots; i++) { - slot = &in_q->slot[i]; - slot->req_id = -1; - slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; - slot->skip_idx = 1; - slot->status = CRM_SLOT_STATUS_NO_REQ; - } - in_q->wr_idx = 0; - in_q->rd_idx = 0; + __cam_req_mgr_flush_req_slot(link); } else if (flush_info->flush_type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { idx = __cam_req_mgr_find_slot_for_req(in_q, flush_info->req_id); -- GitLab From 422de0bbf49c799fc85bb1744b30897708309c74 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 10 Oct 2019 11:31:03 -0700 Subject: [PATCH 123/410] msm: camera: ife: Deinit input mux resources We must deinit IFE input mux resources before the check for open count. Without this change the last bus resource is the last to enter this function when open count reaches zero. So input mux resources are never deinitialized. CRs-Fixed: 2545140 Change-Id: I355afce7d631cdb00e3f6da0ba0be40c2e2b63a2 Signed-off-by: Venkat Chinta --- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 0244e41d5a03..11d6a602117c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -251,6 +251,13 @@ int cam_vfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) return -EINVAL; } + isp_res = (struct cam_isp_resource_node *)deinit_hw_args; + if (isp_res && isp_res->deinit) { + rc = isp_res->deinit(isp_res, NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "deinit failed"); + } + mutex_lock(&vfe_hw->hw_mutex); if (!vfe_hw->open_count) { mutex_unlock(&vfe_hw->hw_mutex); @@ -281,13 +288,6 @@ int cam_vfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); } - isp_res = (struct cam_isp_resource_node *)deinit_hw_args; - if (isp_res && isp_res->deinit) { - rc = isp_res->deinit(isp_res, NULL, 0); - if (rc) - CAM_ERR(CAM_ISP, "deinit failed"); - } - rc = cam_vfe_reset(hw_priv, &reset_core_args, sizeof(uint32_t)); /* Turn OFF Regulators, Clocks and other SOC resources */ -- GitLab From 064d662a3cc352f7dfcf881d7b2ca276765d15a0 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 3 Oct 2019 12:19:02 -0700 Subject: [PATCH 124/410] msm: camera: isp: Update last applied request ID This change updates last applied request ID when init packets are applied and when stop ioctls are invoked. CRs-Fixed: 2539888 Change-Id: I113b7897740d6577a4757ce41f9fcb1fff8c56e9 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 67e6c7d05160..5698e73bbd32 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3683,6 +3683,8 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, start_isp.hw_config.init_packet = 1; start_isp.hw_config.reapply = 0; + ctx_isp->last_applied_req_id = req->request_id; + if (ctx->state == CAM_CTX_FLUSHED) start_isp.start_only = true; else @@ -3837,6 +3839,7 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; ctx_isp->bubble_frame_cnt = 0; + ctx_isp->last_applied_req_id = 0; atomic_set(&ctx_isp->process_bubble, 0); atomic64_set(&ctx_isp->state_monitor_head, -1); -- GitLab From a62a43252281382396ee1fbdd908bf4f8f32fc5b Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 15 Oct 2019 12:31:49 +0530 Subject: [PATCH 125/410] msm: camera: cpas: Fix TCSR register programming Program TCSR_CAMERA_HF_SF_ARES_GLITCH_MASK to ignore erroneous signals. CRs-Fixed: 2545751 Change-Id: Ie638136d364372b7a8309af1d9656a8c8b7772fc Signed-off-by: Trishansh Bhardwaj --- drivers/cam_cpas/cam_cpas_hw.c | 2 +- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 11 +++++++++++ drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 4 +++- drivers/cam_cpas/cpas_top/cpastop_v175_130.h | 11 +++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 7ee738da4748..78e12fcd1090 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -44,7 +44,7 @@ int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, value = reg_info->value; } - CAM_DBG(CAM_CPAS, "Base[%d] Offset[0x%8x] Value[0x%8x]", + CAM_DBG(CAM_CPAS, "Base[%d] Offset[0x%08x] Value[0x%08x]", reg_base, reg_info->offset, value); cam_io_w_mb(value, soc_info->reg_map[reg_base_index].mem_base + diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 18151d1069a3..0543397a8482 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -7,6 +7,8 @@ #include #include +#include + #include "cam_cpas_hw_intf.h" #include "cam_cpas_hw.h" #include "cam_cpastop_hw.h" @@ -513,6 +515,10 @@ static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data) static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) { int i; + struct cam_cpas_hw_errata_wa_list *errata_wa_list = + camnoc_info->errata_wa_list; + struct cam_cpas_hw_errata_wa *errata_wa = + &errata_wa_list->tcsr_camera_hf_sf_ares_glitch; cam_cpastop_reset_irq(cpas_hw); for (i = 0; i < camnoc_info->specific_size; i++) { @@ -534,6 +540,11 @@ static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) } } + if (errata_wa->enable) { + scm_io_write(errata_wa->data.reg_info.offset, + errata_wa->data.reg_info.value); + } + return 0; } diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index bdcf00da90b7..a4d44a3feff6 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -208,10 +208,12 @@ struct cam_cpas_hw_errata_wa { * * @camnoc_flush_slave_pending_trans: Errata workaround info for flushing * camnoc slave pending transactions before turning off CPAS_TOP gdsc - * + * @tcsr_camera_hf_sf_ares_glitch: Errata workaround info from ignoring + * erroneous signals at camera start */ struct cam_cpas_hw_errata_wa_list { struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans; + struct cam_cpas_hw_errata_wa tcsr_camera_hf_sf_ares_glitch; }; /** diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h index 2d3d96ea819a..769e77fc3d6b 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h @@ -747,6 +747,17 @@ static struct cam_cpas_hw_errata_wa_list cam175_cpas130_errata_wa_list = { .value = 0, /* expected to be 0 */ }, }, + /* TZ owned register */ + .tcsr_camera_hf_sf_ares_glitch = { + .enable = true, + .data.reg_info = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + /* TCSR_CAMERA_HF_SF_ARES_GLITCH_MASK */ + .offset = 0x01FCA08C, + .value = 0x4, /* set bit[2] to 1 */ + }, + }, }; static struct cam_camnoc_info cam175_cpas130_camnoc_info = { -- GitLab From 3205f18e3c50d38075780e5878599b4b102eea84 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 14 Oct 2019 00:05:31 +0530 Subject: [PATCH 126/410] msm: camera: csiphy: Enable multi-datarate support for csiphy v1.2 Enable support for multiple data rates (2.5/3.5/4.5 Gsps) for csiphy v1.2 driver. CRs-Fixed: 2542855 Change-Id: Idbe299aca210e30d732304e77e2a8191c8809f09 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_soc.c | 5 +++-- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 18 ++++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index a6aba5940181..c5a8033aaffb 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -269,7 +269,7 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; csiphy_dev->ctrl_reg->data_rates_settings_table = - &data_rate_delta_table; + &data_rate_delta_table_1_2; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v1.2.1")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_1_reg; @@ -308,7 +308,8 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->is_divisor_32_comp = false; csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; - csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index c9cbe845cc1b..cc6c1adb366c 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -376,17 +376,14 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { }, }; -struct data_rate_settings_t data_rate_delta_table = { +struct data_rate_settings_t data_rate_delta_table_1_2 = { .num_data_rate_settings = 3, .data_rate_settings = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 9, + .data_rate_reg_array_size = 6, .csiphy_data_rate_regs = { - {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -398,11 +395,8 @@ struct data_rate_settings_t data_rate_delta_table = { { /* (3.5 * 10**3 * 2.28) rounded value */ .bandwidth = 7980000000, - .data_rate_reg_array_size = 18, + .data_rate_reg_array_size = 15, .csiphy_data_rate_regs = { - {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -418,17 +412,13 @@ struct data_rate_settings_t data_rate_delta_table = { {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - }, }, { /* (4.5 * 10**3 * 2.28) rounded value */ .bandwidth = 10260000000, - .data_rate_reg_array_size = 18, + .data_rate_reg_array_size = 15, .csiphy_data_rate_regs = { - {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, -- GitLab From 037967bc88dd727228eab18d1001b2d641102236 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Tue, 1 Oct 2019 12:31:36 -0700 Subject: [PATCH 127/410] msm: camera: ife: Dump ife camnoc debug registers ife camnoc debug registers need to dumped only when bus overflow status is set. CRs-Fixed: 2538876 Change-Id: I6f886f6e084380de62c0b4acaa48fa02fce01136 Signed-off-by: Vishalsingh Hajeri --- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 126 +++++++++--------- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 118 ++++++++-------- 2 files changed, 121 insertions(+), 123 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index 495e4afbd50a..bfb17d2145f8 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -762,72 +762,57 @@ static int cam_vfe_camif_lite_process_cmd( return rc; } -static void cam_vfe_camif_lite_overflow_debug_info(uint32_t *status, +static void cam_vfe_camif_lite_overflow_debug_info( struct cam_vfe_mux_camif_lite_data *camif_lite_priv) { - uint32_t bus_overflow_status = 0; struct cam_vfe_soc_private *soc_private = NULL; uint32_t val0, val1, val2, val3; - bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; soc_private = camif_lite_priv->soc_info->soc_private; - if (bus_overflow_status) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); - CAM_INFO(CAM_ISP, - "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", - val0, val1, val2); + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_0); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_1); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_2); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_3); + CAM_INFO(CAM_ISP, + "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", + val0, val1, val2, val3); - } else { - val0 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_0); - val1 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_1); - val2 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_2); - val3 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_3); - CAM_INFO(CAM_ISP, - "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", - val0, val1, val2, val3); - - if (soc_private->is_ife_lite) - return; - - val0 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_4); - val1 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_5); - val2 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_6); - val3 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_7); - CAM_INFO(CAM_ISP, - "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", - val0, val1, val2, val3); - val0 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_8); - val1 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_9); - val2 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_10); - val3 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_11); - CAM_INFO(CAM_ISP, - "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", - val0, val1, val2, val3); - val0 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_12); - val1 = cam_io_r(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->top_debug_13); - CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", - val0, val1); - } + if (soc_private->is_ife_lite) + return; + + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_4); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_5); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_6); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_7); + CAM_INFO(CAM_ISP, + "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", + val0, val1, val2, val3); + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_8); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_9); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_10); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_11); + CAM_INFO(CAM_ISP, + "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", + val0, val1, val2, val3); + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_12); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_13); + CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", + val0, val1); } static void cam_vfe_camif_lite_print_status(uint32_t *status, @@ -836,6 +821,7 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, uint32_t violation_mask = 0x3F00, violation_status = 0; uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; struct cam_vfe_soc_private *soc_private = NULL; + uint32_t val0, val1, val2; if (!status) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -893,13 +879,21 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, if (bus_overflow_status & 0x02000000) CAM_INFO(CAM_ISP, "RDI2 BUS OVERFLOW"); - return; + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { CAM_INFO(CAM_ISP, "PDLIB / LCR Module hang"); /* print debug registers */ - cam_vfe_camif_lite_overflow_debug_info(status, camif_lite_priv); + cam_vfe_camif_lite_overflow_debug_info(camif_lite_priv); return; } @@ -979,12 +973,22 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, if (bus_overflow_status & 0x08) CAM_INFO(CAM_ISP, "RDI3 BUS OVERFLOW"); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { CAM_INFO(CAM_ISP, "RDI hang"); /* print debug registers */ - cam_vfe_camif_lite_overflow_debug_info(status, camif_lite_priv); + cam_vfe_camif_lite_overflow_debug_info(camif_lite_priv); return; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index c390b6f542d4..8e5a30588c52 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -776,71 +776,53 @@ static int cam_vfe_camif_ver3_process_cmd( } -static void cam_vfe_camif_ver3_overflow_debug_info(uint32_t *status, +static void cam_vfe_camif_ver3_overflow_debug_info( struct cam_vfe_mux_camif_ver3_data *camif_priv) { - struct cam_vfe_soc_private *soc_private; - uint32_t bus_overflow_status; uint32_t val0, val1, val2, val3; - bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; - soc_private = camif_priv->soc_info->soc_private; - - if (bus_overflow_status) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); - CAM_INFO(CAM_ISP, - "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", - val0, val1, val2); - } else { - val0 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_0); - val1 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_1); - val2 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_2); - val3 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_3); - CAM_INFO(CAM_ISP, - "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", - val0, val1, val2, val3); - - val0 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_4); - val1 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_5); - val2 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_6); - val3 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_7); - CAM_INFO(CAM_ISP, - "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", - val0, val1, val2, val3); - - val0 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_8); - val1 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_9); - val2 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_10); - val3 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_11); - CAM_INFO(CAM_ISP, - "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", - val0, val1, val2, val3); - - val0 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_12); - val1 = cam_io_r(camif_priv->mem_base + - camif_priv->common_reg->top_debug_13); - CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", - val0, val1); - } - + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_0); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_1); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_2); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_3); + CAM_INFO(CAM_ISP, + "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_4); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_5); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_6); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_7); + CAM_INFO(CAM_ISP, + "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_8); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_9); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_10); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_11); + CAM_INFO(CAM_ISP, + "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_12); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_13); + CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", + val0, val1); } static void cam_vfe_camif_ver3_print_status(uint32_t *status, @@ -848,6 +830,8 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, { uint32_t violation_mask = 0x3F, module_id = 0; uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; + struct cam_vfe_soc_private *soc_private; + uint32_t val0, val1, val2; if (!status) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -933,13 +917,23 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, if (bus_overflow_status & 0x0200000) CAM_INFO(CAM_ISP, "PDAF BUS OVERFLOW"); + soc_private = camif_priv->soc_info->soc_private; + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); return; } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { CAM_INFO(CAM_ISP, "PIXEL PIPE Module hang"); /* print debug registers */ - cam_vfe_camif_ver3_overflow_debug_info(status, camif_priv); + cam_vfe_camif_ver3_overflow_debug_info(camif_priv); return; } -- GitLab From 35bead08c397908b6344787382a150c484d1a42c Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 24 Sep 2019 13:01:20 +0530 Subject: [PATCH 128/410] msm: camera: common: Fix compilation issues for 32-bit arch Fix improper use of divide and modulo operator on 64 bit numbers. Fix variable type to work with both 32/64 bit arch. CRs-Fixed: 2543730 Change-Id: Ifa52d46dece3434d41308d284982a0cd8e17cd1b Signed-off-by: Trishansh Bhardwaj --- drivers/cam_cdm/cam_cdm_hw_core.c | 2 +- drivers/cam_cpas/cam_cpas_hw.c | 12 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 107 ++++++++++-------- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 4 +- drivers/cam_isp/cam_isp_context.c | 14 ++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 9 +- .../hw_utils/cam_isp_packet_parser.c | 4 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 +- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 2 +- drivers/cam_lrme/cam_lrme_context.h | 2 +- .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 2 +- drivers/cam_req_mgr/cam_mem_mgr.c | 2 +- drivers/cam_req_mgr/cam_mem_mgr_api.h | 2 +- .../cam_csiphy/cam_csiphy_core.c | 15 ++- drivers/cam_smmu/cam_smmu_api.c | 2 +- 15 files changed, 105 insertions(+), 76 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 7d0515b747a4..f54f9d61b55f 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -413,7 +413,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, } for (i = 0; i < req->data->cmd_arrary_count ; i++) { - uint64_t hw_vaddr_ptr = 0; + dma_addr_t hw_vaddr_ptr = 0; size_t len = 0; if ((!cdm_cmd->cmd[i].len) && diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 78e12fcd1090..ae0368acdb05 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -424,7 +424,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( if (soc_private->control_camnoc_axi_clk) { struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; - uint64_t required_camnoc_bw = 0; + uint64_t required_camnoc_bw = 0, intermediate_result = 0; int32_t clk_rate = 0; for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { @@ -440,15 +440,19 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( } } - required_camnoc_bw += (required_camnoc_bw * - soc_private->camnoc_axi_clk_bw_margin) / 100; + intermediate_result = required_camnoc_bw * + soc_private->camnoc_axi_clk_bw_margin; + do_div(intermediate_result, 100); + required_camnoc_bw += intermediate_result; if ((required_camnoc_bw > 0) && (required_camnoc_bw < soc_private->camnoc_axi_min_ib_bw)) required_camnoc_bw = soc_private->camnoc_axi_min_ib_bw; - clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; + intermediate_result = required_camnoc_bw; + do_div(intermediate_result, soc_private->camnoc_bus_width); + clk_rate = intermediate_result; CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", required_camnoc_bw, clk_rate); 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 994310f84b10..786fd0e98f32 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 @@ -422,6 +422,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) (struct cam_icp_hw_ctx_data *)task_data->data; struct cam_icp_hw_mgr *hw_mgr = &icp_hw_mgr; uint32_t id; + uint64_t temp; struct cam_hw_intf *ipe0_dev_intf = NULL; struct cam_hw_intf *ipe1_dev_intf = NULL; struct cam_hw_intf *bps_dev_intf = NULL; @@ -521,16 +522,17 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) ctx_data->clk_info.base_clk = 0; clk_update.axi_vote.num_paths = 1; - clk_update.axi_vote.axi_path[0].camnoc_bw = - clk_info->uncompressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].mnoc_ab_bw = - clk_info->compressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].mnoc_ib_bw = - clk_info->compressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].ddr_ab_bw = - clk_info->compressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].ddr_ib_bw = - clk_info->compressed_bw / device_share_ratio; + + temp = clk_info->uncompressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].camnoc_bw = temp; + + temp = clk_info->compressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].mnoc_ab_bw = temp; + clk_update.axi_vote.axi_path[0].mnoc_ib_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ab_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ib_bw = temp; } else { int path_index; @@ -594,16 +596,21 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) if (device_share_ratio > 1) { for (i = 0; i < clk_update.axi_vote.num_paths; i++) { - clk_update.axi_vote.axi_path[i].camnoc_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].mnoc_ab_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].mnoc_ib_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].ddr_ab_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].ddr_ib_bw /= - device_share_ratio; + do_div( + clk_update.axi_vote.axi_path[i].camnoc_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ib_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ib_bw, + device_share_ratio); } } } @@ -780,7 +787,8 @@ static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles, uint64_t base_clk; uint64_t mul = 1000000000; - base_clk = (frame_cycles * mul) / budget; + base_clk = frame_cycles * mul; + do_div(base_clk, budget); CAM_DBG(CAM_ICP, "budget = %lld fc = %d ib = %lld base_clk = %lld", budget, frame_cycles, @@ -1408,6 +1416,7 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, struct cam_icp_hw_ctx_data *ctx_data) { uint32_t id; + uint64_t temp; int i = 0; struct cam_hw_intf *ipe0_dev_intf = NULL; struct cam_hw_intf *ipe1_dev_intf = NULL; @@ -1463,16 +1472,17 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, clk_update.axi_vote.axi_path[0].transac_type = CAM_IPE_DEFAULT_AXI_TRANSAC; } - clk_update.axi_vote.axi_path[0].camnoc_bw = - clk_info->uncompressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].mnoc_ab_bw = - clk_info->compressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].mnoc_ib_bw = - clk_info->compressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].ddr_ab_bw = - clk_info->compressed_bw / device_share_ratio; - clk_update.axi_vote.axi_path[0].ddr_ib_bw = - clk_info->compressed_bw / device_share_ratio; + + temp = clk_info->uncompressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].camnoc_bw = temp; + + temp = clk_info->compressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].mnoc_ab_bw = temp; + clk_update.axi_vote.axi_path[0].mnoc_ib_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ab_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ib_bw = temp; } else { clk_update.axi_vote.num_paths = clk_info->num_paths; memcpy(&clk_update.axi_vote.axi_path[0], @@ -1482,16 +1492,21 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, if (device_share_ratio > 1) { for (i = 0; i < clk_update.axi_vote.num_paths; i++) { - clk_update.axi_vote.axi_path[i].camnoc_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].mnoc_ab_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].mnoc_ib_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].ddr_ab_bw /= - device_share_ratio; - clk_update.axi_vote.axi_path[i].ddr_ib_bw /= - device_share_ratio; + do_div( + clk_update.axi_vote.axi_path[i].camnoc_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ib_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ib_bw, + device_share_ratio); } } } @@ -3877,7 +3892,7 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, int rc = 0; int i; int num_cmd_buf = 0; - uint64_t addr; + dma_addr_t addr; size_t len; struct cam_cmd_buf_desc *cmd_desc = NULL; uintptr_t cpu_addr = 0; @@ -4020,7 +4035,7 @@ static int cam_icp_process_stream_settings( { int rc = 0, i = 0; size_t packet_size, map_cmd_size, len; - uint64_t iova; + dma_addr_t iova; unsigned long rem_jiffies; int timeout = 5000; struct hfi_cmd_ipe_bps_map *map_cmd; @@ -4298,7 +4313,7 @@ static int cam_icp_process_generic_cmd_buffer( struct cam_packet *packet, struct cam_icp_hw_ctx_data *ctx_data, int32_t index, - uint64_t *io_buf_addr) + dma_addr_t *io_buf_addr) { int i, rc = 0; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -4394,7 +4409,7 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, bool *mem_found) { - uint64_t iova_addr; + dma_addr_t iova_addr; size_t src_buf_size; int i; int j; @@ -5056,7 +5071,7 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { int rc = 0, bitmap_size = 0; uint32_t ctx_id = 0, dev_type; - uint64_t io_buf_addr; + dma_addr_t io_buf_addr; size_t io_buf_size; struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_icp_hw_ctx_data *ctx_data = NULL; diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index fb7fff082114..b26bfc0dff65 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -135,7 +135,7 @@ struct clk_work_data { */ struct icp_frame_info { uint64_t request_id; - uint64_t io_config; + dma_addr_t io_config; struct hfi_cmd_ipebps_async hfi_cfg_io_cmd; }; @@ -262,7 +262,7 @@ struct cam_icp_hw_ctx_data { struct icp_cmd_generic_blob { struct cam_icp_hw_ctx_data *ctx; uint32_t frame_info_idx; - uint64_t *io_buf_addr; + dma_addr_t *io_buf_addr; }; /** diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 5698e73bbd32..17411f6dc762 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -24,9 +24,9 @@ static const char isp_dev_name[] = "cam-isp"; static struct cam_isp_ctx_debug isp_ctx_debug; -#define INC_STATE_MONITOR_HEAD(head) \ - (atomic64_add_return(1, head) % \ - CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) +#define INC_STATE_MONITOR_HEAD(head, ret) \ + div_u64_rem(atomic64_add_return(1, head),\ + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, (ret)) static int cam_isp_context_dump_active_request(void *data, unsigned long iova, uint32_t buf_info); @@ -39,7 +39,9 @@ static void __cam_isp_ctx_update_state_monitor_array( enum cam_isp_state_change_trigger trigger_type, uint64_t req_id) { - int iterator = INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head); + int iterator; + + INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head, &iterator); ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state = ctx_isp->substate_activated; @@ -117,8 +119,8 @@ static void __cam_isp_ctx_dump_state_monitor_array( oldest_entry = 0; } else { num_entries = CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; - oldest_entry = (state_head + 1) % - CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; + div_u64_rem(state_head + 1, + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, &oldest_entry); } CAM_ERR(CAM_ISP, diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 0b224ade013e..3c82c6b2f8e5 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -689,16 +689,19 @@ static void cam_ife_hw_mgr_dump_acq_data( struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; struct cam_isp_resource_node *hw_res = NULL; struct timespec64 *ts = NULL; - uint64_t ms, tmp; + uint64_t ms, tmp, hrs, min, sec; int i = 0, j = 0; ts = &hwr_mgr_ctx->ts; tmp = ts->tv_sec; ms = (ts->tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); CAM_INFO(CAM_ISP, "**** %llu:%llu:%llu.%llu ctx_idx: %u rdi_only: %s is_dual: %s acquired ****", - (tmp / 3600) % 24, (tmp / 60) % 60, tmp % 60, ms, + hrs, min, sec, ms, hwr_mgr_ctx->ctx_index, (hwr_mgr_ctx->is_rdi_only_context ? "true" : "false"), (hwr_mgr_ctx->is_dual ? "true" : "false")); @@ -5688,7 +5691,7 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, bool *mem_found) { - uint64_t iova_addr; + dma_addr_t iova_addr; size_t src_buf_size; int i; int j; diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 9c95b587df26..86a14229915f 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -465,8 +465,8 @@ int cam_isp_add_io_buffers( uint32_t size_isp_out, bool fill_fence) { - int rc = 0; - uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + int rc = 0; + dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; struct cam_buf_io_cfg *io_cfg; struct cam_isp_resource_node *res; struct cam_ife_hw_mgr_res *hw_mgr_res; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 741b41d4cccf..7ac79feb2a9f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -201,7 +201,7 @@ struct cam_isp_hw_cmd_buf_update { * */ struct cam_isp_hw_get_wm_update { - uint64_t *image_buf; + dma_addr_t *image_buf; uint32_t num_buf; struct cam_buf_io_cfg *io_cfg; }; diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index c9ec8d1b39f1..9f331d46221c 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -611,7 +611,7 @@ static void cam_jpeg_mgr_print_io_bufs(struct cam_packet *packet, int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, bool *mem_found) { - uint64_t iova_addr; + dma_addr_t iova_addr; size_t src_buf_size; int i; int j; diff --git a/drivers/cam_lrme/cam_lrme_context.h b/drivers/cam_lrme/cam_lrme_context.h index 8dfdc36501a9..9fb88ed85f1b 100644 --- a/drivers/cam_lrme/cam_lrme_context.h +++ b/drivers/cam_lrme/cam_lrme_context.h @@ -11,7 +11,7 @@ #include "cam_hw_mgr_intf.h" #include "cam_req_mgr_interface.h" -#define CAM_LRME_CTX_INDEX_SHIFT 32 +#define CAM_LRME_CTX_INDEX_SHIFT 16 /** * struct cam_lrme_context diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 90b3f3fa442a..40700bbce9e0 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -144,7 +144,7 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, int rc = -EINVAL; uint32_t num_in_buf, num_out_buf, i, j, plane; struct cam_buf_io_cfg *io_cfg; - uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; size_t size; num_in_buf = 0; diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 49b7e09b2228..a0b1e66f8e0c 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -175,7 +175,7 @@ static void cam_mem_put_slot(int32_t idx) } int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, - uint64_t *iova_ptr, size_t *len_ptr) + dma_addr_t *iova_ptr, size_t *len_ptr) { int rc = 0, idx; diff --git a/drivers/cam_req_mgr/cam_mem_mgr_api.h b/drivers/cam_req_mgr/cam_mem_mgr_api.h index 0bbf094ee1e8..e216a46a3a6f 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr_api.h +++ b/drivers/cam_req_mgr/cam_mem_mgr_api.h @@ -75,7 +75,7 @@ int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp); * @return Status of operation. Negative in case of error. Zero otherwise. */ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, - uint64_t *iova_ptr, size_t *len_ptr); + dma_addr_t *iova_ptr, size_t *len_ptr); /** * @brief: This indicates begin of CPU access. diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 6755eb2954ca..9d5976d86f26 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -375,6 +375,7 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) uint16_t lane_mask = 0, i = 0, cfg_size = 0, temp = 0; uint8_t lane_cnt, lane_pos = 0; uint16_t settle_cnt = 0; + uint64_t intermediate_var; void __iomem *csiphybase; struct csiphy_reg_t *csiphy_common_reg = NULL; struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE]; @@ -484,12 +485,16 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) continue; } - settle_cnt = (csiphy_dev->csiphy_info.settle_time / 200000000); + intermediate_var = csiphy_dev->csiphy_info.settle_time; + do_div(intermediate_var, 200000000); + settle_cnt = intermediate_var; if (csiphy_dev->csiphy_info.combo_mode == 1 && - (lane_pos >= 3)) - settle_cnt = - (csiphy_dev->csiphy_info.settle_time_combo_sensor / - 200000000); + (lane_pos >= 3)) { + intermediate_var = + csiphy_dev->csiphy_info.settle_time_combo_sensor; + do_div(intermediate_var, 200000000); + settle_cnt = intermediate_var; + } for (i = 0; i < cfg_size; i++) { switch (reg_array[lane_pos][i].csiphy_param_type) { case CSIPHY_LANE_ENABLE: diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 55962a8f3e7a..784ea62e0925 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -3546,7 +3546,7 @@ static int cam_populate_smmu_context_banks(struct device *dev, } dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); - dma_set_seg_boundary(dev, DMA_BIT_MASK(64)); + dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64)); end: /* increment count to next bank */ -- GitLab From 898869cd11640dab946477452be8470b3fda9cdb Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 16 Oct 2019 13:41:25 -0700 Subject: [PATCH 129/410] msm: camera: ife: Remove line start addition This change removes line start addition to epoch line config. After CSID crop is applied, the first line that CAMIF receives is already at the required line and therefore number of lines for epoch should just be half of the frame width. CRs-Fixed: 2546941 Change-Id: Ib12b1fc96cedf140672af03862aaf4be65ab38d8 Signed-off-by: Venkat Chinta --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 8e5a30588c52..12cdcb19f2c0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -425,9 +425,8 @@ static int cam_vfe_camif_ver3_resource_start( /* epoch config */ switch (soc_private->cpas_version) { case CAM_CPAS_TITAN_480_V100: - epoch0_line_cfg = ((rsrc_data->last_line - - rsrc_data->first_line) / 4) + - rsrc_data->first_line; + epoch0_line_cfg = (rsrc_data->last_line - + rsrc_data->first_line) / 4; /* epoch line cfg will still be configured at midpoint of the * frame width. We use '/ 4' instead of '/ 2' * cause it is multipixel path -- GitLab From 80560aa9383e3375414f1385bed6c8eb43a89c85 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Fri, 4 Oct 2019 09:52:24 -0700 Subject: [PATCH 130/410] msm: camera: isp: Add log for first SOF in EPCR This change adds a log for first SOF in early PCR. CRs-Fixed: 2546941 Change-Id: Iaca8695f0886fecba84e40b06798818b3f864c35 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 17411f6dc762..a06ce0b3d7b3 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1125,8 +1125,9 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); - CAM_DBG(CAM_ISP, "next substate %d", - ctx_isp->substate_activated); + CAM_INFO(CAM_ISP, + "First SOF in EPCR ctx:%d frame_id:%lld next substate %d", + ctx->ctx_id, ctx_isp->frame_id, ctx_isp->substate_activated); return rc; } -- GitLab From faf531221131e59968c4ab1503c891c3c226da67 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Thu, 17 Oct 2019 14:58:21 +0530 Subject: [PATCH 131/410] msm: camera: csiphy: Update CPHY 3-phase registers for CSIPHY v1.2 Fix CSI_EXTRA_CTRL12 CPHY 3phase registers as per the latest HPG (rev. H). CRs-Fixed: 2542855 Change-Id: I6c2fbc66df52db71c454c86ee894c05d12e0dead Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index cc6c1adb366c..35e2a4ab1d6a 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -334,7 +334,7 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AB0, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -369,7 +369,7 @@ csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BB0, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, -- GitLab From ec8b26eda2bbf98a99da0c8d03a06f1d4b256fd5 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 15 Oct 2019 17:24:18 -0700 Subject: [PATCH 132/410] msm: camera: ife: Remove duplicate add to port counters This change removes duplicate add to port counters during IFE acquire. CRs-Fixed: 2546941 Change-Id: Ie42838a2e66200a5a52cc27600bd25e430c0e3f0 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 3c82c6b2f8e5..05b41a7d8def 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2409,8 +2409,8 @@ static int cam_ife_mgr_acquire_hw_for_ctx( goto err; } - *num_pix_port += ipp_count + ppp_count + ife_rd_count + lcr_count; - *num_rdi_port += rdi_count; + *num_pix_port = ipp_count + ppp_count + ife_rd_count + lcr_count; + *num_rdi_port = rdi_count; return 0; err: -- GitLab From 69fc708d01521f60d972fdc478992ef73242e117 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 17 Oct 2019 18:31:30 -0700 Subject: [PATCH 133/410] msm: camera: icp: Fix AHB, AXI voting in icp Due to a mismatched internal structure num_paths for AXI voting is always set to 0 for ipe, bps which is causing not to vote any AXI bandwidth for these hws. After all contexts associated with a device go to inactive state, reduce the AHB vote to minimum value to make sure previously voted high AHB vote doesn't remain for the rest of camera session. CRs-Fixed: 2546088 Change-Id: I7621bb85280b2541ed37a87c9e486dd6be62ea24 Signed-off-by: Pavan Kumar Chilamkurthi --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 48 ++++++++++++++++--- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 2 + 2 files changed, 43 insertions(+), 7 deletions(-) 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 786fd0e98f32..a02adb4cb202 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 @@ -431,6 +431,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) struct cam_icp_cpas_vote clk_update; int i = 0; int device_share_ratio = 1; + uint64_t total_ab_bw = 0; if (!ctx_data) { CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk"); @@ -494,10 +495,6 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) device_share_ratio = 2; - clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC; - clk_update.ahb_vote.vote.freq = 0; - clk_update.ahb_vote_valid = false; - if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { clk_update.axi_vote.num_paths = 1; if (ctx_data->icp_dev_acquire_info->dev_type == @@ -516,6 +513,8 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) clk_info->compressed_bw -= ctx_data->clk_info.compressed_bw; clk_info->uncompressed_bw -= ctx_data->clk_info.uncompressed_bw; + total_ab_bw = clk_info->compressed_bw; + ctx_data->clk_info.uncompressed_bw = 0; ctx_data->clk_info.compressed_bw = 0; ctx_data->clk_info.curr_fc = 0; @@ -580,6 +579,9 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) ctx_data->clk_info.axi_path[i].ddr_ab_bw; clk_info->axi_path[path_index].ddr_ib_bw -= ctx_data->clk_info.axi_path[i].ddr_ib_bw; + + total_ab_bw += + clk_info->axi_path[path_index].mnoc_ab_bw; } memset(&ctx_data->clk_info.axi_path[0], 0, @@ -616,6 +618,16 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) } clk_update.axi_vote_valid = true; + + if (total_ab_bw == 0) { + /* If no more contexts are active, reduce AHB vote to minimum */ + clk_update.ahb_vote.type = CAM_VOTE_ABSOLUTE; + clk_update.ahb_vote.vote.level = CAM_LOWSVS_VOTE; + clk_update.ahb_vote_valid = true; + } else { + clk_update.ahb_vote_valid = false; + } + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, &clk_update, sizeof(clk_update)); @@ -1061,7 +1073,8 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, if (!update_required) { CAM_DBG(CAM_ICP, - "Incoming BW hasn't changed, no update required"); + "Incoming BW hasn't changed, no update required, num_paths=%d", + clk_info->num_paths); return false; } @@ -1326,6 +1339,9 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, } else if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V2) { clk_info_v2 = &ctx_data->hfi_frame_process.clk_info_v2[idx]; + CAM_DBG(CAM_ICP, "index=%d, num_paths=%d, ctx_data=%pK", + idx, clk_info_v2->num_paths, ctx_data); + bw_updated = cam_icp_update_bw_v2(hw_mgr, ctx_data, hw_mgr_clk_info, clk_info_v2, busy); @@ -4138,6 +4154,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, size_t io_buf_size, clk_update_size; int rc = 0; uintptr_t pResource; + uint32_t i = 0; if (!blob_data || (blob_size == 0)) { CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data, @@ -4241,9 +4258,26 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, clk_info->frame_cycles = clk_info_v2->frame_cycles; clk_info->rt_flag = clk_info_v2->rt_flag; - CAM_DBG(CAM_ICP, "budget=%llu, frame_cycle=%llu, rt_flag=%d", + CAM_DBG(CAM_ICP, + "budget=%llu, frame_cycle=%llu, rt_flag=%d, num_paths=%d, clk_update_size=%d, index=%d, ctx_data=%pK", clk_info_v2->budget_ns, clk_info_v2->frame_cycles, - clk_info_v2->rt_flag); + clk_info_v2->rt_flag, + clk_info_v2->num_paths, + clk_update_size, + index, + ctx_data); + + for (i = 0; i < clk_info_v2->num_paths; i++) { + CAM_DBG(CAM_ICP, + "[%d] : path_type=%d, trans_type=%d, camnoc=%lld, mnoc_ab=%lld, mnoc_ib=%lld", + i, + clk_info_v2->axi_path[i].path_data_type, + clk_info_v2->axi_path[i].transac_type, + clk_info_v2->axi_path[i].camnoc_bw, + clk_info_v2->axi_path[i].mnoc_ab_bw, + clk_info_v2->axi_path[i].mnoc_ib_bw); + } + break; case CAM_ICP_CMD_GENERIC_BLOB_CFG_IO: diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index b26bfc0dff65..7ca32efd9318 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -145,6 +145,7 @@ struct icp_frame_info { * @budget_ns: Time required to process frame * @frame_cycles: Frame cycles needed to process the frame * @rt_flag: Flag to indicate real time stream + * @reserved: Reserved filed. * @num_paths: Number of paths for per path bw vote * @axi_path: Per path vote info for IPE/BPS */ @@ -152,6 +153,7 @@ struct cam_icp_clk_bw_req_internal_v2 { uint64_t budget_ns; uint32_t frame_cycles; uint32_t rt_flag; + uint32_t reserved; uint32_t num_paths; struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; }; -- GitLab From 1fdbf849b90cd1f9d81b31cef4467fcba9e0d2ca Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Thu, 17 Oct 2019 17:34:47 +0530 Subject: [PATCH 134/410] msm: camera: ife: Add packing format support This change adds packing format field for CSID in IFE Lite for version 17x hardware. CRs-Fixed: 2547147 Change-Id: Ib6b8331af6a425314a507e18486c1fffd819007a Signed-off-by: Trishansh Bhardwaj --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h index 0573e30d151e..4d8783ce0c0f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_LITE17X_H_ @@ -286,6 +286,7 @@ static const struct cam_ife_csid_common_reg_offset .path_rst_stb_all = 0x7f, .path_rst_done_shift_val = 1, .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, .dt_id_shift_val = 27, .vc_shift_val = 22, .dt_shift_val = 16, -- GitLab From efffa6d11a6db87eab41ac73e4d2079bd0ef1229 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 17 Oct 2019 11:36:29 -0700 Subject: [PATCH 135/410] msm: camera: isp: Dump isp req for cdm timeout Print out CDM command buffers to check for invalid command entry. CRs-Fixed: 2549972 Change-Id: I5998e62e4ba72fa67394ddf92a4680bc1c909597 Signed-off-by: Vishalsingh Hajeri --- drivers/cam_isp/cam_isp_context.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index a06ce0b3d7b3..56f51b124a43 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3734,6 +3734,8 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, CAM_ERR(CAM_ISP, "Start HW failed"); ctx->state = CAM_CTX_READY; trace_cam_context_state("ISP", ctx); + if (rc == -ETIMEDOUT) + cam_isp_ctx_dump_req(req_isp); list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); goto end; -- GitLab From 04cf1dd4ae4ce5a3ecaf3c7cff09c43198389278 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 17 Oct 2019 14:14:09 -0700 Subject: [PATCH 136/410] msm: camera: isp: Change state immediately in flush This commit changes the isp context state to flushed state immediately in order to ignore any further IRQs from the HW. CRs-Fixed: 2546941 Change-Id: I47f4999a3f51b581697e8dbfd07ef1539b478766 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 56 +++++++++++++++++++------------ 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 56f51b124a43..200e869f68bb 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -689,9 +689,10 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( if (done_next_req.num_handles) { struct cam_isp_hw_done_event_data unhandled_res; - struct cam_ctx_request *next_req = list_next_entry(req, list); + struct cam_ctx_request *next_req = list_last_entry( + &ctx->active_req_list, struct cam_ctx_request, list); - if (next_req) { + if (next_req->request_id != req->request_id) { /* * Few resource handles are already signalled in the * current request, lets check if there is another @@ -719,6 +720,10 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( CAM_ERR(CAM_ISP, "BUF Done not handled for next request %lld", next_req->request_id); + } else { + CAM_WARN(CAM_ISP, + "Req %lld only active request, spurious buf_done rxd", + req->request_id); } } @@ -2103,6 +2108,7 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, } } req_isp->reapply = false; + list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); } @@ -2127,33 +2133,37 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_hw_cmd_args hw_cmd_args; ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; - if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { - CAM_INFO(CAM_ISP, "Last request id to flush is %lld", - flush_req->req_id); - ctx->last_flush_req = flush_req->req_id; - } CAM_DBG(CAM_ISP, "Flush pending list"); spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); - memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); - hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; - hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH; - rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, - &hw_cmd_args); - if (rc) { - CAM_ERR(CAM_ISP, "Reg dump on flush failed rc: %d", rc); - rc = 0; - } - if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { if (ctx->state <= CAM_CTX_READY) { ctx->state = CAM_CTX_ACQUIRED; goto end; } + spin_lock_bh(&ctx->lock); + ctx->state = CAM_CTX_FLUSHED; + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; + spin_unlock_bh(&ctx->lock); + + CAM_INFO(CAM_ISP, "Last request id to flush is %lld", + flush_req->req_id); + ctx->last_flush_req = flush_req->req_id; + + memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); + hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Reg dump on flush failed rc: %d", rc); + rc = 0; + } + stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx; stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; stop_isp.stop_only = true; @@ -2184,8 +2194,6 @@ static int __cam_isp_ctx_flush_req_in_top_state( if (rc) CAM_ERR(CAM_ISP, "Failed to reset HW rc: %d", rc); - ctx->state = CAM_CTX_FLUSHED; - ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; ctx_isp->init_received = false; } @@ -3025,10 +3033,12 @@ static int __cam_isp_ctx_config_dev_in_top_state( ctx_isp->init_received = true; } else { rc = -EINVAL; - CAM_ERR(CAM_ISP, "Recevied INIT pkt in wrong state"); + CAM_ERR(CAM_ISP, "Recevied INIT pkt in wrong state:%d", + ctx->state); } } else { - if (ctx->state >= CAM_CTX_READY && ctx->ctx_crm_intf->add_req) { + if (ctx->state != CAM_CTX_FLUSHED && ctx->state >= CAM_CTX_READY + && ctx->ctx_crm_intf->add_req) { add_req.link_hdl = ctx->link_hdl; add_req.dev_hdl = ctx->dev_hdl; add_req.req_id = req->request_id; @@ -3043,7 +3053,9 @@ static int __cam_isp_ctx_config_dev_in_top_state( } } else { rc = -EINVAL; - CAM_ERR(CAM_ISP, "Recevied Update in wrong state"); + CAM_ERR(CAM_ISP, + "Recevied update req %lld in wrong state:%d", + req->request_id, ctx->state); } } if (rc) -- GitLab From cb1341b56b2a7ef13d4908b8a02b3a470595034b Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Tue, 1 Oct 2019 15:21:35 -0700 Subject: [PATCH 137/410] msm: camera: jpeg: Add plane stride & slice height debug info Add plane stride and slice height to debug info for verifying JPEG buffer configuration. CRs-Fixed: 2542420 Change-Id: I67fbb0a0da9104b4f9c412a558b62149abb8aec9 Signed-off-by: Karthik Jayakumar --- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 9f331d46221c..27a12377d16e 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -663,15 +663,15 @@ static void cam_jpeg_mgr_print_io_bufs(struct cam_packet *packet, } CAM_INFO(CAM_JPEG, - "pln %d w %d h %d size %d addr 0x%x offset 0x%x memh %x", + "pln %u w %u h %u stride %u slice %u size %d addr 0x%x offset 0x%x memh %x", j, io_cfg[i].planes[j].width, io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + io_cfg[i].planes[j].slice_height, (int32_t)src_buf_size, (unsigned int)iova_addr, io_cfg[i].offsets[j], io_cfg[i].mem_handle[j]); - - iova_addr += io_cfg[i].offsets[j]; } } } -- GitLab From c23b66889006544bc477050ca39614ce97b61741 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 23 Oct 2019 20:06:51 -0700 Subject: [PATCH 138/410] msm: camera: isp: Limit sof_in_epoch log to first frame This change limits SOF in early PCR log to the first frame for that context. This log is needed to catch unexpected reg updates on first frame after stream on. CRs-Fixed: 2553728 Change-Id: Icad85aeab2b095a6b95889c933a2de34acebed80 Signed-off-by: Venkat Chinta Signed-off-by: Vishalsingh Hajeri Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_isp/cam_isp_context.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 200e869f68bb..722680b5c96a 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1130,8 +1130,13 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); - CAM_INFO(CAM_ISP, - "First SOF in EPCR ctx:%d frame_id:%lld next substate %d", + if (ctx_isp->frame_id == 1) + CAM_INFO(CAM_ISP, + "First SOF in EPCR ctx:%d frame_id:%lld next substate %d", + ctx->ctx_id, ctx_isp->frame_id, + ctx_isp->substate_activated); + + CAM_DBG(CAM_ISP, "SOF in epoch ctx:%d frame_id:%lld next substate:%d", ctx->ctx_id, ctx_isp->frame_id, ctx_isp->substate_activated); return rc; -- GitLab From 09e2bdc6bfd6fe084586b295a904f19912046c69 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Mon, 28 Oct 2019 11:33:28 -0700 Subject: [PATCH 139/410] msm: camera: isp: Improve isp substate logging Improve sp substate logging to print state string instead of value. Add handler for reg_update in bubble state to print a warning log indicate the event. CRs-Fixed: 2523062 Change-Id: I95c6f16733a177cbf33099775d8ef7eb049a62b4 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_isp/cam_isp_context.c | 183 +++++++++++++++++++----------- drivers/cam_isp/cam_isp_context.h | 52 ++++----- 2 files changed, 143 insertions(+), 92 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 722680b5c96a..b251d75ac2f5 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -56,7 +56,7 @@ static void __cam_isp_ctx_update_state_monitor_array( } static const char *__cam_isp_ctx_substate_val_to_type( - uint32_t type) + enum cam_isp_ctx_activated_substate type) { switch (type) { case CAM_ISP_CTX_ACTIVATED_SOF: @@ -74,7 +74,7 @@ static const char *__cam_isp_ctx_substate_val_to_type( case CAM_ISP_CTX_ACTIVATED_HALT: return "HALT"; default: - return "CAM_ISP_CTX_INVALID_STATE"; + return "INVALID"; } } @@ -130,7 +130,7 @@ static void __cam_isp_ctx_dump_state_monitor_array( for (i = 0; i < num_entries; i++) { CAM_ERR(CAM_ISP, - "Index[%d] time[%d] : State[%s] Frame[%lld] ReqId[%llu] evt_type[%s]", + "Index[%d] time[%d] : Substate[%s] Frame[%lld] ReqId[%llu] evt_type[%s]", index, ctx_isp->cam_isp_ctx_state_monitor[index].evt_time_stamp, __cam_isp_ctx_substate_val_to_type( @@ -730,15 +730,19 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( return rc; } -static int __cam_isp_ctx_reg_upd_in_epoch_state( +static int __cam_isp_ctx_reg_upd_in_epoch_bubble_state( struct cam_isp_context *ctx_isp, void *evt_data) { if (ctx_isp->frame_id == 1) - CAM_DBG(CAM_ISP, "Reg update for early PCR"); + CAM_DBG(CAM_ISP, "Reg update in Substate[%s] for early PCR", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); else CAM_WARN(CAM_ISP, - "Unexpected reg update in activated substate:%d for frame_id:%lld", - ctx_isp->substate_activated, ctx_isp->frame_id); + "Unexpected reg update in activated Substate[%s] for frame_id:%lld", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), + ctx_isp->frame_id); return 0; } @@ -780,7 +784,9 @@ static int __cam_isp_ctx_reg_upd_in_applied_state( * state so change substate here. */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, request_id); @@ -1073,8 +1079,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_REQ_MGR_SOF_EVENT_ERROR); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_DBG(CAM_ISP, "next substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); end: if (request_id == 0) { req = list_last_entry(&ctx->active_req_list, @@ -1132,12 +1139,15 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, if (ctx_isp->frame_id == 1) CAM_INFO(CAM_ISP, - "First SOF in EPCR ctx:%d frame_id:%lld next substate %d", + "First SOF in EPCR ctx:%d frame_id:%lld next substate %s", ctx->ctx_id, ctx_isp->frame_id, - ctx_isp->substate_activated); + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); - CAM_DBG(CAM_ISP, "SOF in epoch ctx:%d frame_id:%lld next substate:%d", - ctx->ctx_id, ctx_isp->frame_id, ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "SOF in epoch ctx:%d frame_id:%lld next substate:%s", + ctx->ctx_id, ctx_isp->frame_id, + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); return rc; } @@ -1237,7 +1247,9 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_REQ_MGR_SOF_EVENT_SUCCESS); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); end: req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, list); @@ -1718,7 +1730,9 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( rc = -EFAULT; } - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); end: if (req != NULL && !rc) { __cam_isp_ctx_update_state_monitor_array(ctx_isp, @@ -1757,7 +1771,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_epoch, - __cam_isp_ctx_reg_upd_in_epoch_state, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, __cam_isp_ctx_notify_sof_in_activated_state, __cam_isp_ctx_notify_eof_in_activated_state, __cam_isp_ctx_buf_done_in_epoch, @@ -1768,7 +1782,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_activated_state, - NULL, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, __cam_isp_ctx_notify_sof_in_activated_state, __cam_isp_ctx_notify_eof_in_activated_state, __cam_isp_ctx_buf_done_in_bubble, @@ -1830,7 +1844,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_epoch, - __cam_isp_ctx_reg_upd_in_epoch_state, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, __cam_isp_ctx_notify_sof_in_activated_state, __cam_isp_ctx_notify_eof_in_activated_state, __cam_isp_ctx_fs2_buf_done_in_epoch, @@ -1841,7 +1855,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_sof_in_activated_state, - NULL, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, __cam_isp_ctx_notify_sof_in_activated_state, __cam_isp_ctx_notify_eof_in_activated_state, __cam_isp_ctx_buf_done_in_bubble, @@ -1876,7 +1890,7 @@ static struct cam_isp_ctx_irq_ops static int __cam_isp_ctx_apply_req_in_activated_state( struct cam_context *ctx, struct cam_req_mgr_apply_request *apply, - uint32_t next_state) + enum cam_isp_ctx_activated_substate next_state) { int rc = 0; struct cam_ctx_request *req; @@ -1926,8 +1940,10 @@ static int __cam_isp_ctx_apply_req_in_activated_state( goto end; } - CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u", - req->request_id, ctx_isp->substate_activated, ctx->ctx_id); + CAM_DBG(CAM_REQ, "Apply request %lld in Substate[%s] ctx %u", + req->request_id, + __cam_isp_ctx_substate_val_to_type(ctx_isp->substate_activated), + ctx->ctx_id); req_isp = (struct cam_isp_ctx_req *) req->req_priv; if (ctx_isp->active_req_cnt >= 2) { @@ -1976,8 +1992,9 @@ static int __cam_isp_ctx_apply_req_in_activated_state( ctx_isp->last_applied_req_id = apply->request_id; list_del_init(&req->list); list_add_tail(&req->list, &ctx->wait_req_list); - CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld", - next_state, ctx_isp->last_applied_req_id); + CAM_DBG(CAM_ISP, "new substate Substate[%s], applied req %lld", + __cam_isp_ctx_substate_val_to_type(next_state), + ctx_isp->last_applied_req_id); spin_unlock_bh(&ctx->lock); __cam_isp_ctx_update_state_monitor_array(ctx_isp, @@ -1995,15 +2012,19 @@ static int __cam_isp_ctx_apply_req_in_sof( struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; - CAM_DBG(CAM_ISP, "current substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_APPLIED); - CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); if (rc) - CAM_DBG(CAM_ISP, "Apply failed in state %d, rc %d", - ctx_isp->substate_activated, rc); + CAM_DBG(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); return rc; } @@ -2015,15 +2036,19 @@ static int __cam_isp_ctx_apply_req_in_epoch( struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; - CAM_DBG(CAM_ISP, "current substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_APPLIED); - CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); if (rc) - CAM_DBG(CAM_ISP, "Apply failed in state %d, rc %d", - ctx_isp->substate_activated, rc); + CAM_DBG(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); return rc; } @@ -2035,15 +2060,19 @@ static int __cam_isp_ctx_apply_req_in_bubble( struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; - CAM_DBG(CAM_ISP, "current substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED); - CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); if (rc) - CAM_DBG(CAM_ISP, "Apply failed in state %d, rc %d", - ctx_isp->substate_activated, rc); + CAM_DBG(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); return rc; } @@ -2389,8 +2418,9 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state( else CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); - CAM_DBG(CAM_ISP, "next substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); return rc; } @@ -2411,7 +2441,9 @@ static int __cam_isp_ctx_rdi_only_sof_in_applied_state( ctx_isp->frame_id, ctx_isp->sof_timestamp_val); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED; - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); return 0; } @@ -2507,7 +2539,9 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( /* change the state to bubble, as reg update has not come */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); end: return 0; } @@ -2579,8 +2613,9 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_DBG(CAM_ISP, "next substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); return 0; } @@ -2644,7 +2679,9 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); return 0; error: @@ -2734,15 +2771,19 @@ static int __cam_isp_ctx_rdi_only_apply_req_top_state( struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; - CAM_DBG(CAM_ISP, "current substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, CAM_ISP_CTX_ACTIVATED_APPLIED); - CAM_DBG(CAM_ISP, "new substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); if (rc) - CAM_ERR(CAM_ISP, "Apply failed in state %d, rc %d", - ctx_isp->substate_activated, rc); + CAM_ERR(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); return rc; } @@ -3808,7 +3849,9 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( spin_lock_bh(&ctx->lock); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; spin_unlock_bh(&ctx->lock); - CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); while (!list_empty(&ctx->pending_req_list)) { req = list_first_entry(&ctx->pending_req_list, @@ -4032,22 +4075,25 @@ static int __cam_isp_ctx_apply_req(struct cam_context *ctx, (struct cam_isp_context *) ctx->ctx_priv; trace_cam_apply_req("ISP", apply->request_id); - CAM_DBG(CAM_ISP, "Enter: apply req in Substate %d request _id:%lld", - ctx_isp->substate_activated, apply->request_id); + CAM_DBG(CAM_ISP, "Enter: apply req in Substate[%s] request_id:%lld", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), apply->request_id); ctx_ops = &ctx_isp->substate_machine[ctx_isp->substate_activated]; if (ctx_ops->crm_ops.apply_req) { rc = ctx_ops->crm_ops.apply_req(ctx, apply); } else { CAM_WARN_RATE_LIMIT(CAM_ISP, - "No handle function in activated substate %d", - ctx_isp->substate_activated); + "No handle function in activated Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); rc = -EFAULT; } if (rc) CAM_WARN_RATE_LIMIT(CAM_ISP, - "Apply failed in active substate %d rc %d", - ctx_isp->substate_activated, rc); + "Apply failed in active Substate[%s] rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); return rc; } @@ -4067,20 +4113,23 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context, trace_cam_isp_activated_irq(ctx, ctx_isp->substate_activated, evt_id, __cam_isp_ctx_get_event_ts(evt_id, evt_data)); - CAM_DBG(CAM_ISP, "Enter: State %d, Substate %d, evt id %d", - ctx->state, ctx_isp->substate_activated, evt_id); + CAM_DBG(CAM_ISP, "Enter: State %d, Substate[%s], evt id %d", + ctx->state, __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), evt_id); irq_ops = &ctx_isp->substate_machine_irq[ctx_isp->substate_activated]; if (irq_ops->irq_ops[evt_id]) { rc = irq_ops->irq_ops[evt_id](ctx_isp, evt_data); } else { - CAM_DBG(CAM_ISP, "No handle function for substate %d", - ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "No handle function for Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); if (isp_ctx_debug.enable_state_monitor_dump) __cam_isp_ctx_dump_state_monitor_array(ctx_isp); } - CAM_DBG(CAM_ISP, "Exit: State %d Substate %d", - ctx->state, ctx_isp->substate_activated); + CAM_DBG(CAM_ISP, "Exit: State %d Substate[%s]", + ctx->state, __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); spin_unlock(&ctx->lock); return rc; } @@ -4358,7 +4407,9 @@ int cam_isp_context_deinit(struct cam_isp_context *ctx) cam_context_deinit(ctx->base); if (ctx->substate_activated != CAM_ISP_CTX_ACTIVATED_SOF) - CAM_ERR(CAM_ISP, "ISP context substate is invalid"); + CAM_ERR(CAM_ISP, "ISP context Substate[%s] is invalid", + __cam_isp_ctx_substate_val_to_type( + ctx->substate_activated)); memset(ctx, 0, sizeof(*ctx)); return rc; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 1151ca78c052..34f899f65b27 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -180,33 +180,33 @@ struct cam_isp_context_state_monitor { * */ struct cam_isp_context { - struct cam_context *base; - - int64_t frame_id; - uint32_t substate_activated; - atomic_t process_bubble; - uint32_t bubble_frame_cnt; - struct cam_ctx_ops *substate_machine; - struct cam_isp_ctx_irq_ops *substate_machine_irq; - - struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; - struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; - - void *hw_ctx; - uint64_t sof_timestamp_val; - uint64_t boot_timestamp; - int32_t active_req_cnt; - int64_t reported_req_id; - uint32_t subscribe_event; - int64_t last_applied_req_id; - atomic64_t state_monitor_head; - struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ + struct cam_context *base; + + int64_t frame_id; + enum cam_isp_ctx_activated_substate substate_activated; + atomic_t process_bubble; + uint32_t bubble_frame_cnt; + struct cam_ctx_ops *substate_machine; + struct cam_isp_ctx_irq_ops *substate_machine_irq; + + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; + + void *hw_ctx; + uint64_t sof_timestamp_val; + uint64_t boot_timestamp; + int32_t active_req_cnt; + int64_t reported_req_id; + uint32_t subscribe_event; + int64_t last_applied_req_id; + atomic64_t state_monitor_head; + struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; - bool rdi_only_context; - bool hw_acquired; - bool init_received; - bool split_acquire; - unsigned int init_timestamp; + bool rdi_only_context; + bool hw_acquired; + bool init_received; + bool split_acquire; + unsigned int init_timestamp; }; /** -- GitLab From d1469c8f6a123d3a538044bdc8107172ffcfcd66 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 30 Oct 2019 13:39:40 +0530 Subject: [PATCH 140/410] msm: camera: isp: Set device enable flag after enable csid hardware Device enable flag is getting set after configuring the CSID csi rx and csid path configuration. If irq comes after configuring the csi rx hardware then irq handler is not handling as it is checking the device enable flag. So set device enable flag after enabling the hardware. CRs-Fixed: 2541840 Change-Id: I022b6dccef4153c34bc8cf99e7a18e2978f92d3f Signed-off-by: Ravikishore Pampana --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index af9f67286d82..96c88567dc31 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1194,6 +1194,7 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) struct cam_hw_soc_info *soc_info; uint32_t i, val; int clk_lvl; + unsigned long flags; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -1274,6 +1275,10 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", csid_hw->hw_intf->hw_idx, val); + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + return 0; disable_soc: @@ -3257,7 +3262,6 @@ int cam_ife_csid_init_hw(void *hw_priv, struct cam_hw_info *csid_hw_info; struct cam_isp_resource_node *res; const struct cam_ife_csid_reg_offset *csid_reg; - unsigned long flags; if (!hw_priv || !init_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -3338,9 +3342,6 @@ int cam_ife_csid_init_hw(void *hw_priv, if (rc) cam_ife_csid_disable_hw(csid_hw); - spin_lock_irqsave(&csid_hw->lock_state, flags); - csid_hw->device_enabled = 1; - spin_unlock_irqrestore(&csid_hw->lock_state, flags); end: mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; -- GitLab From 4e9f21ee2747c133372160bf5078e56c4e885d0f Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 22 Oct 2019 16:52:22 +0530 Subject: [PATCH 141/410] msm: camera: reqmgr: Remove division on uint64_t Arm arch does not support dividing 64 bit integer, replacing it with do_div call. CRs-Fixed: 2543730 Change-Id: I86f8c706d20978b4c7bfd78c499dacb482c4d37a Signed-off-by: Trishansh Bhardwaj --- drivers/cam_req_mgr/cam_req_mgr_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index be08f48a5f72..427bc87d672e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1198,10 +1198,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( * difference of two SOF timestamp less than * (sync_frame_duration / 5). */ + do_div(sync_frame_duration, 5); if ((link->sof_timestamp > sync_link->sof_timestamp) && (sync_link->sof_timestamp > 0) && (link->sof_timestamp - sync_link->sof_timestamp < - sync_frame_duration / 5) && + sync_frame_duration) && (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { /* -- GitLab From 30b9eed071a10735947f2773711c698a37b76805 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Wed, 30 Oct 2019 15:22:06 +0530 Subject: [PATCH 142/410] msm: camera: common: Fix integer overflow in shift Various drivers are using right shift by 32 to check if dma address is 32 bit addressable. This will result in shift count overflow in 32 bit arch. CRs-Fixed: 2543730 Change-Id: I57e30bc9c0a8179c8d74f3bd3b6567bdfff60741 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 a02adb4cb202..e82c04b44890 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 @@ -4490,7 +4490,7 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, "get src buf address fail rc %d", rc); continue; } - if (iova_addr >> 32) { + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { CAM_ERR(CAM_ICP, "Invalid mapped address"); rc = -EINVAL; continue; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 05b41a7d8def..1f394d8bcad5 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -5740,7 +5740,7 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, io_cfg[i].mem_handle[j]); continue; } - if (iova_addr >> 32) { + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { CAM_ERR(CAM_ISP, "Invalid mapped address"); rc = -EINVAL; continue; diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 27a12377d16e..09b4b8d3e0f6 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -656,7 +656,7 @@ static void cam_jpeg_mgr_print_io_bufs(struct cam_packet *packet, CAM_ERR(CAM_UTIL, "get src buf address fail"); continue; } - if (iova_addr >> 32) { + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { CAM_ERR(CAM_JPEG, "Invalid mapped address"); rc = -EINVAL; continue; -- GitLab From bef4415dc8476866ec2651102667a717dd06fe25 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 29 Oct 2019 11:52:12 +0530 Subject: [PATCH 143/410] msm: camera: common: va_end should follow va_start Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function. CRs-Fixed: 2549155 Change-Id: I6a3214ce863c4af0425d061184cfa44682f89545 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_utils/cam_debug_util.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_utils/cam_debug_util.c b/drivers/cam_utils/cam_debug_util.c index 274980f8bb64..1cd21b2a971d 100644 --- a/drivers/cam_utils/cam_debug_util.c +++ b/drivers/cam_utils/cam_debug_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundataion. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundataion. All rights reserved. */ #include @@ -115,6 +115,7 @@ void cam_debug_log(unsigned int module_id, const char *func, const int line, pr_info("CAM_DBG: %s: %s: %d: %s\n", cam_get_module_name(module_id), func, line, str_buffer); - va_end(args); } + + va_end(args); } -- GitLab From a293b9bfe62f2624e0603e74476c5bd2bc21b620 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Mon, 28 Oct 2019 12:11:02 -0700 Subject: [PATCH 144/410] msm: camera: icp: Use CAM_PERF for clock, bw related logs Use CAM_PERF logging group while printing logs related to clock, bandwidth updates. CRs-Fixed: 2523062 Change-Id: Icaa912ae308c307d55e318c0861850093d0ee456 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_icp/icp_hw/bps_hw/bps_core.c | 16 ++-- drivers/cam_icp/icp_hw/bps_hw/bps_soc.c | 2 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 91 ++++++++++--------- drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c | 16 ++-- drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c | 2 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 21 +++-- 6 files changed, 75 insertions(+), 73 deletions(-) diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c index 232f29c81db6..8a079bd14202 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_core.c @@ -40,7 +40,7 @@ static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info, &cpas_vote->axi_vote); if (rc < 0) - CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + CAM_ERR(CAM_PERF, "cpas vote is failed: %d", rc); return rc; } @@ -171,7 +171,7 @@ static int cam_bps_handle_pc(struct cam_hw_info *bps_dev) hw_info->pwr_ctrl, true, 0x1); if ((pwr_status >> BPS_PWR_ON_MASK)) - CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + CAM_WARN(CAM_PERF, "BPS: pwr_status(%x):pwr_ctrl(%x)", pwr_status, pwr_ctrl); } cam_bps_get_gdsc_control(soc_info); @@ -181,7 +181,7 @@ static int cam_bps_handle_pc(struct cam_hw_info *bps_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return 0; @@ -203,7 +203,7 @@ static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); if (pwr_ctrl & BPS_COLLAPSE_MASK) { - CAM_DBG(CAM_ICP, "BPS: pwr_ctrl set(%x)", pwr_ctrl); + CAM_DBG(CAM_PERF, "BPS: pwr_ctrl set(%x)", pwr_ctrl); cam_cpas_reg_write(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, 0); @@ -214,7 +214,7 @@ static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return rc; @@ -370,7 +370,7 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; int32_t clk_level = 0, err = 0; - CAM_DBG(CAM_ICP, "bps_src_clk rate = %d", (int)clk_rate); + CAM_DBG(CAM_PERF, "bps_src_clk rate = %d", (int)clk_rate); if (!core_info->clk_enable) { if (clk_upd_cmd->ipe_bps_pc_enable) { @@ -390,10 +390,10 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, CAM_ERR(CAM_ICP, "BPS resume failed"); } } - CAM_DBG(CAM_ICP, "clock rate %d", clk_rate); + CAM_DBG(CAM_PERF, "clock rate %d", clk_rate); rc = cam_bps_update_clk_rate(soc_info, clk_rate); if (rc) - CAM_ERR(CAM_ICP, "Failed to update clk"); + CAM_ERR(CAM_PERF, "Failed to update clk %d", clk_rate); err = cam_soc_util_get_clk_level(soc_info, clk_rate, soc_info->src_clk_idx, diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c index bf152d1fc485..481eeafdb0b2 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -140,7 +140,7 @@ int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { - CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + CAM_DBG(CAM_PERF, "clk_rate %d greater than max, reset to %d", clk_rate, soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; 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 a02adb4cb202..a02671a9feea 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 @@ -182,7 +182,7 @@ static bool cam_icp_is_over_clk(struct cam_icp_hw_mgr *hw_mgr, curr_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data, hw_mgr_clk_info->curr_clk); - CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %d %d", + CAM_DBG(CAM_PERF, "bc_idx = %d cc_idx = %d %d %d", base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); @@ -202,7 +202,7 @@ static int cam_icp_get_lower_clk_rate(struct cam_icp_hw_mgr *hw_mgr, if (i > 0) return ctx_data->clk_info.clk_rate[i - 1]; - CAM_DBG(CAM_ICP, "Already clk at lower level"); + CAM_DBG(CAM_PERF, "Already clk at lower level"); return base_clk; } @@ -216,7 +216,7 @@ static int cam_icp_get_next_clk_rate(struct cam_icp_hw_mgr *hw_mgr, if (i < CAM_MAX_VOTE - 1) return ctx_data->clk_info.clk_rate[i + 1]; - CAM_DBG(CAM_ICP, "Already clk at higher level"); + CAM_DBG(CAM_PERF, "Already clk at higher level"); return base_clk; } @@ -256,7 +256,7 @@ static int cam_icp_supported_clk_rates(struct cam_icp_hw_mgr *hw_mgr, for (i = 0; i < CAM_MAX_VOTE; i++) { ctx_data->clk_info.clk_rate[i] = soc_info->clk_rate[i][soc_info->src_clk_idx]; - CAM_DBG(CAM_ICP, "clk_info[%d] = %d", + CAM_DBG(CAM_PERF, "clk_info[%d] = %d", i, ctx_data->clk_info.clk_rate[i]); } @@ -307,7 +307,7 @@ static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data) { if (ctx_data && ctx_data->watch_dog) { ctx_data->watch_dog_reset_counter++; - CAM_DBG(CAM_ICP, "reset timer : ctx_id = %d, counter=%d", + CAM_DBG(CAM_PERF, "reset timer : ctx_id = %d, counter=%d", ctx_data->ctx_id, ctx_data->watch_dog_reset_counter); crm_timer_reset(ctx_data->watch_dog); } @@ -322,7 +322,7 @@ static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr, return; if (hw_mgr->clk_info[device_index].watch_dog) { - CAM_DBG(CAM_ICP, "reset timer : device_index = %d", + CAM_DBG(CAM_PERF, "reset timer : device_index = %d", device_index); crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog); hw_mgr->clk_info[device_index].watch_dog_reset_counter++; @@ -396,7 +396,7 @@ static int32_t cam_icp_deinit_idle_clk(void *priv, void *data) goto done; } - CAM_DBG(CAM_ICP, "Disable %d", clk_info->hw_type); + CAM_DBG(CAM_PERF, "Disable %d", clk_info->hw_type); clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; @@ -441,7 +441,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) mutex_lock(&ctx_data->ctx_mutex); if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) || (ctx_data->watch_dog_reset_counter == 0)) { - CAM_DBG(CAM_ICP, "state %d, counter=%d", + CAM_DBG(CAM_PERF, "state %d, counter=%d", ctx_data->state, ctx_data->watch_dog_reset_counter); mutex_unlock(&ctx_data->ctx_mutex); return 0; @@ -453,7 +453,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) return -EBUSY; } - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", ctx_data->ctx_id, ctx_data->clk_info.uncompressed_bw, @@ -560,7 +560,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) } if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_WARN(CAM_ICP, + CAM_WARN(CAM_PERF, "Invalid path %d, start offset=%d, max=%d", ctx_data->clk_info.axi_path[i] .path_data_type, @@ -641,7 +641,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, id, &clk_update, sizeof(clk_update)); - CAM_DBG(CAM_ICP, "X :ctx_id = %d curr_fc = %u bc = %u", + CAM_DBG(CAM_PERF, "X :ctx_id = %d curr_fc = %u bc = %u", ctx_data->ctx_id, ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); mutex_unlock(&ctx_data->ctx_mutex); @@ -739,7 +739,7 @@ static int cam_icp_ctx_timer_start(struct cam_icp_hw_ctx_data *ctx_data) ctx_data->watch_dog_reset_counter = 0; - CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + CAM_DBG(CAM_PERF, "start timer : ctx_id = %d", ctx_data->ctx_id); return rc; } @@ -767,7 +767,7 @@ static int cam_icp_device_timer_start(struct cam_icp_hw_mgr *hw_mgr) static int cam_icp_ctx_timer_stop(struct cam_icp_hw_ctx_data *ctx_data) { if (ctx_data->watch_dog) { - CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id); + CAM_DBG(CAM_PERF, "stop timer : ctx_id = %d", ctx_data->ctx_id); ctx_data->watch_dog_reset_counter = 0; crm_timer_exit(&ctx_data->watch_dog); ctx_data->watch_dog = NULL; @@ -802,7 +802,7 @@ static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles, base_clk = frame_cycles * mul; do_div(base_clk, budget); - CAM_DBG(CAM_ICP, "budget = %lld fc = %d ib = %lld base_clk = %lld", + CAM_DBG(CAM_PERF, "budget = %lld fc = %d ib = %lld base_clk = %lld", budget, frame_cycles, (long long)(frame_cycles * mul), base_clk); @@ -818,7 +818,7 @@ static bool cam_icp_busy_prev_reqs(struct hfi_frame_process_info *frm_process, for (i = 0, cnt = 0; i < CAM_FRAME_CMD_MAX; i++) { if (frm_process->request_id[i]) { if (frm_process->fw_process_flag[i]) { - CAM_DBG(CAM_ICP, "r id = %lld busy = %d", + CAM_DBG(CAM_PERF, "r id = %lld busy = %d", frm_process->request_id[i], frm_process->fw_process_flag[i]); cnt++; @@ -1010,7 +1010,7 @@ static bool cam_icp_debug_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk; hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_debug_clk; hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_debug_clk; - CAM_DBG(CAM_ICP, "bc = %d cc = %d", + CAM_DBG(CAM_PERF, "bc = %d cc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); return true; } @@ -1025,7 +1025,7 @@ static bool cam_icp_default_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_default_clk; hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_default_clk; hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_default_clk; - CAM_DBG(CAM_ICP, "bc = %d cc = %d", + CAM_DBG(CAM_PERF, "bc = %d cc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); return true; } @@ -1049,7 +1049,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, */ for (i = 0; i < clk_info->num_paths; i++) - CAM_DBG(CAM_ICP, "clk_info camnoc = %lld busy = %d", + CAM_DBG(CAM_PERF, "clk_info camnoc = %lld busy = %d", clk_info->axi_path[i].camnoc_bw, busy); if (clk_info->num_paths == ctx_data->clk_info.num_paths) { @@ -1072,7 +1072,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, } if (!update_required) { - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Incoming BW hasn't changed, no update required, num_paths=%d", clk_info->num_paths); return false; @@ -1104,7 +1104,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, } if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_WARN(CAM_ICP, + CAM_WARN(CAM_PERF, "Invalid path %d, start offset=%d, max=%d", ctx_data->clk_info.axi_path[i].path_data_type, CAM_AXI_PATH_DATA_IPE_START_OFFSET, @@ -1148,7 +1148,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, } if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_WARN(CAM_ICP, + CAM_WARN(CAM_PERF, "Invalid path %d, start offset=%d, max=%d", ctx_data->clk_info.axi_path[i].path_data_type, CAM_AXI_PATH_DATA_IPE_START_OFFSET, @@ -1171,7 +1171,7 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, hw_mgr_clk_info->axi_path[path_index].ddr_ib_bw += ctx_data->clk_info.axi_path[i].ddr_ib_bw; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Consolidate Path Vote : Dev[%s] i[%d] path_idx[%d] : [%s %s] [%lld %lld]", cam_icp_dev_type_to_name( ctx_data->icp_dev_acquire_info->dev_type), @@ -1204,14 +1204,14 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, * recalculate bandwidth of all contexts of same hardware and update * voting of bandwidth */ - CAM_DBG(CAM_ICP, "ubw ctx = %lld clk_info ubw = %lld busy = %d", + CAM_DBG(CAM_PERF, "ubw ctx = %lld clk_info ubw = %lld busy = %d", ctx_data->clk_info.uncompressed_bw, clk_info->uncompressed_bw, busy); if ((clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw) && (ctx_data->clk_info.uncompressed_bw == hw_mgr_clk_info->uncompressed_bw)) { - CAM_DBG(CAM_ICP, "Update not required bw=%lld", + CAM_DBG(CAM_PERF, "Update not required bw=%lld", ctx_data->clk_info.uncompressed_bw); return false; } @@ -1219,7 +1219,8 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, if (busy && (ctx_data->clk_info.uncompressed_bw > clk_info->uncompressed_bw)) { - CAM_DBG(CAM_ICP, "Busy, Update not req existing=%lld, new=%lld", + CAM_DBG(CAM_PERF, + "Busy, Update not req existing=%lld, new=%lld", ctx_data->clk_info.uncompressed_bw, clk_info->uncompressed_bw); return false; @@ -1240,7 +1241,7 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, ctx->clk_info.uncompressed_bw; hw_mgr_clk_info->compressed_bw += ctx->clk_info.compressed_bw; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Current context=[%lld %lld] Total=[%lld %lld]", ctx->clk_info.uncompressed_bw, ctx->clk_info.compressed_bw, @@ -1266,11 +1267,11 @@ static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_BPS); hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; - CAM_DBG(CAM_ICP, "Reset bps timer"); + CAM_DBG(CAM_PERF, "Reset bps timer"); } else { cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_IPE); hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; - CAM_DBG(CAM_ICP, "Reset ipe timer"); + CAM_DBG(CAM_PERF, "Reset ipe timer"); } if (icp_hw_mgr.icp_debug_clk) @@ -1280,7 +1281,7 @@ static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, frame_info = &ctx_data->hfi_frame_process; req_id = frame_info->request_id[idx]; busy = cam_icp_busy_prev_reqs(frame_info, req_id); - CAM_DBG(CAM_ICP, "busy = %d req_id = %lld", busy, req_id); + CAM_DBG(CAM_PERF, "busy = %d req_id = %lld", busy, req_id); clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; if (!clk_info->frame_cycles) @@ -1298,7 +1299,7 @@ static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, rc = cam_icp_update_clk_free(hw_mgr, ctx_data, hw_mgr_clk_info, clk_info, base_clk); - CAM_DBG(CAM_ICP, "bc = %d cc = %d busy = %d overclk = %d uc = %d", + CAM_DBG(CAM_PERF, "bc = %d cc = %d busy = %d overclk = %d uc = %d", hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk, busy, hw_mgr_clk_info->over_clked, rc); @@ -1328,7 +1329,7 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Ctx[%pK][%d] Req[%lld] Current camno=%lld, mnoc=%lld", ctx_data, ctx_data->ctx_id, req_id, hw_mgr_clk_info->uncompressed_bw, @@ -1339,14 +1340,14 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, } else if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V2) { clk_info_v2 = &ctx_data->hfi_frame_process.clk_info_v2[idx]; - CAM_DBG(CAM_ICP, "index=%d, num_paths=%d, ctx_data=%pK", + CAM_DBG(CAM_PERF, "index=%d, num_paths=%d, ctx_data=%pK", idx, clk_info_v2->num_paths, ctx_data); bw_updated = cam_icp_update_bw_v2(hw_mgr, ctx_data, hw_mgr_clk_info, clk_info_v2, busy); for (i = 0; i < hw_mgr_clk_info->num_paths; i++) { - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "Final path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", cam_cpas_axi_util_path_type_to_string( hw_mgr_clk_info->axi_path[i].path_data_type), @@ -1359,7 +1360,7 @@ static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, ctx_data->icp_dev_acquire_info->dev_type)); } } else { - CAM_ERR(CAM_ICP, "Invalid bw config version: %d", + CAM_ERR(CAM_PERF, "Invalid bw config version: %d", ctx_data->bw_config_version); return false; } @@ -1418,7 +1419,7 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, } /* update a5 clock */ - CAM_DBG(CAM_ICP, "Update ICP clk to level [%d]", + CAM_DBG(CAM_PERF, "Update ICP clk to level [%d]", clk_upd_cmd.clk_level); a5_dev_intf->hw_ops.process_cmd(a5_dev_intf->hw_priv, CAM_ICP_A5_CMD_CLK_UPDATE, &clk_upd_cmd.clk_level, @@ -1625,7 +1626,7 @@ static int cam_icp_mgr_ipe_bps_resume(struct cam_icp_hw_mgr *hw_mgr, core_info_mask = ICP_PWR_CLP_IPE0; } - CAM_DBG(CAM_ICP, "core_info %X", core_info_mask); + CAM_DBG(CAM_PERF, "core_info %X", core_info_mask); if (icp_hw_mgr.ipe_bps_pc_flag) rc = hfi_enable_ipe_bps_pc(true, core_info_mask); else @@ -1657,7 +1658,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, dev = ctx_data->icp_dev_acquire_info->dev_type; if (dev == CAM_ICP_RES_TYPE_BPS) { - CAM_DBG(CAM_ICP, "bps ctx cnt %d", hw_mgr->bps_ctxt_cnt); + CAM_DBG(CAM_PERF, "bps ctx cnt %d", hw_mgr->bps_ctxt_cnt); if (ctx_data) --hw_mgr->bps_ctxt_cnt; @@ -1678,7 +1679,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, hw_mgr->bps_clk_state = false; } } else { - CAM_DBG(CAM_ICP, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt); + CAM_DBG(CAM_PERF, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt); if (ctx_data) --hw_mgr->ipe_ctxt_cnt; @@ -2935,7 +2936,7 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) struct cam_hw_intf *a5_dev_intf = NULL; struct cam_hw_info *a5_dev = NULL; - CAM_DBG(CAM_ICP, "ENTER"); + CAM_DBG(CAM_PERF, "ENTER"); a5_dev_intf = hw_mgr->a5_dev_intf; if (!a5_dev_intf) { @@ -2955,7 +2956,7 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); } a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); - CAM_DBG(CAM_ICP, "EXIT"); + CAM_DBG(CAM_PERF, "EXIT"); return rc; } @@ -4168,7 +4169,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, switch (blob_type) { case CAM_ICP_CMD_GENERIC_BLOB_CLK: - CAM_WARN_RATE_LIMIT_CUSTOM(CAM_ICP, 300, 1, + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_PERF, 300, 1, "Using deprecated blob type GENERIC_BLOB_CLK"); if (blob_size != sizeof(struct cam_icp_clk_bw_request)) { CAM_ERR(CAM_ICP, "Mismatch blob size %d expected %lu", @@ -4192,7 +4193,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, soc_req = (struct cam_icp_clk_bw_request *)blob_data; *clk_info = *soc_req; - CAM_DBG(CAM_ICP, "budget:%llu fc: %llu %d BW %lld %lld", + CAM_DBG(CAM_PERF, "budget:%llu fc: %llu %d BW %lld %lld", clk_info->budget_ns, clk_info->frame_cycles, clk_info->rt_flag, clk_info->uncompressed_bw, clk_info->compressed_bw); @@ -4219,7 +4220,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, soc_req_v2 = (struct cam_icp_clk_bw_request_v2 *)blob_data; if (soc_req_v2->num_paths > CAM_ICP_MAX_PER_PATH_VOTES) { - CAM_ERR(CAM_ICP, "Invalid num paths: %d", + CAM_ERR(CAM_PERF, "Invalid num paths: %d", soc_req_v2->num_paths); return -EINVAL; } @@ -4258,7 +4259,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, clk_info->frame_cycles = clk_info_v2->frame_cycles; clk_info->rt_flag = clk_info_v2->rt_flag; - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "budget=%llu, frame_cycle=%llu, rt_flag=%d, num_paths=%d, clk_update_size=%d, index=%d, ctx_data=%pK", clk_info_v2->budget_ns, clk_info_v2->frame_cycles, clk_info_v2->rt_flag, @@ -4268,7 +4269,7 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, ctx_data); for (i = 0; i < clk_info_v2->num_paths; i++) { - CAM_DBG(CAM_ICP, + CAM_DBG(CAM_PERF, "[%d] : path_type=%d, trans_type=%d, camnoc=%lld, mnoc_ab=%lld, mnoc_ib=%lld", i, clk_info_v2->axi_path[i].path_data_type, diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c index a0de07833b72..4263cf7ea669 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -39,7 +39,7 @@ static int cam_ipe_cpas_vote(struct cam_ipe_device_core_info *core_info, &cpas_vote->axi_vote); if (rc) - CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + CAM_ERR(CAM_PERF, "cpas vote is failed: %d", rc); return rc; } @@ -168,7 +168,7 @@ static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev) hw_info->pwr_ctrl, true, 0x1); if (pwr_status >> IPE_PWR_ON_MASK) - CAM_WARN(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + CAM_WARN(CAM_PERF, "BPS: pwr_status(%x):pwr_ctrl(%x)", pwr_status, pwr_ctrl); } @@ -179,7 +179,7 @@ static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return 0; @@ -202,7 +202,7 @@ static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); if (pwr_ctrl & IPE_COLLAPSE_MASK) { - CAM_DBG(CAM_ICP, "IPE pwr_ctrl set(%x)", pwr_ctrl); + CAM_DBG(CAM_PERF, "IPE pwr_ctrl set(%x)", pwr_ctrl); cam_cpas_reg_write(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, 0); @@ -214,7 +214,7 @@ static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) cam_cpas_reg_read(core_info->cpas_handle, CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); - CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x", + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", pwr_ctrl, pwr_status); return rc; @@ -364,7 +364,7 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; int32_t clk_level = 0, err = 0; - CAM_DBG(CAM_ICP, "ipe_src_clk rate = %d", (int)clk_rate); + CAM_DBG(CAM_PERF, "ipe_src_clk rate = %d", (int)clk_rate); if (!core_info->clk_enable) { if (clk_upd_cmd->ipe_bps_pc_enable) { cam_ipe_handle_pc(ipe_dev); @@ -383,11 +383,11 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, CAM_ERR(CAM_ICP, "bps resume failed"); } } - CAM_DBG(CAM_ICP, "clock rate %d", clk_rate); + CAM_DBG(CAM_PERF, "clock rate %d", clk_rate); rc = cam_ipe_update_clk_rate(soc_info, clk_rate); if (rc) - CAM_ERR(CAM_ICP, "Failed to update clk"); + CAM_ERR(CAM_PERF, "Failed to update clk %d", clk_rate); err = cam_soc_util_get_clk_level(soc_info, clk_rate, soc_info->src_clk_idx, diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c index a33c7b68bf97..11cc7f7a3317 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -143,7 +143,7 @@ int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { - CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + CAM_DBG(CAM_PERF, "clk_rate %d greater than max, reset to %d", clk_rate, soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 05b41a7d8def..f9e6e71550cd 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -3239,7 +3239,7 @@ static int cam_isp_blob_bw_update_v2( sizeof( struct cam_vfe_bw_update_args_v2)); if (rc) - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "BW Update failed rc: %d", rc); } else { CAM_WARN(CAM_ISP, "NULL hw_intf!"); @@ -3338,7 +3338,7 @@ static int cam_isp_blob_bw_update( &bw_upd_args, sizeof(struct cam_vfe_bw_update_args)); if (rc) - CAM_ERR(CAM_ISP, "BW Update failed"); + CAM_ERR(CAM_PERF, "BW Update failed"); } else CAM_WARN(CAM_ISP, "NULL hw_intf!"); } @@ -3387,7 +3387,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { if (hw_update_data->bw_config_valid[i] == true) { - CAM_DBG(CAM_ISP, "idx=%d, bw_config_version=%d", + CAM_DBG(CAM_PERF, "idx=%d, bw_config_version=%d", ctx, ctx->ctx_index, i, hw_update_data->bw_config_version); @@ -3397,7 +3397,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, (struct cam_isp_bw_config *) &hw_update_data->bw_config[i], ctx); if (rc) - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "Bandwidth Update Failed rc: %d", rc); } else if (hw_update_data->bw_config_version == CAM_ISP_BW_CONFIG_V2) { @@ -3405,11 +3405,11 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, (struct cam_isp_bw_config_v2 *) &hw_update_data->bw_config_v2[i], ctx); if (rc) - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "Bandwidth Update Failed rc: %d", rc); } else { - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_PERF, "Invalid bw config version: %d", hw_update_data->bw_config_version); } @@ -4876,7 +4876,7 @@ static int cam_isp_blob_clock_update( if (hw_intf && hw_intf->hw_ops.process_cmd) { clock_upd_args.node_res = hw_mgr_res->hw_res[i]; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "res_id=%u i= %d clk=%llu\n", hw_mgr_res->res_id, i, clk_rate); @@ -4889,7 +4889,8 @@ static int cam_isp_blob_clock_update( sizeof( struct cam_vfe_clock_update_args)); if (rc) - CAM_ERR(CAM_ISP, "Clock Update failed"); + CAM_ERR(CAM_PERF, + "Clock Update failed"); } else CAM_WARN(CAM_ISP, "NULL hw_intf!"); } @@ -5115,14 +5116,14 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, rc = cam_isp_blob_clock_update(blob_type, blob_info, clock_config, prepare); if (rc) - CAM_ERR(CAM_ISP, "Clock Update Failed"); + CAM_ERR(CAM_PERF, "Clock Update Failed, rc=%d", rc); } break; case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: { struct cam_isp_bw_config *bw_config; struct cam_isp_prepare_hw_update_data *prepare_hw_data; - CAM_WARN_RATE_LIMIT_CUSTOM(CAM_ISP, 300, 1, + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_PERF, 300, 1, "Deprecated Blob TYPE_BW_CONFIG"); if (blob_size < sizeof(struct cam_isp_bw_config)) { CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); -- GitLab From 2a7ffe96970fc0a5fa09934fb7b7c05b015e230d Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Wed, 30 Oct 2019 17:54:18 -0700 Subject: [PATCH 145/410] msm: camera: sync: Dump fence info in case of fence exhaust Add error message in case of fence exhaust. Add support to dump fence table in case of fence exhaust. CRs-Fixed: 2556458 Change-Id: I9910a04c69b54fe99541524b6581fa9994fd523f Signed-off-by: Karthik Jayakumar --- drivers/cam_sync/cam_sync.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 10ed0cdecebf..0fdc082790a0 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -25,6 +25,24 @@ struct sync_device *sync_dev; */ static bool trigger_cb_without_switch; +static void cam_sync_print_fence_table(void) +{ + int idx; + + for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++) { + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + CAM_INFO(CAM_SYNC, + "index[%u]: sync_id=%d, name=%s, type=%d, state=%d, ref_cnt=%d", + idx, + sync_dev->sync_table[idx].sync_id, + sync_dev->sync_table[idx].name, + sync_dev->sync_table[idx].type, + sync_dev->sync_table[idx].state, + sync_dev->sync_table[idx].ref_cnt); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + } +} + int cam_sync_create(int32_t *sync_obj, const char *name) { int rc; @@ -33,8 +51,13 @@ int cam_sync_create(int32_t *sync_obj, const char *name) do { idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); - if (idx >= CAM_SYNC_MAX_OBJS) + if (idx >= CAM_SYNC_MAX_OBJS) { + CAM_ERR(CAM_SYNC, + "Error: Unable to create sync idx = %d reached max!", + idx); + cam_sync_print_fence_table(); return -ENOMEM; + } CAM_DBG(CAM_SYNC, "Index location available at idx: %ld", idx); bit = test_and_set_bit(idx, sync_dev->bitmap); } while (bit); -- GitLab From 632c43cf64bed71de15e76fd29b74220690a62ee Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Thu, 31 Oct 2019 14:49:12 -0700 Subject: [PATCH 146/410] msm: camera: icp: Remove qcom soc dependency Remove soc_info from icp driver as it was unused. CRs-Fixed: 2557184 Change-Id: I7b85768502f825753ea4b9650b5c3f9df67643fb Signed-off-by: Karthik Jayakumar --- drivers/cam_icp/hfi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index 783b5c3723be..b5d340cb424a 100644 --- a/drivers/cam_icp/hfi.c +++ b/drivers/cam_icp/hfi.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "cam_io_util.h" #include "hfi_reg.h" @@ -20,7 +19,6 @@ #include "hfi_intf.h" #include "cam_icp_hw_mgr_intf.h" #include "cam_debug_util.h" -#include "cam_soc_util.h" #define HFI_VERSION_INFO_MAJOR_VAL 1 #define HFI_VERSION_INFO_MINOR_VAL 1 @@ -681,7 +679,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, struct hfi_qtbl *qtbl; struct hfi_qtbl_hdr *qtbl_hdr; struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr; - uint32_t hw_version, soc_version, fw_version, status = 0; + uint32_t hw_version, fw_version, status = 0; uint32_t retry_cnt = 0; struct sfr_buf *sfr_buffer; @@ -703,7 +701,6 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map)); g_hfi->hfi_state = HFI_DEINIT; - soc_version = socinfo_get_version(); if (debug) { cam_io_w_mb( (uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN | -- GitLab From 15feb22bdd685e1f0b09b0cb14e3021cc7b19dbb Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Fri, 1 Nov 2019 14:59:32 -0700 Subject: [PATCH 147/410] msm: camera: core: Fix extraneous variable declaration Remove an extra variable declaration within a for loop. CRs-Fixed: 2554484 Change-Id: I89885eeb8f89893ad7054d54a694a040e4c0bfbb Signed-off-by: Karthik Jayakumar --- drivers/cam_core/cam_context_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 5ec9c6cdc7b1..dd5bcd455030 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -481,7 +481,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, return rc; put_ctx_ref: - for (j; j >= 0; j--) + for (; j >= 0; j--) cam_context_putref(ctx); put_ref: for (--i; i >= 0; i--) { -- GitLab From 93a5aef8185f86edec60390b1a19ae4ce56bef8d Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 5 Sep 2019 23:45:51 -0700 Subject: [PATCH 148/410] msm: camera: csiphy: Correct Dphy mission mode sequence DPHY mission mode sequence is not full functional for mission mode. Correct and add mandate register settings for the bringup of DPHY mission mode. CRs-Fixed: 2545921 Change-Id: Ia1bbf496c5aa993cf0e404c81f7b69b7b889c6f1 Signed-off-by: Jigarkumar Zala --- .../include/cam_csiphy_1_2_1_hwreg.h | 130 ++++++++---------- 1 file changed, 60 insertions(+), 70 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index 4f9fd086a97d..c78af37b579e 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -14,7 +14,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 21, + .csiphy_2ph_config_array_size = 19, .csiphy_3ph_config_array_size = 34, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -55,118 +55,108 @@ struct csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0600, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From 335b376e21f10f31662533afb6c8f22197ec517c Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 10 Oct 2019 17:22:23 -0700 Subject: [PATCH 149/410] msm: camera: csiphy: Update DPHY combo mode sequence DPHY combo mode bring up sequence is missing with some important register settings. Correct and update required register setting to bringup DPHY combo mode. CRs-Fixed: 2545921 Change-Id: I1dfb71f1775aa6d6b1173a7de7f14ce74eac08e1 Signed-off-by: Jigarkumar Zala --- .../include/cam_csiphy_1_2_1_hwreg.h | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index c78af37b579e..32fbf47eabd9 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -14,7 +14,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 19, + .csiphy_2ph_config_array_size = 20, .csiphy_3ph_config_array_size = 34, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -71,6 +71,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -92,6 +93,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -113,6 +115,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -134,6 +137,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -155,6 +159,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -164,118 +169,113 @@ struct csiphy_reg_t csiphy_2ph_v1_2_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; -- GitLab From c1054611fda69d1131c51a661a0a3d27b2a62aec Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Mon, 4 Nov 2019 13:50:06 -0800 Subject: [PATCH 150/410] msm: camera: utils: Remove deprecated clk_set_flag functions Removed unused functions that called clk_set_flag, which has been deprecated in linux kernel 5.x. CRs-Fixed: 2554484 Change-Id: I0062383b0b059e6b359229f4b33470713289abb4 Signed-off-by: Karthik Jayakumar --- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c | 39 ------------------- drivers/cam_utils/cam_soc_util.c | 12 ------ drivers/cam_utils/cam_soc_util.h | 14 ------- 3 files changed, 65 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c index d05530ae4e17..c3d5a68c6910 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c @@ -71,39 +71,6 @@ static int cam_fd_hw_soc_util_setup_regbase_indices( return 0; } -static int cam_fd_soc_set_clk_flags(struct cam_hw_soc_info *soc_info) -{ - int i, rc = 0; - - if (soc_info->num_clk > CAM_SOC_MAX_CLK) { - CAM_ERR(CAM_FD, "Invalid num clk %d", soc_info->num_clk); - return -EINVAL; - } - - /* set memcore and mem periphery logic flags to 0 */ - for (i = 0; i < soc_info->num_clk; i++) { - if ((strcmp(soc_info->clk_name[i], "fd_core_clk") == 0) || - (strcmp(soc_info->clk_name[i], "fd_core_uar_clk") == - 0)) { - rc = cam_soc_util_set_clk_flags(soc_info, i, - CLKFLAG_NORETAIN_MEM); - if (rc) - CAM_ERR(CAM_FD, - "Failed in NORETAIN_MEM i=%d, rc=%d", - i, rc); - - cam_soc_util_set_clk_flags(soc_info, i, - CLKFLAG_NORETAIN_PERIPH); - if (rc) - CAM_ERR(CAM_FD, - "Failed in NORETAIN_PERIPH i=%d, rc=%d", - i, rc); - } - } - - return rc; -} - void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info, enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value) { @@ -228,12 +195,6 @@ int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info, return rc; } - rc = cam_fd_soc_set_clk_flags(soc_info); - if (rc) { - CAM_ERR(CAM_FD, "failed in set_clk_flags rc=%d", rc); - goto release_res; - } - soc_private = kzalloc(sizeof(struct cam_fd_soc_private), GFP_KERNEL); if (!soc_private) { rc = -ENOMEM; diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 04f2f80b82ba..4e3dacaa822c 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -368,18 +368,6 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, return clk_round_rate(soc_info->clk[clk_index], clk_rate); } -int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, - uint32_t clk_index, unsigned long flags) -{ - if (!soc_info || (clk_index >= soc_info->num_clk)) { - CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d", - soc_info, clk_index); - return -EINVAL; - } - - return clk_set_flags(soc_info->clk[clk_index], flags); -} - /** * cam_soc_util_set_clk_rate() * diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index ad2382b835ef..64320ca7b91d 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -371,20 +371,6 @@ int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, uint32_t clk_index, unsigned long clk_rate); -/** - * cam_soc_util_set_clk_flags() - * - * @brief: Camera SOC util to set the flags for a specified clock - * - * @soc_info: Device soc information - * @clk_index: Clock index in soc_info for which flags are to be set - * @flags: Flags to set - * - * @return: Success or Failure - */ -int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, - uint32_t clk_index, unsigned long flags); - /** * cam_soc_util_set_src_clk_rate() * -- GitLab From b46dcb39c451184c177747bfcc41744b04a9039e Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Mon, 4 Nov 2019 11:38:29 -0800 Subject: [PATCH 151/410] msm: camera: cci: Fix cam_cci_get_subdev for conditional compilation Fixes cci_get_subdev to return NULL or computed value depending on camera driver configuration. CRs-Fixed: 2554484 Change-Id: I79933ddf28e2c0d23739308b57b5b40d3b56d78e Signed-off-by: Karthik Jayakumar --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 11 +++++++++-- drivers/cam_sensor_module/cam_cci/cam_cci_dev.h | 9 +-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index e30574da5c0b..4c2d7af6ca96 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -14,9 +14,16 @@ static struct v4l2_subdev *g_cci_subdev[MAX_CCI]; struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) { + struct v4l2_subdev *sub_device = NULL; + if (cci_dev_index < MAX_CCI) - return g_cci_subdev[cci_dev_index]; - return NULL; + sub_device = g_cci_subdev[cci_dev_index]; + else + CAM_WARN(CAM_CCI, "Index: %u is beyond max num CCI allowed: %u", + cci_dev_index, + MAX_CCI); + + return sub_device; } static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd, diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index 439e3058a70b..21e3e3c80ebe 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -298,14 +298,7 @@ struct cci_write_async { irqreturn_t cam_cci_irq(int irq_num, void *data); -#ifdef CONFIG_SPECTRA_CAMERA -extern struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); -#else -static inline struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) -{ - return NULL; -} -#endif +struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); #define VIDIOC_MSM_CCI_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) -- GitLab From e2085ffb7f216fb38c19c5d4da1cfd96ad41503f Mon Sep 17 00:00:00 2001 From: Mangalaram ARCHANA Date: Fri, 25 Oct 2019 11:55:18 +0530 Subject: [PATCH 152/410] msm: camera: cpas: Fix TCSR Register programming Fix TCSR Register programming to enable SAT. CRs-Fixed: 2553475 Change-Id: Iaeae7cd06dcbccaa8bf1f98657efff734d048b9f Signed-off-by: Mangalaram ARCHANA --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 0543397a8482..1f52e1993a5c 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -514,7 +514,7 @@ static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data) static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) { - int i; + int i, reg_val; struct cam_cpas_hw_errata_wa_list *errata_wa_list = camnoc_info->errata_wa_list; struct cam_cpas_hw_errata_wa *errata_wa = @@ -541,8 +541,9 @@ static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) } if (errata_wa->enable) { - scm_io_write(errata_wa->data.reg_info.offset, - errata_wa->data.reg_info.value); + reg_val = scm_io_read(errata_wa->data.reg_info.offset); + reg_val |= errata_wa->data.reg_info.value; + scm_io_write(errata_wa->data.reg_info.offset, reg_val); } return 0; -- GitLab From 17ea11cdec605a96a7e90a5e44f1c090e9d2d2ee Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 16 Oct 2019 13:36:57 -0700 Subject: [PATCH 153/410] msm: camera: reqmgr: Add provision to obtain exposure time Currently CRM watchdog timer expiry is fixed at 1 second. This will not hold good if the sensor exposure time is increased beyond 1 second. In such situations obtain the time from userspace, and modify the CRM watchdog timer accordingly. CRs-Fixed: 2530691 Change-Id: I6251bcb2b915a9e317caffd350220e249214c8b2 Signed-off-by: Karthik Anantha Ram Signed-off-by: Mukund Madhusudan Atre --- include/uapi/media/cam_req_mgr.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 36471a290ad3..59564609035a 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -183,6 +183,11 @@ struct cam_req_mgr_flush_info { * @bubble_enable: Input Param - Cam req mgr will do bubble recovery if this * flag is set. * @sync_mode: Type of Sync mode for this request + * @additional_timeout: Additional timeout value (in ms) associated with + * this request. This value needs to be 0 in cases where long exposure is + * not configured for the sensor.The max timeout that will be supported + * is 50000 ms + * @reserved: Reserved * @req_id: Input Param - Request Id from which all requests will be flushed */ struct cam_req_mgr_sched_request { @@ -190,6 +195,8 @@ struct cam_req_mgr_sched_request { int32_t link_hdl; int32_t bubble_enable; int32_t sync_mode; + int32_t additional_timeout; + int32_t reserved; int64_t req_id; }; @@ -406,11 +413,13 @@ struct cam_mem_cache_ops_cmd { * @CAM_REQ_MGR_ERROR_TYPE_REQUEST: Error on a single request, not fatal * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered + * @CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE: SOF freeze, can be recovered */ #define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 #define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 #define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 #define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 +#define CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE 4 /** * struct cam_req_mgr_error_msg -- GitLab From a6c3698b1f3e58adc36a77177de58882ba5870c9 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Fri, 18 Oct 2019 16:25:36 -0700 Subject: [PATCH 154/410] msm: camera: reqmgr: Add support to modify timer for long exposure In case of long exposure shots, watchdog timer needs to be modified according to the requested value to avoid trigger. Add support for modifying timer value and changing it back to normal. CRs-Fixed: 2530691 Change-Id: I97bdd92d2ed461066bbf746bc6293094a444f8a5 Signed-off-by: Mukund Madhusudan Atre Signed-off-by: Karthik Anantha Ram --- drivers/cam_req_mgr/cam_req_mgr_core.c | 96 ++++++++++++++++++++++++-- drivers/cam_req_mgr/cam_req_mgr_core.h | 22 +++--- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 427bc87d672e..faa15479ecda 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -443,6 +443,7 @@ static void __cam_req_mgr_flush_req_slot( slot->req_id = -1; slot->skip_idx = 1; slot->recover = 0; + slot->additional_timeout = 0; slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; slot->status = CRM_SLOT_STATUS_NO_REQ; @@ -486,6 +487,7 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, slot->req_id = -1; slot->skip_idx = 0; slot->recover = 0; + slot->additional_timeout = 0; slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; slot->status = CRM_SLOT_STATUS_NO_REQ; @@ -499,6 +501,66 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, } } +/** + * __cam_req_mgr_validate_crm_wd_timer() + * + * @brief : Validate/modify the wd timer based on associated + * timeout with the request + * @link : link pointer + * + */ +static void __cam_req_mgr_validate_crm_wd_timer( + struct cam_req_mgr_core_link *link) +{ + int idx = 0; + int next_frame_timeout = 0, current_frame_timeout = 0; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + + idx = in_q->rd_idx; + __cam_req_mgr_dec_idx( + &idx, (link->max_delay - 1), + in_q->num_slots); + next_frame_timeout = in_q->slot[idx].additional_timeout; + CAM_DBG(CAM_CRM, + "rd_idx: %d idx: %d next_frame_timeout: %d ms", + in_q->rd_idx, idx, next_frame_timeout); + + idx = in_q->rd_idx; + __cam_req_mgr_dec_idx( + &idx, link->max_delay, + in_q->num_slots); + current_frame_timeout = in_q->slot[idx].additional_timeout; + CAM_DBG(CAM_CRM, + "rd_idx: %d idx: %d current_frame_timeout: %d ms", + in_q->rd_idx, idx, current_frame_timeout); + + if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > + link->watchdog->expires) { + CAM_DBG(CAM_CRM, + "Modifying wd timer expiry from %d ms to %d ms", + link->watchdog->expires, + (next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (current_frame_timeout) { + CAM_DBG(CAM_CRM, + "Reset wd timer to current frame from %d ms to %d ms", + link->watchdog->expires, + (current_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (link->watchdog->expires > + CAM_REQ_MGR_WATCHDOG_TIMEOUT) { + CAM_DBG(CAM_CRM, + "Reset wd timer to default from %d ms to %d ms", + link->watchdog->expires, CAM_REQ_MGR_WATCHDOG_TIMEOUT); + crm_timer_modify(link->watchdog, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } +} + /** * __cam_req_mgr_check_for_lower_pd_devices() * @@ -1275,9 +1337,11 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, * - if in applied_state, somthign wrong. * - if in no_req state, no new req */ - CAM_DBG(CAM_REQ, "SOF Req[%lld] idx %d req_status %d link_hdl %x", + CAM_DBG(CAM_REQ, + "SOF Req[%lld] idx %d req_status %d link_hdl %x wd_timeout %d ms", in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx, - in_q->slot[in_q->rd_idx].status, link->link_hdl); + in_q->slot[in_q->rd_idx].status, link->link_hdl, + in_q->slot[in_q->rd_idx].additional_timeout); slot = &in_q->slot[in_q->rd_idx]; if (slot->status == CRM_SLOT_STATUS_NO_REQ) { @@ -1393,6 +1457,9 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, link->trigger_mask |= trigger; + /* Check for any long exposure settings */ + __cam_req_mgr_validate_crm_wd_timer(link); + CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success", slot->req_id, link->link_hdl); spin_lock_bh(&link->link_state_spin_lock); @@ -1641,7 +1708,7 @@ static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) memset(&msg, 0, sizeof(msg)); msg.session_hdl = session->session_hdl; - msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE; msg.u.err_msg.request_id = 0; msg.u.err_msg.link_hdl = link->link_hdl; @@ -2030,6 +2097,7 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) mutex_unlock(&link->req.lock); return -EINVAL; } + slot->additional_timeout = 0; __cam_req_mgr_in_q_skip_idx(in_q, idx); } } @@ -2081,10 +2149,11 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) in_q = link->req.in_q; CAM_DBG(CAM_CRM, - "link_hdl %x req_id %lld at slot %d sync_mode %d is_master:%d", + "link_hdl %x req_id %lld at slot %d sync_mode %d is_master %d exp_timeout_val %d ms", sched_req->link_hdl, sched_req->req_id, in_q->wr_idx, sched_req->sync_mode, - link->is_master); + link->is_master, + sched_req->additional_timeout); mutex_lock(&link->req.lock); slot = &in_q->slot[in_q->wr_idx]; @@ -2098,6 +2167,22 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) slot->sync_mode = sched_req->sync_mode; slot->skip_idx = 0; slot->recover = sched_req->bubble_enable; + if (sched_req->additional_timeout < 0) { + CAM_WARN(CAM_CRM, + "Requested timeout is invalid [%dms]", + sched_req->additional_timeout); + slot->additional_timeout = 0; + } else if (sched_req->additional_timeout > + CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX) { + CAM_WARN(CAM_CRM, + "Requested timeout [%dms] max supported timeout [%dms] resetting to max", + sched_req->additional_timeout, + CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX); + slot->additional_timeout = CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX; + } else { + slot->additional_timeout = sched_req->additional_timeout; + } + link->open_req_cnt++; __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); @@ -3261,6 +3346,7 @@ int cam_req_mgr_schedule_request( sched->req_id = sched_req->req_id; sched->sync_mode = sched_req->sync_mode; sched->link_hdl = sched_req->link_hdl; + sched->additional_timeout = sched_req->additional_timeout; if (session->force_err_recovery == AUTO_RECOVERY) { sched->bubble_enable = sched_req->bubble_enable; } else { diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index c790ce824244..0afdc69b0445 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -13,9 +13,10 @@ #define CAM_REQ_MGR_MAX_LINKED_DEV 16 #define MAX_REQ_SLOTS 48 -#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 5000 -#define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 -#define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 1000 +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX 50000 +#define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 +#define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 #define FORCE_DISABLE_RECOVERY 2 #define FORCE_ENABLE_RECOVERY 1 @@ -226,13 +227,15 @@ struct cam_req_mgr_req_tbl { /** * struct cam_req_mgr_slot * - Internal Book keeping - * @idx : slot index - * @skip_idx : if req id in this slot needs to be skipped/not applied - * @status : state machine for life cycle of a slot + * @idx : slot index + * @skip_idx : if req id in this slot needs to be skipped/not applied + * @status : state machine for life cycle of a slot * - members updated due to external events - * @recover : if user enabled recovery for this request. - * @req_id : mask tracking which all devices have request ready - * @sync_mode : Sync mode in which req id in this slot has to applied + * @recover : if user enabled recovery for this request. + * @req_id : mask tracking which all devices have request ready + * @sync_mode : Sync mode in which req id in this slot has to applied + * @additional_timeout : Adjusted watchdog timeout value associated with + * this request */ struct cam_req_mgr_slot { int32_t idx; @@ -241,6 +244,7 @@ struct cam_req_mgr_slot { int32_t recover; int64_t req_id; int32_t sync_mode; + int32_t additional_timeout; }; /** -- GitLab From fd1db0292d79364c7512cede28b8dd63b25cfe2e Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Thu, 24 Oct 2019 13:49:43 -0700 Subject: [PATCH 155/410] msm: camera: sensor: Remove true/false redefinitions Remove defines in header files that redefine true and false. CRs-Fixed: 2556282 Change-Id: Ibf87f35efd403faa05e72b070dcfca59e0196a29 Signed-off-by: Karthik Jayakumar --- .../cam_actuator/cam_actuator_dev.h | 4 ---- drivers/cam_sensor_module/cam_cci/cam_cci_core.c | 4 ++-- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 14 +++++++------- drivers/cam_sensor_module/cam_cci/cam_cci_dev.h | 3 --- drivers/cam_sensor_module/cam_cci/cam_cci_soc.c | 6 +++--- .../cam_sensor_module/cam_sensor/cam_sensor_dev.h | 3 --- 6 files changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h index e4e5e4305246..e4bfaed4414f 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -30,16 +30,12 @@ #define NUM_MASTERS 2 #define NUM_QUEUES 2 -#define TRUE 1 -#define FALSE 0 - #define ACTUATOR_DRIVER_I2C "i2c_actuator" #define CAMX_ACTUATOR_DEV_NAME "cam-actuator-driver" #define MSM_ACTUATOR_MAX_VREGS (10) #define ACTUATOR_MAX_POLL_COUNT 10 - enum cam_actuator_apply_state_t { ACT_APPLY_SETTINGS_NOW, ACT_APPLY_SETTINGS_LATER, diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index 8701c6b9d62e..a0d1cbe058d9 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -49,8 +49,8 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, } else if (rc == 0) { CAM_ERR(CAM_CCI, "wait timeout"); - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; + /* Set reset pending flag to true */ + cci_dev->cci_master_info[master].reset_pending = true; /* Set proper mask to RESET CMD address based on MASTER */ if (master == MASTER_0) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index e30574da5c0b..f377c07a6c36 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -69,18 +69,18 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { struct cam_cci_master_info *cci_master_info; - if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + if (cci_dev->cci_master_info[MASTER_0].reset_pending == true) { cci_master_info = &cci_dev->cci_master_info[MASTER_0]; cci_dev->cci_master_info[MASTER_0].reset_pending = - FALSE; + false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); cci_master_info->status = 0; } - if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + if (cci_dev->cci_master_info[MASTER_1].reset_pending == true) { cci_master_info = &cci_dev->cci_master_info[MASTER_1]; cci_dev->cci_master_info[MASTER_1].reset_pending = - FALSE; + false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); cci_master_info->status = 0; @@ -205,12 +205,12 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_1"); if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + cci_dev->cci_master_info[MASTER_0].reset_pending = true; cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { - cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; + cci_dev->cci_master_info[MASTER_1].reset_pending = true; cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } @@ -316,7 +316,7 @@ static int cam_cci_irq_routine(struct v4l2_subdev *sd, u32 status, &cci_dev->soc_info; ret = cam_cci_irq(soc_info->irq_line->start, cci_dev); - *handled = TRUE; + *handled = true; return 0; } diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index 439e3058a70b..56798feb5edf 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -42,9 +42,6 @@ #define NUM_MASTERS 2 #define NUM_QUEUES 2 -#define TRUE 1 -#define FALSE 0 - #define CCI_PINCTRL_STATE_DEFAULT "cci_default" #define CCI_PINCTRL_STATE_SLEEP "cci_suspend" diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index 092f42bbe0d9..82f1c61cf8fe 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -52,8 +52,8 @@ int cam_cci_init(struct v4l2_subdev *sd, for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; + /* Set reset pending flag to true */ + cci_dev->cci_master_info[master].reset_pending = true; /* Set proper mask to RESET CMD address */ if (master == MASTER_0) cam_io_w_mb(CCI_M0_RESET_RMSK, @@ -131,7 +131,7 @@ int cam_cci_init(struct v4l2_subdev *sd, } } - cci_dev->cci_master_info[master].reset_pending = TRUE; + cci_dev->cci_master_info[master].reset_pending = true; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h index 37e0affdf991..b1963e15eb59 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -28,9 +28,6 @@ #define NUM_MASTERS 2 #define NUM_QUEUES 2 -#define TRUE 1 -#define FALSE 0 - #undef CDBG #ifdef CAM_SENSOR_DEBUG #define CDBG(fmt, args...) pr_err(fmt, ##args) -- GitLab From 4e13a0294dc401f7c5caf7bf8527ac1f8f52dfc8 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 7 Nov 2019 19:34:58 -0800 Subject: [PATCH 156/410] msm: camera: cpas: Update ife_rd safe lut value Do not set safe_lut value for ife_rd path, default values is good as per recommendation. CRs-Fixed: 2561696 Change-Id: Icce19f7814329d2e96e94d18096aa12069626429 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cpas/cpas_top/cpastop_v480_100.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h index 510b97062fbc..0d46e0ddcc20 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -357,7 +357,7 @@ static struct cam_camnoc_specific .value = 0x0, }, .safe_lut = { - .enable = true, + .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .offset = 0x1048, /* IFE_RDI_RD_SAFELUT_LOW */ .value = 0x0, -- GitLab From 69c67ebc90fbe9d712ac1bee8432f5b20175b6ac Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Thu, 31 Oct 2019 09:50:07 +0530 Subject: [PATCH 157/410] msm: camera: ife: calculate accurate boot timestamp at CSID SOF The boot timestamp is calculated in tasklet context. Due to system performance and scheduling delay, it may vary. It is somtimes causing failure for few time bound test cases. To handle above problem, This change also considers qtime difference to calculate accurate boot time at CSID each SOF. CRs-Fixed: 2557758 Change-Id: I36b21a0f2c12cc1c83c209ab01ea90c0ac226995 Signed-off-by: Alok Pandey --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 63 ++++++++++--------- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 22 ++++++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 4 ++ 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 41d02f06aaf0..998dfd743087 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -5888,41 +5888,42 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( struct cam_hw_intf *hw_intf; struct cam_csid_get_time_stamp_args csid_get_time; - list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!hw_mgr_res->hw_res[i]) - continue; + hw_mgr_res = list_first_entry(&ife_ctx->res_list_ife_csid, + struct cam_ife_hw_mgr_res, list); + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + /* + * Get the SOF time stamp from left resource only. + * Left resource is master for dual vfe case and + * Rdi only context case left resource only hold + * the RDI resource + */ + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { /* - * Get the SOF time stamp from left resource only. - * Left resource is master for dual vfe case and - * Rdi only context case left resource only hold - * the RDI resource + * Single VFE case, Get the time stamp from + * available one csid hw in the context + * Dual VFE case, get the time stamp from + * master(left) would be sufficient */ - hw_intf = hw_mgr_res->hw_res[i]->hw_intf; - if (hw_intf->hw_ops.process_cmd) { - /* - * Single VFE case, Get the time stamp from - * available one csid hw in the context - * Dual VFE case, get the time stamp from - * master(left) would be sufficient - */ - - csid_get_time.node_res = - hw_mgr_res->hw_res[i]; - rc = hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_IFE_CSID_CMD_GET_TIME_STAMP, - &csid_get_time, - sizeof( - struct cam_csid_get_time_stamp_args)); - if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { - *time_stamp = - csid_get_time.time_stamp_val; - *boot_time_stamp = - csid_get_time.boot_timestamp; - } + csid_get_time.node_res = + hw_mgr_res->hw_res[i]; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_CMD_GET_TIME_STAMP, + &csid_get_time, + sizeof( + struct cam_csid_get_time_stamp_args)); + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { + *time_stamp = + csid_get_time.time_stamp_val; + *boot_time_stamp = + csid_get_time.boot_timestamp; } } } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index af9f67286d82..f21c47e5f56d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -534,6 +534,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d", csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; return rc; } @@ -1329,6 +1330,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) spin_unlock_irqrestore(&csid_hw->lock_state, flags); csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; return rc; } @@ -2928,6 +2930,7 @@ static int cam_ife_csid_get_time_stamp( const struct cam_ife_csid_udi_reg_offset *udi_reg; struct timespec64 ts; uint32_t time_32, id; + uint64_t time_delta; time_stamp = (struct cam_csid_get_time_stamp_args *)cmd_args; res = time_stamp->node_res; @@ -2999,9 +3002,22 @@ static int cam_ife_csid_get_time_stamp( CAM_IFE_CSID_QTIMER_MUL_FACTOR, CAM_IFE_CSID_QTIMER_DIV_FACTOR); - get_monotonic_boottime64(&ts); - time_stamp->boot_timestamp = (uint64_t)((ts.tv_sec * 1000000000) + - ts.tv_nsec); + if (!csid_hw->prev_boot_timestamp) { + get_monotonic_boottime64(&ts); + time_stamp->boot_timestamp = + (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + csid_hw->prev_qtimer_ts = 0; + CAM_DBG(CAM_ISP, "timestamp:%lld", + time_stamp->boot_timestamp); + } else { + time_delta = time_stamp->time_stamp_val - + csid_hw->prev_qtimer_ts; + time_stamp->boot_timestamp = + csid_hw->prev_boot_timestamp + time_delta; + } + csid_hw->prev_qtimer_ts = time_stamp->time_stamp_val; + csid_hw->prev_boot_timestamp = time_stamp->boot_timestamp; return 0; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 7bfb0dac4231..863aec341899 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -550,6 +550,8 @@ struct cam_ife_csid_path_cfg { * @binning_enable Flag is set if hardware supports QCFA binning * @binning_supported Flag is set if sensor supports QCFA binning * + * @first_sof_ts first bootime stamp at the start + * @prev_qtimer_ts stores csid timestamp */ struct cam_ife_csid_hw { struct cam_hw_intf *hw_intf; @@ -581,6 +583,8 @@ struct cam_ife_csid_hw { spinlock_t lock_state; uint32_t binning_enable; uint32_t binning_supported; + uint64_t prev_boot_timestamp; + uint64_t prev_qtimer_ts; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, -- GitLab From fdd212fdf315445164ceaf3557adc41a41e75f0c Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 9 Sep 2019 22:48:13 -0700 Subject: [PATCH 158/410] msm: camera: common: Update uapi to support custom hw features This change provides provision to propagate frame id to userspace as part of shutter notification. The change also add new acquire params for IFE when custom HW is in the pipeline. CRs-Fixed: 2524308 Change-Id: Ia6f6efb1edc6e6a01d7b37aeb2787b1e98d8f81e Signed-off-by: Karthik Anantha Ram --- include/uapi/media/cam_isp.h | 5 +++++ include/uapi/media/cam_req_mgr.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 79314b59363f..e4778cfc9cc2 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -126,6 +126,11 @@ #define CAM_ISP_USAGE_RIGHT_PX 2 #define CAM_ISP_USAGE_RDI 3 +/* Acquire with custom hw */ +#define CAM_ISP_ACQ_CUSTOM_NONE 0 +#define CAM_ISP_ACQ_CUSTOM_PRIMARY 1 +#define CAM_ISP_ACQ_CUSTOM_SECONDARY 2 + /* Query devices */ /** * struct cam_isp_dev_cap_info - A cap info for particular hw type diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 59564609035a..adfc1cb32f78 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -444,6 +444,9 @@ struct cam_req_mgr_error_msg { * @timestamp: timestamp of the frame * @link_hdl: link handle associated with this message * @sof_status: sof status success or fail + * @frame_id_meta: refers to the meta for + * that frame in specific usecases + * @reserved: reserved */ struct cam_req_mgr_frame_msg { uint64_t request_id; @@ -451,6 +454,8 @@ struct cam_req_mgr_frame_msg { uint64_t timestamp; int32_t link_hdl; uint32_t sof_status; + uint32_t frame_id_meta; + uint32_t reserved; }; /** -- GitLab From 7583d45a07c083aac9bda7a45bf45f4630ede849 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 4 Nov 2019 11:16:39 -0800 Subject: [PATCH 159/410] msm: camera: reqmgr: Change v4l2 notify error log type In case userspace fails to dequeue a v4l2 event with a valid request, kernel will dump that message as error and rest will be rate limited. CRs-Fixed: 2558548 Change-Id: I1c6769f47d0e1ca4a3ce5c6467f6c280104ae2b8 Signed-off-by: Karthik Anantha Ram --- drivers/cam_req_mgr/cam_req_mgr_dev.c | 42 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index f2452d9c340c..cdb2210a2efb 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -204,31 +204,39 @@ static void cam_v4l2_event_queue_notify_error(const struct v4l2_event *old, ev_header = CAM_REQ_MGR_GET_PAYLOAD_PTR((*old), struct cam_req_mgr_message); + switch (old->id) { case V4L_EVENT_CAM_REQ_MGR_SOF: - CAM_ERR(CAM_CRM, "Failed to notify SOF event"); - CAM_ERR(CAM_CRM, "Sess %X FrameId %lld ReqId %lld link %X", - ev_header->session_hdl, - ev_header->u.frame_msg.frame_id, - ev_header->u.frame_msg.request_id, - ev_header->u.frame_msg.link_hdl); + case V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS: + if (ev_header->u.frame_msg.request_id) + CAM_ERR(CAM_CRM, + "Failed to notify %s Sess %X FrameId %lld FrameMeta %d ReqId %lld link %X", + ((old->id == V4L_EVENT_CAM_REQ_MGR_SOF) ? + "SOF_TS" : "BOOT_TS"), + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.frame_id_meta, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); + else + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_CRM, 5, 1, + "Failed to notify %s Sess %X FrameId %lld FrameMeta %d ReqId %lld link %X", + ((old->id == V4L_EVENT_CAM_REQ_MGR_SOF) ? + "SOF_TS" : "BOOT_TS"), + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.frame_id_meta, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); break; case V4L_EVENT_CAM_REQ_MGR_ERROR: - CAM_ERR(CAM_CRM, "Failed to notify ERROR"); - CAM_ERR(CAM_CRM, "Sess %X ReqId %d Link %X Type %d", - ev_header->u.err_msg.error_type, + CAM_ERR(CAM_CRM, + "Failed to notify ERROR Sess %X ReqId %d Link %X Type %d", + ev_header->session_hdl, ev_header->u.err_msg.request_id, ev_header->u.err_msg.link_hdl, ev_header->u.err_msg.error_type); break; - case V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS: - CAM_ERR(CAM_CRM, "Failed to notify BOOT_TS event"); - CAM_ERR(CAM_CRM, "Sess %X FrameId %lld ReqId %lld link %X", - ev_header->session_hdl, - ev_header->u.frame_msg.frame_id, - ev_header->u.frame_msg.request_id, - ev_header->u.frame_msg.link_hdl); - break; default: CAM_ERR(CAM_CRM, "Failed to notify crm event id %d", old->id); -- GitLab From 8acdfccd8582a6a63fe4dac62bbbdb1dc340e674 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Wed, 23 Oct 2019 12:07:49 +0530 Subject: [PATCH 160/410] msm: camera: csiphy: Update registers for CSIPHY v1.2 Update register settings for CPHY/DPHY/combo DPHY modes as per the latest HPG (revision J). CRs-Fixed: 2563037 Change-Id: I137141a490bedce4632991e5eb12887d0c9fa30e Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 88 ++++++++----------- 1 file changed, 38 insertions(+), 50 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 35e2a4ab1d6a..e00e2bdf344d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,9 +12,9 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 5, + .csiphy_common_array_size = 6, .csiphy_reset_array_size = 4, - .csiphy_2ph_config_array_size = 19, + .csiphy_2ph_config_array_size = 18, .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -23,9 +23,10 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { struct csiphy_reg_t csiphy_common_reg_1_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2[] = { @@ -55,18 +56,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -76,18 +76,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -97,18 +96,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -118,18 +116,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -139,18 +136,17 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -159,23 +155,22 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { }; struct csiphy_reg_t - csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { +csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -185,18 +180,17 @@ struct csiphy_reg_t {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -206,18 +200,17 @@ struct csiphy_reg_t {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -227,18 +220,17 @@ struct csiphy_reg_t {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -248,18 +240,17 @@ struct csiphy_reg_t {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -382,14 +373,11 @@ struct data_rate_settings_t data_rate_delta_table_1_2 = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 6, + .data_rate_reg_array_size = 3, .csiphy_data_rate_regs = { {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { @@ -397,12 +385,12 @@ struct data_rate_settings_t data_rate_delta_table_1_2 = { .bandwidth = 7980000000, .data_rate_reg_array_size = 15, .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x2D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -419,21 +407,21 @@ struct data_rate_settings_t data_rate_delta_table_1_2 = { .bandwidth = 10260000000, .data_rate_reg_array_size = 15, .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x10C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x30C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x50C, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, }, } } -- GitLab From 97c65b5ff3e817f3e641e4b838c25da6fc3065de Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Wed, 6 Nov 2019 16:38:00 +0530 Subject: [PATCH 161/410] msm: camera: csiphy: Update reset sequence for csiphy v1.2 Add a transition of 1 to 0 in the PHY reset register during the PHY reset sequence to fix UNBOUNDED_FRAME errors for CPHY sensor. CRs-Fixed: 2563019 Change-Id: I019e4cfdfa2042416e62b306dca0448d6a05c3b8 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index e00e2bdf344d..20e14a354515 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -13,7 +13,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, - .csiphy_reset_array_size = 4, + .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 18, .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, @@ -33,6 +33,7 @@ struct csiphy_reg_t csiphy_reset_reg_1_2[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; -- GitLab From 313a84b8084a1a25b6fae7c7ebfc6658a32a4c6f Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Fri, 8 Nov 2019 13:33:36 +0530 Subject: [PATCH 162/410] msm: camera: csiphy: Fix csiphy v1.2 skew calibration settings Correct the skew calibration register settings in the DPHY sequence for csiphy v1.2. CRs-Fixed: 2563037 Change-Id: Idd97600b66dd00ff67db902dbd9d649aa005b4ec Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 20e14a354515..3bed231e0246 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -71,7 +71,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -111,7 +111,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -131,7 +131,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -151,7 +151,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, }, }; @@ -171,10 +171,10 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -211,10 +211,10 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -231,10 +231,10 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { -- GitLab From fc8ddd752d08cd9b95d512e361a977f46a2e3f0c Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Wed, 30 Oct 2019 18:30:06 +0530 Subject: [PATCH 163/410] msm: camera: isp: Notify CRM to pause SOF timer after flush Adding CRM interface to stop SOF timer from isp during flush. During flush hardware is getting stop and will not send SOF notification to CRM so need to pause SOF timer. Whenever SOF timer will get expire,do not need to send error to UMD during pause time. CRs-Fixed: 2564389 Change-Id: I6d85f2c658c30dbe211f0ec9d83bca323a5c265b Signed-off-by: Chandan Kumar Jha --- drivers/cam_isp/cam_isp_context.c | 9 ++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 55 +++++++++++++++++++++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 16 ++++++ drivers/cam_req_mgr/cam_req_mgr_timer.h | 12 +++-- 4 files changed, 87 insertions(+), 5 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index b251d75ac2f5..1a66070585e5 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -2165,6 +2165,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_hw_stop_args stop_args; struct cam_hw_reset_args reset_args; struct cam_hw_cmd_args hw_cmd_args; + struct cam_req_mgr_timer_notify timer; ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; @@ -2210,6 +2211,14 @@ static int __cam_isp_ctx_flush_req_in_top_state( CAM_INFO(CAM_ISP, "Stop HW complete. Reset HW next."); CAM_DBG(CAM_ISP, "Flush wait and active lists"); + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_timer) { + timer.link_hdl = ctx->link_hdl; + timer.dev_hdl = ctx->dev_hdl; + timer.state = false; + ctx->ctx_crm_intf->notify_timer(&timer); + } + spin_lock_bh(&ctx->lock); if (!list_empty(&ctx->wait_req_list)) rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index faa15479ecda..00677b9d864e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1744,6 +1744,10 @@ static void __cam_req_mgr_sof_freeze(struct timer_list *timer_data) } link = (struct cam_req_mgr_core_link *)timer->parent; + + if (link->watchdog->pause_timer) + return; + task = cam_req_mgr_workq_get_task(link->workq); if (!task) { CAM_ERR(CAM_CRM, "No empty task"); @@ -2643,6 +2647,52 @@ static int cam_req_mgr_cb_notify_err( return rc; } +/** + * cam_req_mgr_cb_notify_timer() + * + * @brief : Notify SOF timer to pause after flush + * @timer_data : contains information about frame_id, link etc. + * + * @return : 0 on success + * + */ +static int cam_req_mgr_cb_notify_timer( + struct cam_req_mgr_timer_notify *timer_data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + + if (!timer_data) { + CAM_ERR(CAM_CRM, "timer data is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(timer_data->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", timer_data->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + spin_unlock_bh(&link->link_state_spin_lock); + + + if (!timer_data->state) + link->watchdog->pause_timer = true; + +end: + return rc; +} + /** * cam_req_mgr_cb_notify_trigger() * @@ -2682,6 +2732,10 @@ static int cam_req_mgr_cb_notify_trigger( rc = -EPERM; goto end; } + + if (link->watchdog->pause_timer) + link->watchdog->pause_timer = false; + crm_timer_reset(link->watchdog); spin_unlock_bh(&link->link_state_spin_lock); @@ -2711,6 +2765,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { .notify_trigger = cam_req_mgr_cb_notify_trigger, .notify_err = cam_req_mgr_cb_notify_err, .add_req = cam_req_mgr_cb_add_req, + .notify_timer = cam_req_mgr_cb_notify_timer, }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index f4b662dd4138..5df13b26e215 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -14,6 +14,7 @@ struct cam_req_mgr_trigger_notify; struct cam_req_mgr_error_notify; struct cam_req_mgr_add_request; +struct cam_req_mgr_timer_notify; struct cam_req_mgr_device_info; struct cam_req_mgr_core_dev_link_setup; struct cam_req_mgr_apply_request; @@ -35,6 +36,7 @@ typedef int (*cam_req_mgr_notify_trigger)( struct cam_req_mgr_trigger_notify *); typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *); typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); +typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *); /** * @brief: cam req mgr to camera device drivers @@ -64,6 +66,7 @@ struct cam_req_mgr_crm_cb { cam_req_mgr_notify_trigger notify_trigger; cam_req_mgr_notify_err notify_err; cam_req_mgr_add_req add_req; + cam_req_mgr_notify_timer notify_timer; }; /** @@ -206,6 +209,19 @@ struct cam_req_mgr_trigger_notify { uint64_t sof_timestamp_val; }; +/** + * struct cam_req_mgr_timer_notify + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @frame_id : frame id for internal tracking + * @state : timer state i.e ON or OFF + */ +struct cam_req_mgr_timer_notify { + int32_t link_hdl; + int32_t dev_hdl; + bool state; +}; + /** * struct cam_req_mgr_error_notify * @link_hdl : link identifier diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.h b/drivers/cam_req_mgr/cam_req_mgr_timer.h index 9f9ba71a3879..be200f1b2693 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_timer.h +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_TIMER_H_ @@ -12,16 +12,18 @@ #include "cam_req_mgr_core_defs.h" /** struct cam_req_mgr_timer - * @expires : timeout value for timer - * @sys_timer : system timer variable - * @parent : priv data - link pointer - * @timer_cb : callback func which will be called when timeout expires + * @expires : timeout value for timer + * @sys_timer : system timer variable + * @parent : priv data - link pointer + * @timer_cb : callback func which will be called when timeout expires + * @pause_timer : flag to pause SOF timer */ struct cam_req_mgr_timer { int32_t expires; struct timer_list sys_timer; void *parent; void (*timer_cb)(struct timer_list *timer_data); + bool pause_timer; }; /** -- GitLab From 1f409d4bca45932dade1b32feba90bad91068640 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Mon, 11 Nov 2019 11:46:42 +0530 Subject: [PATCH 164/410] msm: camera: reqmgr: Improve master slave sync If link is not ready on master epoch, but it becomes ready on slave epoch, then master skips apply and slave applies request and goes ahead of master. Fix this by skipping apply on slave if master slot in not in applied state. CRs-Fixed: 2562008 Change-Id: Ic612eedfeedf2a6ea50737a49a6f1f31a5de1dc2 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_req_mgr/cam_req_mgr_core.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 00677b9d864e..0a4af3c097d0 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1106,6 +1106,8 @@ static int __cam_req_mgr_check_sync_req_is_ready( int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; uint64_t sync_frame_duration = 0; + uint64_t sof_timestamp_delta = 0; + uint64_t master_slave_diff = 0; bool ready = true, sync_ready = true; if (!link->sync_link) { @@ -1139,6 +1141,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( else sync_frame_duration = DEFAULT_FRAME_DURATION; + sof_timestamp_delta = + link->sof_timestamp >= sync_link->sof_timestamp + ? link->sof_timestamp - sync_link->sof_timestamp + : sync_link->sof_timestamp - link->sof_timestamp; + CAM_DBG(CAM_CRM, "sync link %x last frame_duration is %d ns", sync_link->link_hdl, sync_frame_duration); @@ -1260,11 +1267,10 @@ static int __cam_req_mgr_check_sync_req_is_ready( * difference of two SOF timestamp less than * (sync_frame_duration / 5). */ - do_div(sync_frame_duration, 5); - if ((link->sof_timestamp > sync_link->sof_timestamp) && - (sync_link->sof_timestamp > 0) && - (link->sof_timestamp - sync_link->sof_timestamp < - sync_frame_duration) && + master_slave_diff = sync_frame_duration; + do_div(master_slave_diff, 5); + if ((sync_link->sof_timestamp > 0) && + (sof_timestamp_delta < master_slave_diff) && (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { /* @@ -1287,6 +1293,11 @@ static int __cam_req_mgr_check_sync_req_is_ready( "sync link %x too quickly, skip next frame of sync link", sync_link->link_hdl); link->sync_link_sof_skip = true; + } else if (sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_DBG(CAM_CRM, + "link %x other not applied", link->link_hdl); + return -EAGAIN; } } -- GitLab From a3b0bbaa8cf31466fcff9c3f6e1f6d7f4df8b219 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Wed, 16 Oct 2019 10:39:45 +0530 Subject: [PATCH 165/410] msm: camera: icp: icp debug improvement ON receiving HFI_EVENT_SYS_ERROR event_id as part of sys_error msg and event_data1 is set to HFI_ERR_SYS_FATAL, trigger the crash. CRs-Fixed: 2549369 Change-Id: Iddf56f46b2c07a703a787b0dedebd801081c93d6 Signed-off-by: Tejas Prajapati --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 4 ++++ 1 file changed, 4 insertions(+) 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 a7e6bd9e987f..8bc550bc188d 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 @@ -2361,6 +2361,10 @@ static int cam_icp_mgr_process_fatal_error( if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); + if (event_notify->event_data1 == HFI_ERR_SYS_FATAL) { + CAM_ERR(CAM_ICP, "received HFI_ERR_SYS_FATAL"); + BUG(); + } rc = cam_icp_mgr_trigger_recovery(hw_mgr); cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); } -- GitLab From 09c9b6c054f25110aa69c941723c6cec7d9f0406 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Mon, 11 Nov 2019 11:59:21 +0530 Subject: [PATCH 166/410] msm: camera: icp: Increase MAX_PKT_SIZE_MSGQ for ICP Increase ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS to improve workqueue delay tolerance. CRs-Fixed: 2564981 Change-Id: Ic61e79588a834e651e7b2f5e44acd3fcbc9d8f77 Signed-off-by: Trishansh Bhardwaj --- drivers/cam_icp/fw_inc/hfi_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_icp/fw_inc/hfi_reg.h b/drivers/cam_icp/fw_inc/hfi_reg.h index f67a7044f26b..2a30c1451201 100644 --- a/drivers/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/cam_icp/fw_inc/hfi_reg.h @@ -74,7 +74,7 @@ #define ICP_SHARED_MEM_IN_BYTES (1024 * 1024) #define ICP_UNCACHED_HEAP_SIZE_IN_BYTES (2 * 1024 * 1024) #define ICP_HFI_MAX_PKT_SIZE_IN_WORDS 25600 -#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS 256 +#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS 1024 #define ICP_HFI_QTBL_HOSTID1 0x01000000 #define ICP_HFI_QTBL_STATUS_ENABLED 0x00000001 -- GitLab From 2c2fea11c5534bfde20baa49a9c8b0fa8c1aef5c Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Wed, 13 Nov 2019 00:04:55 -0800 Subject: [PATCH 167/410] msm: camera: isp: Reset overflow pending flag in start hw While start hw, either a fresh start or resume after flush, reset the overflow pending flag as we reset the hw and start fresh with applying init packet. In case where overflow happening at the same time as halt immediately, we set overflow pending flag to true. Eventhough while halt immediate and resume scenario, we reset the hw, not resetting overflow pending flag causes not to apply any new packets while resume. CRs-Fixed: 2565049 Change-Id: Ia9c871402343306945fe1b8f8373659e52630fe2 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 35 +++++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 998dfd743087..94f1c75f6d20 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -3358,9 +3358,10 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, struct cam_ife_hw_mgr_ctx *ctx; struct cam_isp_prepare_hw_update_data *hw_update_data; - CAM_DBG(CAM_ISP, "Enter"); if (!hw_mgr_priv || !config_hw_args) { - CAM_ERR(CAM_ISP, "Invalid arguments"); + CAM_ERR(CAM_ISP, + "Invalid arguments, hw_mgr_priv=%pK, config_hw_args=%pK", + hw_mgr_priv, config_hw_args); return -EINVAL; } @@ -3368,21 +3369,28 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, ctx = (struct cam_ife_hw_mgr_ctx *)cfg->ctxt_to_hw_map; if (!ctx) { CAM_ERR(CAM_ISP, "Invalid context is used"); - return -EPERM; + return -EINVAL; } if (!ctx->ctx_in_use || !ctx->cdm_cmd) { - CAM_ERR(CAM_ISP, "Invalid context parameters"); + CAM_ERR(CAM_ISP, + "Invalid context parameters : ctx_in_use=%d, cdm_cmd=%pK", + ctx->ctx_in_use, ctx->cdm_cmd); + return -EPERM; + } + + if (atomic_read(&ctx->overflow_pending)) { + CAM_DBG(CAM_ISP, + "Ctx[%pK][%d] Overflow pending, cannot apply req %llu", + ctx, ctx->ctx_index, cfg->request_id); return -EPERM; } - if (atomic_read(&ctx->overflow_pending)) - return -EINVAL; hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; hw_update_data->ife_mgr_ctx = ctx; - CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld", - ctx, ctx->ctx_index, cfg->request_id); + CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld, init_packet=%d", + ctx, ctx->ctx_index, cfg->request_id, cfg->init_packet); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { if (hw_update_data->bw_config_valid[i] == true) { @@ -3454,7 +3462,9 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, atomic_set(&ctx->cdm_done, 0); rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); if (rc) { - CAM_ERR(CAM_ISP, "Failed to apply the configs"); + CAM_ERR(CAM_ISP, + "Failed to apply the configs for req %llu, rc %d", + cfg->request_id, rc); return rc; } @@ -3954,11 +3964,16 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } start_only: + + atomic_set(&ctx->overflow_pending, 0); + /* Apply initial configuration */ CAM_DBG(CAM_ISP, "Config HW"); rc = cam_ife_mgr_config_hw(hw_mgr_priv, &start_isp->hw_config); if (rc) { - CAM_ERR(CAM_ISP, "Config HW failed"); + CAM_ERR(CAM_ISP, + "Config HW failed, start_only=%d, rc=%d", + start_isp->start_only, rc); goto cdm_streamoff; } -- GitLab From 809c56ef1683d75ad0542638cda54f6b541519d8 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Mon, 11 Nov 2019 12:15:16 +0530 Subject: [PATCH 168/410] msm: camera: isp: csid hw register reset with IRQ CSID hw register reset is done with the the help of IRQ to make sure it is reset every time before we start a new session. CRs-Fixed: 2563958 Change-Id: I33c870003eb1e99d458b7650b5b3218f61cccd3b Signed-off-by: Tejas Prajapati --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 148 ++++++++++++------ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 1 + 2 files changed, 97 insertions(+), 52 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 570d2ba0e484..2c58913ef1f3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -43,6 +43,8 @@ /* Max CSI Rx irq error count threshold value */ #define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw); static int cam_ife_csid_is_ipp_ppp_format_supported( uint32_t in_format) { @@ -419,7 +421,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) const struct cam_ife_csid_reg_offset *csid_reg; int rc = 0; uint32_t val = 0, i; - uint32_t status; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; csid_reg = csid_hw->csid_info->csid_reg; @@ -434,6 +436,8 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d Csid reset", csid_hw->hw_intf->hw_idx); + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* Mask all interrupts */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); @@ -481,6 +485,8 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + cam_io_w_mb(0x80, soc_info->reg_map[0].mem_base + csid_hw->csid_info->csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); @@ -497,37 +503,14 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr); - /* perform the top CSID HW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, - soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_rst_strobes_addr); - - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - rc = -ETIMEDOUT; - } - - /* perform the SW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, - soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_rst_strobes_addr); - - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - rc = -ETIMEDOUT; - } + /* reset HW regs first, then SW */ + rc = cam_ife_csid_reset_regs(csid_hw, true); + if (rc < 0) + goto end; + rc = cam_ife_csid_reset_regs(csid_hw, false); + if (rc < 0) + goto end; - usleep_range(3000, 3010); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); if (val != 0) @@ -536,6 +519,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->error_irq_count = 0; csid_hw->prev_boot_timestamp = 0; +end: return rc; } @@ -655,7 +639,7 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, return -EINVAL; } - init_completion(complete); + reinit_completion(complete); reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all; /* Reset the corresponding ife csid path */ @@ -1240,6 +1224,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) if (rc) goto disable_soc; + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear all interrupts */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); @@ -1271,6 +1257,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_hw_version_addr); CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", @@ -1564,7 +1552,7 @@ static int cam_ife_csid_enable_csi2( } } - /*Enable the CSI2 rx inerrupts */ + /*Enable the CSI2 rx interrupts */ val = CSID_CSI2_RX_INFO_RST_DONE | CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW | CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | @@ -3093,6 +3081,7 @@ int cam_ife_csid_reset(void *hw_priv, csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; reset = (struct cam_csid_reset_cfg_args *)reset_args; + mutex_lock(&csid_hw->hw_info->hw_mutex); switch (reset->reset_type) { case CAM_IFE_CSID_RESET_GLOBAL: rc = cam_ife_csid_global_reset(csid_hw); @@ -3106,6 +3095,7 @@ int cam_ife_csid_reset(void *hw_priv, rc = -EINVAL; break; } + mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; } @@ -3230,43 +3220,86 @@ int cam_ife_csid_release(void *hw_priv, return rc; } -static int cam_ife_csid_reset_retain_sw_reg( - struct cam_ife_csid_hw *csid_hw) +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw) { int rc = 0; - uint32_t status; const struct cam_ife_csid_reg_offset *csid_reg = csid_hw->csid_info->csid_reg; struct cam_hw_soc_info *soc_info; + uint32_t val = 0; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; + + reinit_completion(&csid_hw->csid_top_complete); + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear the top interrupt first */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + if (reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + /* perform the top CSID registers reset */ + val = reset_hw ? csid_reg->cmn_reg->csid_rst_stb : + csid_reg->cmn_reg->csid_reg_rst_stb; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); - rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_status_addr, - status, (status & 0x1) == 0x1, - CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); - if (rc < 0) { - CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); + + /* + * for SW reset, we enable the IRQ after since the mask + * register has been reset + */ + if (!reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + CAM_DBG(CAM_ISP, "CSID reset start"); + rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr); + if (val & 0x1) { + /* clear top reset IRQ */ + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, + reset_hw ? "hw" : "sw", + rc); + rc = 0; + goto end; + } + CAM_ERR(CAM_ISP, "CSID:%d csid_reset %s fail rc = %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); rc = -ETIMEDOUT; + goto end; } else { - CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", - csid_hw->hw_intf->hw_idx, rc); + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); rc = 0; } - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_clear_addr); - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_irq_cmd_addr); +end: return rc; } @@ -3351,9 +3384,9 @@ int cam_ife_csid_init_hw(void *hw_priv, break; } - rc = cam_ife_csid_reset_retain_sw_reg(csid_hw); + rc = cam_ife_csid_reset_regs(csid_hw, true); if (rc < 0) - CAM_ERR(CAM_ISP, "CSID: Failed in SW reset"); + CAM_ERR(CAM_ISP, "CSID: Failed in HW reset"); if (rc) cam_ife_csid_disable_hw(csid_hw); @@ -3830,7 +3863,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } } + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); /* clear */ + cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) @@ -3860,6 +3897,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); @@ -3871,6 +3910,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); + if (irq_status_top & CSID_TOP_IRQ_DONE) { + CAM_DBG(CAM_ISP, "csid top reset complete"); + complete(&csid_hw->csid_top_complete); + } + if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 863aec341899..4c2ac18089af 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -40,6 +40,7 @@ #define CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW BIT(26) #define CSID_CSI2_RX_INFO_RST_DONE BIT(27) +#define CSID_TOP_IRQ_DONE BIT(0) #define CSID_PATH_INFO_RST_DONE BIT(1) #define CSID_PATH_ERROR_FIFO_OVERFLOW BIT(2) #define CSID_PATH_INFO_SUBSAMPLED_EOF BIT(3) -- GitLab From 5f530223baa4897a4b8278638d8db8a0cae447b1 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Mon, 4 Nov 2019 12:13:04 +0530 Subject: [PATCH 169/410] msm: camera: core: Prevent crash on kref_put kref_put causes crash if refcount is zero. This change prevents crash by checking if refcount value. CRs-Fixed: 2553290 Change-Id: Ie9a950b289cdb2b8fca8c5d025be540d926eadbd Signed-off-by: Trishansh Bhardwaj --- drivers/cam_core/cam_context.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 642d530054d8..1c17422d01d0 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -597,7 +597,12 @@ int cam_context_deinit(struct cam_context *ctx) void cam_context_putref(struct cam_context *ctx) { - kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + if (kref_read(&ctx->refcount)) + kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + else + WARN(1, "ctx %s %d state %d devhdl %X\n", ctx->dev_name, + ctx->ctx_id, ctx->state, ctx->dev_hdl); + CAM_DBG(CAM_CORE, "ctx device hdl %ld, ref count %d, dev_name %s", ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), -- GitLab From a27592f01b63d2291ca5031048aa19614d56660b Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 25 Sep 2019 20:27:50 -0700 Subject: [PATCH 170/410] msm: camera: custom: Add support for acquire_hw_v1 Split the acquire in custom node to acquire device and acquire hw to be in line with IFE for multicamera usecases. CRs-Fixed: 2524308 Change-Id: I7be7d5227dcd304d095d7e3d7fac32800fecc199 Signed-off-by: Karthik Anantha Ram --- drivers/cam_cust/cam_custom_context.c | 231 ++++++++++++++-- drivers/cam_cust/cam_custom_context.h | 2 + .../cam_custom_hw_mgr/cam_custom_hw_mgr.c | 249 ++++++++---------- include/uapi/media/cam_custom.h | 17 ++ 4 files changed, 334 insertions(+), 165 deletions(-) diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index 7f38392a7d57..3e69ebd15109 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/drivers/cam_cust/cam_custom_context.c @@ -19,7 +19,7 @@ #include "cam_custom_context.h" #include "cam_common_util.h" -static const char custom_dev_name[] = "custom hw"; +static const char custom_dev_name[] = "cam-custom"; static int __cam_custom_ctx_handle_irq_in_activated( void *context, uint32_t evt_id, void *evt_data); @@ -275,6 +275,67 @@ static int __cam_custom_stop_dev_in_activated(struct cam_context *ctx, return 0; } +static int __cam_custom_ctx_release_hw_in_top_state( + struct cam_context *ctx, void *cmd) +{ + int rc = 0; + struct cam_hw_release_args rel_arg; + struct cam_req_mgr_flush_request flush_req; + struct cam_custom_context *custom_ctx = + (struct cam_custom_context *) ctx->ctx_priv; + + if (custom_ctx->hw_ctx) { + rel_arg.ctxt_to_hw_map = custom_ctx->hw_ctx; + rc = ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &rel_arg); + custom_ctx->hw_ctx = NULL; + if (rc) + CAM_ERR(CAM_CUSTOM, + "Failed to release HW for ctx:%u", ctx->ctx_id); + } else { + CAM_ERR(CAM_CUSTOM, "No HW resources acquired for this ctx"); + } + + ctx->last_flush_req = 0; + custom_ctx->frame_id = 0; + custom_ctx->active_req_cnt = 0; + custom_ctx->hw_acquired = false; + custom_ctx->init_received = false; + + /* check for active requests as well */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_CUSTOM, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, + &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_ACQUIRED; + + CAM_DBG(CAM_CUSTOM, "Release HW success[%u] next state %d", + ctx->ctx_id, ctx->state); + + return rc; +} + +static int __cam_custom_ctx_release_hw_in_activated_state( + struct cam_context *ctx, void *cmd) +{ + int rc = 0; + + rc = __cam_custom_stop_dev_in_activated(ctx, NULL); + if (rc) + CAM_ERR(CAM_CUSTOM, "Stop device failed rc=%d", rc); + + rc = __cam_custom_ctx_release_hw_in_top_state(ctx, cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Release hw failed rc=%d", rc); + + return rc; +} + static int __cam_custom_release_dev_in_acquired(struct cam_context *ctx, struct cam_release_dev_cmd *cmd) { @@ -283,14 +344,16 @@ static int __cam_custom_release_dev_in_acquired(struct cam_context *ctx, (struct cam_custom_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; - rc = cam_context_release_dev_to_hw(ctx, cmd); - if (rc) - CAM_ERR(CAM_CUSTOM, "Unable to release device"); + if (cmd && ctx_custom->hw_ctx) { + CAM_ERR(CAM_CUSTOM, "releasing hw"); + __cam_custom_ctx_release_hw_in_top_state(ctx, NULL); + } ctx->ctx_crm_intf = NULL; ctx->last_flush_req = 0; ctx_custom->frame_id = 0; ctx_custom->active_req_cnt = 0; + ctx_custom->hw_acquired = false; ctx_custom->init_received = false; if (!list_empty(&ctx->active_req_list)) @@ -381,33 +444,128 @@ static int __cam_custom_ctx_apply_req_in_activated_state( return rc; } -static int __cam_custom_ctx_acquire_dev_in_available(struct cam_context *ctx, - struct cam_acquire_dev_cmd *cmd) +static int __cam_custom_ctx_acquire_hw_v1( + struct cam_context *ctx, void *args) { - int rc; - struct cam_custom_context *custom_ctx; + int rc = 0; + struct cam_acquire_hw_cmd_v1 *cmd = + (struct cam_acquire_hw_cmd_v1 *)args; + struct cam_hw_acquire_args param; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_custom_acquire_hw_info *acquire_hw_info = NULL; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CUSTOM, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } - custom_ctx = (struct cam_custom_context *) ctx->ctx_priv; + CAM_DBG(CAM_CUSTOM, + "session_hdl 0x%x, hdl type %d, res %lld", + cmd->session_handle, cmd->handle_type, cmd->resource_hdl); - if (cmd->num_resources > CAM_CUSTOM_DEV_CTX_RES_MAX) { - CAM_ERR(CAM_CUSTOM, "Too much resources in the acquire"); + if (cmd->handle_type != 1) { + CAM_ERR(CAM_CUSTOM, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + if (cmd->data_size < sizeof(*acquire_hw_info)) { + CAM_ERR(CAM_CUSTOM, "data_size is not a valid value"); + goto end; + } + + acquire_hw_info = kzalloc(cmd->data_size, GFP_KERNEL); + if (!acquire_hw_info) { rc = -ENOMEM; - return rc; + goto end; } - if (cmd->handle_type != 1) { - CAM_ERR(CAM_CUSTOM, "Only user pointer is supported"); - rc = -EINVAL; + CAM_DBG(CAM_CUSTOM, "start copy resources from user"); + + if (copy_from_user(acquire_hw_info, (void __user *)cmd->resource_hdl, + cmd->data_size)) { + rc = -EFAULT; + goto free_res; + } + + memset(¶m, 0, sizeof(param)); + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.acquire_info_size = cmd->data_size; + param.acquire_info = (uint64_t) acquire_hw_info; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Acquire HW failed"); + goto free_res; + } + + ctx_custom->hw_ctx = param.ctxt_to_hw_map; + ctx_custom->hw_acquired = true; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + CAM_DBG(CAM_CUSTOM, + "Acquire HW success on session_hdl 0x%xs for ctx_id %u", + ctx->session_hdl, ctx->ctx_id); + + kfree(acquire_hw_info); + return rc; + +free_res: + kfree(acquire_hw_info); +end: + return rc; +} + +static int __cam_custom_ctx_acquire_dev_in_available( + struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) +{ + int rc = 0; + struct cam_create_dev_hdl req_hdl_param; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CUSTOM, "HW interface is not ready"); + rc = -EFAULT; return rc; } - rc = cam_context_acquire_dev_to_hw(ctx, cmd); - if (!rc) { - ctx->state = CAM_CTX_ACQUIRED; - custom_ctx->hw_ctx = ctx->ctxt_to_hw_map; + CAM_DBG(CAM_CUSTOM, + "session_hdl 0x%x, num_resources %d, hdl type %d, res %lld", + cmd->session_handle, cmd->num_resources, + cmd->handle_type, cmd->resource_hdl); + + if (cmd->num_resources != CAM_API_COMPAT_CONSTANT) { + CAM_ERR(CAM_CUSTOM, "Invalid num_resources 0x%x", + cmd->num_resources); + return -EINVAL; } - CAM_DBG(CAM_CUSTOM, "Acquire done %d", ctx->ctx_id); + req_hdl_param.session_hdl = cmd->session_handle; + req_hdl_param.v4l2_sub_dev_flag = 0; + req_hdl_param.media_entity_flag = 0; + req_hdl_param.ops = ctx->crm_ctx_intf; + req_hdl_param.priv = ctx; + + CAM_DBG(CAM_CUSTOM, "get device handle from bridge"); + ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); + if (ctx->dev_hdl <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_CUSTOM, "Can not create device handle"); + return rc; + } + + cmd->dev_handle = ctx->dev_hdl; + ctx->session_hdl = cmd->session_handle; + ctx->state = CAM_CTX_ACQUIRED; + + CAM_DBG(CAM_CUSTOM, + "Acquire dev success on session_hdl 0x%x for ctx %u", + cmd->session_handle, ctx->ctx_id); + return rc; } @@ -642,6 +800,13 @@ static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { int rc = 0; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + if (!ctx_custom->hw_acquired) { + CAM_ERR(CAM_CUSTOM, "HW not acquired, reject config packet"); + return -EAGAIN; + } rc = __cam_custom_ctx_config_dev(ctx, cmd); @@ -826,6 +991,27 @@ static int __cam_custom_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_custom_ctx_acquire_hw_in_acquired( + struct cam_context *ctx, void *args) +{ + int rc = -EINVAL; + uint32_t api_version; + + if (!ctx || !args) { + CAM_ERR(CAM_CUSTOM, "Invalid input pointer"); + return rc; + } + + api_version = *((uint32_t *)args); + if (api_version == 1) + rc = __cam_custom_ctx_acquire_hw_v1(ctx, args); + else + CAM_ERR(CAM_CUSTOM, "Unsupported api version %d", + api_version); + + return rc; +} + /* top state machine */ static struct cam_ctx_ops cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { @@ -847,8 +1033,10 @@ static struct cam_ctx_ops /* Acquired */ { .ioctl_ops = { + .acquire_hw = __cam_custom_ctx_acquire_hw_in_acquired, .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev_in_acquired, + .release_hw = __cam_custom_ctx_release_hw_in_top_state, }, .crm_ops = { .link = __cam_custom_ctx_link_in_acquired, @@ -866,6 +1054,7 @@ static struct cam_ctx_ops .start_dev = __cam_custom_ctx_start_dev_in_ready, .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev, + .release_hw = __cam_custom_ctx_release_hw_in_top_state, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_ready, @@ -883,6 +1072,8 @@ static struct cam_ctx_ops .release_dev = __cam_custom_ctx_release_dev_in_activated, .config_dev = __cam_custom_ctx_config_dev, + .release_hw = + __cam_custom_ctx_release_hw_in_activated_state, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_activated, diff --git a/drivers/cam_cust/cam_custom_context.h b/drivers/cam_cust/cam_custom_context.h index 91acf1e5ee80..27268b20c526 100644 --- a/drivers/cam_cust/cam_custom_context.h +++ b/drivers/cam_cust/cam_custom_context.h @@ -67,6 +67,7 @@ struct cam_custom_dev_ctx_req { * custom HW will invoke CRM cb at those event. * @active_req_cnt: Counter for the active request * @frame_id: Frame id tracking for the custom context + * @hw_acquired: Flag to indicate if HW is acquired for this context * @req_base: common request structure * @req_custom: custom request structure * @@ -80,6 +81,7 @@ struct cam_custom_context { uint32_t subscribe_event; uint32_t active_req_cnt; int64_t frame_id; + bool hw_acquired; struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; struct cam_custom_dev_ctx_req req_custom[CAM_CTX_REQ_MAX]; }; diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c index 1db06bb3ab1f..f2e5a1ff3407 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c @@ -380,7 +380,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_cid, list) { rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT CID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not INIT CID(id :%d)", hw_mgr_res->res_id); goto deinit_hw; } @@ -391,7 +391,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_csid, list) { rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT CSID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not INIT CSID(id :%d)", hw_mgr_res->res_id); goto deinit_hw; } @@ -411,7 +411,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_csid, list) { rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not START CSID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not START CSID(id :%d)", hw_mgr_res->res_id); goto err; } @@ -422,7 +422,7 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, &ctx->res_list_custom_cid, list) { rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); if (rc) { - CAM_ERR(CAM_ISP, "Can not START CID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not START CID(id :%d)", hw_mgr_res->res_id); goto err; } @@ -760,7 +760,7 @@ static int cam_custom_hw_mgr_release_hw_for_ctx( &custom_ctx->res_list_custom_cid, list) { rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); if (rc) - CAM_ERR(CAM_ISP, "Can not release CID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not release CID(id :%d)", hw_mgr_res->res_id); cam_custom_hw_mgr_put_res( &custom_ctx->free_res_list, &hw_mgr_res); @@ -771,7 +771,7 @@ static int cam_custom_hw_mgr_release_hw_for_ctx( &custom_ctx->res_list_custom_csid, list) { rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); if (rc) - CAM_ERR(CAM_ISP, "Can not release CSID(id :%d)", + CAM_ERR(CAM_CUSTOM, "Can not release CSID(id :%d)", hw_mgr_res->res_id); cam_custom_hw_mgr_put_res( &custom_ctx->free_res_list, &hw_mgr_res); @@ -811,41 +811,82 @@ static int cam_custom_mgr_release_hw(void *hw_mgr_priv, return rc; } -static void cam_custom_hw_mgr_acquire_get_unified_dev_str( - struct cam_custom_in_port_info *in, - struct cam_isp_in_port_generic_info *gen_port_info) +static int cam_custom_hw_mgr_acquire_get_unified_dev_str( + struct cam_custom_acquire_hw_info *acquire_hw_info, + uint32_t *input_size, + struct cam_isp_in_port_generic_info **gen_port_info) { - int i; + int32_t rc = 0, i; + uint32_t in_port_length = 0; + struct cam_custom_in_port_info *in = NULL; + struct cam_isp_in_port_generic_info *port_info = NULL; + + in = (struct cam_custom_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset + *input_size); + + in_port_length = sizeof(struct cam_custom_in_port_info) + + (in->num_out_res - 1) * + sizeof(struct cam_custom_out_port_info); + + *input_size += in_port_length; + + if ((*input_size) > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_CUSTOM, "Input is not proper"); + rc = -EINVAL; + return rc; + } + + port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), GFP_KERNEL); + + if (!port_info) + return -ENOMEM; - gen_port_info->res_type = in->res_type + + port_info->res_type = in->res_type + CAM_ISP_IFE_IN_RES_BASE - CAM_CUSTOM_IN_RES_BASE; - gen_port_info->lane_type = in->lane_type; - gen_port_info->lane_num = in->lane_num; - gen_port_info->lane_cfg = in->lane_cfg; - gen_port_info->vc[0] = in->vc[0]; - gen_port_info->dt[0] = in->dt[0]; - gen_port_info->num_valid_vc_dt = in->num_valid_vc_dt; - gen_port_info->format = in->format; - gen_port_info->test_pattern = in->test_pattern; - gen_port_info->usage_type = in->usage_type; - gen_port_info->left_start = in->left_start; - gen_port_info->left_stop = in->left_stop; - gen_port_info->left_width = in->left_width; - gen_port_info->right_start = in->right_start; - gen_port_info->right_stop = in->right_stop; - gen_port_info->right_width = in->right_width; - gen_port_info->line_start = in->line_start; - gen_port_info->line_stop = in->line_stop; - gen_port_info->height = in->height; - gen_port_info->pixel_clk = in->pixel_clk; - gen_port_info->cust_node = 1; - gen_port_info->num_out_res = in->num_out_res; - gen_port_info->num_bytes_out = in->num_bytes_out; + port_info->lane_type = in->lane_type; + port_info->lane_num = in->lane_num; + port_info->lane_cfg = in->lane_cfg; + port_info->vc[0] = in->vc[0]; + port_info->dt[0] = in->dt[0]; + port_info->num_valid_vc_dt = in->num_valid_vc_dt; + port_info->format = in->format; + port_info->test_pattern = in->test_pattern; + port_info->usage_type = in->usage_type; + port_info->left_start = in->left_start; + port_info->left_stop = in->left_stop; + port_info->left_width = in->left_width; + port_info->right_start = in->right_start; + port_info->right_stop = in->right_stop; + port_info->right_width = in->right_width; + port_info->line_start = in->line_start; + port_info->line_stop = in->line_stop; + port_info->height = in->height; + port_info->pixel_clk = in->pixel_clk; + port_info->cust_node = 1; + port_info->num_out_res = in->num_out_res; + port_info->num_bytes_out = in->num_bytes_out; + + port_info->data = kcalloc(in->num_out_res, + sizeof(struct cam_isp_out_port_generic_info), + GFP_KERNEL); + if (port_info->data == NULL) { + rc = -ENOMEM; + goto release_port_mem; + } for (i = 0; i < in->num_out_res; i++) { - gen_port_info->data[i].res_type = in->data[i].res_type; - gen_port_info->data[i].format = in->data[i].format; + port_info->data[i].res_type = in->data[i].res_type; + port_info->data[i].format = in->data[i].format; } + + *gen_port_info = port_info; + return 0; + +release_port_mem: + kfree(port_info); + return rc; } static int cam_custom_mgr_acquire_hw_for_ctx( @@ -896,18 +937,16 @@ static int cam_custom_mgr_acquire_hw( void *hw_mgr_priv, void *acquire_hw_args) { - int rc = -1; - int32_t i; - uint32_t in_port_length; + int rc = -1, i; + uint32_t input_size = 0; struct cam_custom_hw_mgr_ctx *custom_ctx; struct cam_custom_hw_mgr *custom_hw_mgr; - struct cam_hw_acquire_args *acquire_args = - (struct cam_hw_acquire_args *) acquire_hw_args; - struct cam_custom_in_port_info *in_port_info; - struct cam_custom_resource *custom_rsrc; + struct cam_custom_acquire_hw_info *acquire_hw_info = NULL; struct cam_isp_in_port_generic_info *gen_port_info = NULL; + struct cam_hw_acquire_args *acquire_args = + (struct cam_hw_acquire_args *)acquire_hw_args; - if (!hw_mgr_priv || !acquire_args || (acquire_args->num_acq <= 0)) { + if (!hw_mgr_priv || !acquire_args) { CAM_ERR(CAM_CUSTOM, "Invalid params"); return -EINVAL; } @@ -923,127 +962,47 @@ static int cam_custom_mgr_acquire_hw( } mutex_unlock(&g_custom_hw_mgr.ctx_mutex); - /* Handle Acquire Here */ custom_ctx->hw_mgr = custom_hw_mgr; custom_ctx->cb_priv = acquire_args->context_data; custom_ctx->event_cb = acquire_args->event_cb; - custom_rsrc = kcalloc(acquire_args->num_acq, - sizeof(*custom_rsrc), GFP_KERNEL); - if (!custom_rsrc) { - rc = -ENOMEM; - goto free_ctx; - } - - CAM_DBG(CAM_CUSTOM, "start copy %d resources from user", - acquire_args->num_acq); + acquire_hw_info = + (struct cam_custom_acquire_hw_info *)acquire_args->acquire_info; - if (copy_from_user(custom_rsrc, - (void __user *)acquire_args->acquire_info, - ((sizeof(*custom_rsrc)) * acquire_args->num_acq))) { - rc = -EFAULT; - goto free_ctx; - } + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + rc = cam_custom_hw_mgr_acquire_get_unified_dev_str( + acquire_hw_info, &input_size, &gen_port_info); - for (i = 0; i < acquire_args->num_acq; i++) { - if (custom_rsrc[i].resource_id != CAM_CUSTOM_RES_ID_PORT) - continue; - - CAM_DBG(CAM_CUSTOM, "acquire no = %d total = %d", i, - acquire_args->num_acq); - - CAM_DBG(CAM_CUSTOM, - "start copy from user handle %lld with len = %d", - custom_rsrc[i].res_hdl, - custom_rsrc[i].length); - - in_port_length = sizeof(struct cam_custom_in_port_info); - if (in_port_length > custom_rsrc[i].length) { - CAM_ERR(CAM_CUSTOM, "buffer size is not enough"); - rc = -EINVAL; + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, "Failed in parsing: %d", rc); goto free_res; } - in_port_info = memdup_user( - u64_to_user_ptr(custom_rsrc[i].res_hdl), - custom_rsrc[i].length); - - if (!IS_ERR(in_port_info)) { - if (in_port_info->num_out_res > - CAM_CUSTOM_HW_OUT_RES_MAX) { - CAM_ERR(CAM_CUSTOM, "too many output res %d", - in_port_info->num_out_res); - rc = -EINVAL; - kfree(in_port_info); - goto free_res; - } - - in_port_length = - sizeof(struct cam_custom_in_port_info) + - (in_port_info->num_out_res - 1) * - sizeof(struct cam_custom_out_port_info); - - if (in_port_length > custom_rsrc[i].length) { - CAM_ERR(CAM_CUSTOM, - "buffer size is not enough"); - rc = -EINVAL; - kfree(in_port_info); - goto free_res; - } - - gen_port_info = kzalloc( - sizeof(struct cam_isp_in_port_generic_info), - GFP_KERNEL); - if (gen_port_info == NULL) { - rc = -ENOMEM; - goto free_res; - } - - gen_port_info->data = kcalloc( - sizeof(struct cam_isp_out_port_generic_info), - in_port_info->num_out_res, GFP_KERNEL); - if (gen_port_info->data == NULL) { - kfree(gen_port_info); - gen_port_info = NULL; - rc = -ENOMEM; - goto free_res; - } - - cam_custom_hw_mgr_acquire_get_unified_dev_str( - in_port_info, gen_port_info); - - rc = cam_custom_mgr_acquire_hw_for_ctx(custom_ctx, - gen_port_info, &acquire_args->acquired_hw_id[i], - acquire_args->acquired_hw_path[i]); - - kfree(in_port_info); - if (gen_port_info != NULL) { - kfree(gen_port_info->data); - kfree(gen_port_info); - gen_port_info = NULL; - } - - if (rc) { - CAM_ERR(CAM_CUSTOM, "can not acquire resource"); - goto free_res; - } - } else { - CAM_ERR(CAM_CUSTOM, - "Copy from user failed with in_port = %pK", - in_port_info); - rc = -EFAULT; - goto free_res; + CAM_DBG(CAM_CUSTOM, "in_res_type %x", gen_port_info->res_type); + rc = cam_custom_mgr_acquire_hw_for_ctx(custom_ctx, + gen_port_info, &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + if (rc) { + CAM_ERR(CAM_CUSTOM, "can not acquire resource"); + goto free_mem; } + + kfree(gen_port_info->data); + kfree(gen_port_info); + gen_port_info = NULL; } custom_ctx->ctx_in_use = 1; acquire_args->ctxt_to_hw_map = custom_ctx; + cam_custom_hw_mgr_put_ctx(&custom_hw_mgr->used_ctx_list, &custom_ctx); CAM_DBG(CAM_CUSTOM, "Exit...(success)"); return 0; +free_mem: + kfree(gen_port_info->data); + kfree(gen_port_info); free_res: cam_custom_hw_mgr_release_hw_for_ctx(custom_ctx); -free_ctx: cam_custom_hw_mgr_put_ctx(&custom_hw_mgr->free_ctx_list, &custom_ctx); err: CAM_DBG(CAM_CUSTOM, "Exit...(rc=%d)", rc); diff --git a/include/uapi/media/cam_custom.h b/include/uapi/media/cam_custom.h index b36891f4a0dc..37edce171e4b 100644 --- a/include/uapi/media/cam_custom.h +++ b/include/uapi/media/cam_custom.h @@ -170,6 +170,23 @@ struct cam_custom_resource { uint64_t res_hdl; }; +/** + * struct cam_custom_acquire_hw_info - Custom acquire HW params + * + * @num_inputs : Number of inputs + * @input_info_size : Size of input info struct used + * @input_info_offset : Offset of input info from start of data + * @reserved : reserved + * @data : Start of data region + */ +struct cam_custom_acquire_hw_info { + uint32_t num_inputs; + uint32_t input_info_size; + uint32_t input_info_offset; + uint32_t reserved; + uint64_t data; +}; + /** * struct cam_custom_cmd_buf_type_1 - cmd buf type 1 * -- GitLab From dd1ac7b717dd142334ab76777db5603dd6b0e862 Mon Sep 17 00:00:00 2001 From: Karthik Jayakumar Date: Tue, 12 Nov 2019 12:22:39 -0800 Subject: [PATCH 171/410] msm: camera: req_mgr: Fix kmem_cache definition Add fixes to cam_req_mgr to include kmem_cache struct definitions. CRs-Fixed: 2554484 Change-Id: I368aa32e085431eff1976dfc09929e730d63b405 Signed-off-by: Karthik Jayakumar --- drivers/cam_req_mgr/Makefile | 2 +- drivers/cam_req_mgr/cam_req_mgr_dev.c | 6 +++++- drivers/cam_req_mgr/cam_req_mgr_timer.c | 4 +++- drivers/cam_req_mgr/cam_req_mgr_timer.h | 1 - 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/cam_req_mgr/Makefile b/drivers/cam_req_mgr/Makefile index 50599d879255..8ecc89ffd8bb 100644 --- a/drivers/cam_req_mgr/Makefile +++ b/drivers/cam_req_mgr/Makefile @@ -4,7 +4,7 @@ ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils -ccflags-y += -I$(src) +ccflags-y += -I$(srctree)/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_core.o\ cam_req_mgr_dev.o \ diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index cdb2210a2efb..3f9db55ab9a1 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -6,12 +6,17 @@ #include #include #include +#include + +#include + #include #include #include #include #include #include + #include "cam_req_mgr_dev.h" #include "cam_req_mgr_util.h" #include "cam_req_mgr_core.h" @@ -19,7 +24,6 @@ #include "cam_mem_mgr.h" #include "cam_debug_util.h" #include "cam_common_util.h" -#include #define CAM_REQ_MGR_EVENT_MAX 30 diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.c b/drivers/cam_req_mgr/cam_req_mgr_timer.c index ba44534fa48d..eb2a6d599b0f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_timer.c +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include "cam_req_mgr_timer.h" #include "cam_debug_util.h" +extern struct kmem_cache *g_cam_req_mgr_timer_cachep; + void crm_timer_reset(struct cam_req_mgr_timer *crm_timer) { if (!crm_timer) diff --git a/drivers/cam_req_mgr/cam_req_mgr_timer.h b/drivers/cam_req_mgr/cam_req_mgr_timer.h index be200f1b2693..d2e20498df9a 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_timer.h +++ b/drivers/cam_req_mgr/cam_req_mgr_timer.h @@ -62,5 +62,4 @@ int crm_timer_init(struct cam_req_mgr_timer **timer, */ void crm_timer_exit(struct cam_req_mgr_timer **timer); -extern struct kmem_cache *g_cam_req_mgr_timer_cachep; #endif -- GitLab From 50e83233adebcbeafbc5d1463441806cda9952e7 Mon Sep 17 00:00:00 2001 From: Sureshnaidu Laveti Date: Mon, 18 Nov 2019 14:00:11 -0800 Subject: [PATCH 172/410] msm: camera: sensor: Support for read operation Supporting read operation for sensor and sub modules OIS and actuator. CRs-Fixed: 2538801 Change-Id: I83ad154dd577d5a664c4d68792a90489e725fbfd Signed-off-by: Jigarkumar Zala Signed-off-by: Sureshnaidu Laveti --- .../cam_actuator/cam_actuator_core.c | 68 +++- .../cam_flash/cam_flash_core.c | 6 +- .../cam_sensor_module/cam_ois/cam_ois_core.c | 67 +++- .../cam_sensor/cam_sensor_core.c | 42 ++- .../cam_sensor/cam_sensor_dev.c | 4 +- .../cam_sensor_utils/cam_sensor_cmn_header.h | 13 +- .../cam_sensor_utils/cam_sensor_util.c | 308 +++++++++++++++++- .../cam_sensor_utils/cam_sensor_util.h | 7 +- 8 files changed, 495 insertions(+), 20 deletions(-) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index c609b8f85015..d886d8ebaecb 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -554,7 +554,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_i2c_command_parser( &a_ctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed:parse init settings: %d", @@ -612,7 +612,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_i2c_command_parser( &a_ctrl->io_master_info, i2c_reg_settings, - cmd_desc, 1); + cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Auto move lens parsing failed: %d", rc); @@ -643,7 +643,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_i2c_command_parser( &a_ctrl->io_master_info, i2c_reg_settings, - cmd_desc, 1); + cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Manual move lens parsing failed: %d", rc); @@ -662,6 +662,68 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, } cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; + case CAM_ACTUATOR_PACKET_OPCODE_READ: { + struct cam_buf_io_cfg *io_cfg; + struct i2c_settings_array i2c_read_settings; + + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to read actuator: %d", + a_ctrl->cam_act_state); + goto end; + } + CAM_DBG(CAM_ACTUATOR, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs == 0) { + CAM_ERR(CAM_ACTUATOR, "No I/O configs to process"); + rc = -EINVAL; + goto end; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_ACTUATOR, "I/O config is invalid(NULL)"); + rc = -EINVAL; + goto end; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&a_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "actuator read pkt parsing failed: %d", rc); + goto end; + } + + rc = cam_sensor_i2c_read_data( + &i2c_read_settings, + &a_ctrl->io_master_info); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "cannot read data, rc:%d", rc); + delete_request(&i2c_read_settings); + goto end; + } + + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed in deleting the read settings"); + goto end; + } + break; + } default: CAM_ERR(CAM_ACTUATOR, "Wrong Opcode: %d", csl_packet->header.op_code & 0xFFFFFF); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index 293d1422b393..063848104f63 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1070,7 +1070,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_sensor_i2c_command_parser( &fctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_FLASH, "pkt parsing failed: %d", rc); @@ -1150,7 +1150,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_sensor_i2c_command_parser( &fctrl->io_master_info, - i2c_reg_settings, cmd_desc, 1); + i2c_reg_settings, cmd_desc, 1, NULL); if (rc) { CAM_ERR(CAM_FLASH, "Failed in parsing i2c packets"); @@ -1181,7 +1181,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_sensor_i2c_command_parser( &fctrl->io_master_info, - i2c_reg_settings, cmd_desc, 1); + i2c_reg_settings, cmd_desc, 1, NULL); if (rc) { CAM_ERR(CAM_FLASH, "Failed in parsing i2c NRT packets"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index b6035252a234..8ced8a28c309 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -540,7 +540,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_sensor_i2c_command_parser( &o_ctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "init parsing failed: %d", rc); @@ -557,7 +557,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_sensor_i2c_command_parser( &o_ctrl->io_master_info, i2c_reg_settings, - &cmd_desc[i], 1); + &cmd_desc[i], 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "Calib parsing failed: %d", rc); @@ -629,7 +629,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) i2c_reg_settings->request_id = 0; rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, i2c_reg_settings, - cmd_desc, 1); + cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); return rc; @@ -648,6 +648,67 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) return rc; } break; + case CAM_OIS_PACKET_OPCODE_READ: { + struct cam_buf_io_cfg *io_cfg; + struct i2c_settings_array i2c_read_settings; + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to read OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + CAM_DBG(CAM_OIS, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs == 0) { + CAM_ERR(CAM_OIS, "No I/O configs to process"); + rc = -EINVAL; + return rc; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_OIS, "I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS read pkt parsing failed: %d", rc); + return rc; + } + + rc = cam_sensor_i2c_read_data( + &i2c_read_settings, + &o_ctrl->io_master_info); + if (rc < 0) { + CAM_ERR(CAM_OIS, "cannot read data rc: %d", rc); + delete_request(&i2c_read_settings); + return rc; + } + + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in deleting the read settings"); + return rc; + } + break; + } default: CAM_ERR(CAM_OIS, "Invalid Opcode: %d", (csl_packet->header.op_code & 0xFFFFFF)); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 2fa447dbace4..6902122b3f66 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -87,6 +87,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_buf_io_cfg *io_cfg = NULL; struct i2c_settings_array *i2c_reg_settings = NULL; size_t len_of_buff = 0; size_t remain_len = 0; @@ -187,7 +188,28 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, i2c_reg_settings->is_settings_valid = 1; break; } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_READ: { + i2c_reg_settings = &(i2c_data->read_settings); + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + + CAM_DBG(CAM_SENSOR, "number of IO configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs == 0) { + CAM_ERR(CAM_SENSOR, "No I/O configs to process"); + goto end; + } + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_SENSOR, "I/O config is invalid(NULL)"); + goto end; + } + break; + } case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: { if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { @@ -239,7 +261,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_sensor_i2c_command_parser(&s_ctrl->io_master_info, - i2c_reg_settings, cmd_desc, 1); + i2c_reg_settings, cmd_desc, 1, io_cfg); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); goto end; @@ -951,6 +973,24 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } s_ctrl->sensor_state = CAM_SENSOR_CONFIG; } + + if (s_ctrl->i2c_data.read_settings.is_settings_valid) { + rc = cam_sensor_i2c_read_data( + &s_ctrl->i2c_data.read_settings, + &s_ctrl->io_master_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "cannot read data: %d", rc); + delete_request(&s_ctrl->i2c_data.read_settings); + goto release_mutex; + } + rc = delete_request( + &s_ctrl->i2c_data.read_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the read settings"); + goto release_mutex; + } + } } break; default: diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index f847079c730a..765a1244a0aa 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #include "cam_sensor_dev.h" @@ -179,6 +179,7 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.read_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); @@ -314,6 +315,7 @@ static int32_t cam_sensor_driver_platform_probe( INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.read_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index e43e8abe0809..563414e640cc 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -152,13 +152,15 @@ enum cam_sensor_packet_opcodes { CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF, + CAM_SENSOR_PACKET_OPCODE_SENSOR_READ, CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP = 127 }; enum cam_actuator_packet_opcodes { CAM_ACTUATOR_PACKET_OPCODE_INIT, CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS, - CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS + CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS, + CAM_ACTUATOR_PACKET_OPCODE_READ }; enum cam_eeprom_packet_opcodes { @@ -168,7 +170,8 @@ enum cam_eeprom_packet_opcodes { enum cam_ois_packet_opcodes { CAM_OIS_PACKET_OPCODE_INIT, - CAM_OIS_PACKET_OPCODE_OIS_CONTROL + CAM_OIS_PACKET_OPCODE_OIS_CONTROL, + CAM_OIS_PACKET_OPCODE_READ }; enum msm_bus_perf_setting { @@ -218,7 +221,8 @@ enum cam_sensor_i2c_cmd_type { CAM_SENSOR_I2C_WRITE_RANDOM, CAM_SENSOR_I2C_WRITE_BURST, CAM_SENSOR_I2C_WRITE_SEQ, - CAM_SENSOR_I2C_READ, + CAM_SENSOR_I2C_READ_RANDOM, + CAM_SENSOR_I2C_READ_SEQ, CAM_SENSOR_I2C_POLL }; @@ -270,6 +274,8 @@ struct cam_sensor_i2c_reg_setting { enum camera_sensor_i2c_type addr_type; enum camera_sensor_i2c_type data_type; unsigned short delay; + uint8_t *read_buff; + uint32_t read_buff_len; }; struct cam_sensor_i2c_seq_reg { @@ -297,6 +303,7 @@ struct i2c_data_settings { struct i2c_settings_array config_settings; struct i2c_settings_array streamon_settings; struct i2c_settings_array streamoff_settings; + struct i2c_settings_array read_settings; struct i2c_settings_array *per_frame; }; diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 0d82579e7999..078e3e08657a 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -233,6 +233,134 @@ static int32_t cam_sensor_handle_continuous_write( return rc; } +static int32_t cam_sensor_get_io_buffer( + struct cam_buf_io_cfg *io_cfg, + struct cam_sensor_i2c_reg_setting *i2c_settings) +{ + uintptr_t buf_addr = 0x0; + size_t buf_size = 0; + int32_t rc = 0; + + if (io_cfg->direction == CAM_BUF_OUTPUT) { + rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], + &buf_addr, &buf_size); + if ((rc < 0) || (!buf_addr)) { + CAM_ERR(CAM_SENSOR, + "invalid buffer, rc: %d, buf_addr: %pK", + rc, buf_addr); + return -EINVAL; + } + CAM_DBG(CAM_SENSOR, + "buf_addr: %pK, buf_size: %zu, offsetsize: %d", + (void *)buf_addr, buf_size, io_cfg->offsets[0]); + if (io_cfg->offsets[0] >= buf_size) { + CAM_ERR(CAM_SENSOR, + "invalid size:io_cfg->offsets[0]: %d, buf_size: %d", + io_cfg->offsets[0], buf_size); + return -EINVAL; + } + i2c_settings->read_buff = + (uint8_t *)buf_addr + io_cfg->offsets[0]; + i2c_settings->read_buff_len = + buf_size - io_cfg->offsets[0]; + } else { + CAM_ERR(CAM_SENSOR, "Invalid direction: %d", + io_cfg->direction); + rc = -EINVAL; + } + return rc; +} + +static int32_t cam_sensor_handle_random_read( + struct cam_cmd_i2c_random_rd *cmd_i2c_random_rd, + struct i2c_settings_array *i2c_reg_settings, + uint16_t *cmd_length_in_bytes, + int32_t *offset, + struct list_head **list, + struct cam_buf_io_cfg *io_cfg) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt = 0; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, + cmd_i2c_random_rd->header.count); + if ((i2c_list == NULL) || + (i2c_list->i2c_settings.reg_setting == NULL)) { + CAM_ERR(CAM_SENSOR, + "Failed in allocating i2c_list: %pK", + i2c_list); + return -ENOMEM; + } + + rc = cam_sensor_get_io_buffer(io_cfg, &(i2c_list->i2c_settings)); + if (rc) { + CAM_ERR(CAM_SENSOR, "Failed to get read buffer: %d", rc); + } else { + *cmd_length_in_bytes = sizeof(struct i2c_rdwr_header) + + (sizeof(struct cam_cmd_read) * + (cmd_i2c_random_rd->header.count)); + i2c_list->op_code = CAM_SENSOR_I2C_READ_RANDOM; + i2c_list->i2c_settings.addr_type = + cmd_i2c_random_rd->header.addr_type; + i2c_list->i2c_settings.data_type = + cmd_i2c_random_rd->header.data_type; + i2c_list->i2c_settings.size = + cmd_i2c_random_rd->header.count; + + for (cnt = 0; cnt < (cmd_i2c_random_rd->header.count); + cnt++) { + i2c_list->i2c_settings.reg_setting[cnt].reg_addr = + cmd_i2c_random_rd->data_read[cnt].reg_data; + } + *offset = cnt; + *list = &(i2c_list->list); + } + + return rc; +} + +static int32_t cam_sensor_handle_continuous_read( + struct cam_cmd_i2c_continuous_rd *cmd_i2c_continuous_rd, + struct i2c_settings_array *i2c_reg_settings, + uint16_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list, + struct cam_buf_io_cfg *io_cfg) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt = 0; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, 1); + if ((i2c_list == NULL) || + (i2c_list->i2c_settings.reg_setting == NULL)) { + CAM_ERR(CAM_SENSOR, + "Failed in allocating i2c_list: %pK", + i2c_list); + return -ENOMEM; + } + + rc = cam_sensor_get_io_buffer(io_cfg, &(i2c_list->i2c_settings)); + if (rc) { + CAM_ERR(CAM_SENSOR, "Failed to get read buffer: %d", rc); + } else { + *cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); + i2c_list->op_code = CAM_SENSOR_I2C_READ_SEQ; + + i2c_list->i2c_settings.addr_type = + cmd_i2c_continuous_rd->header.addr_type; + i2c_list->i2c_settings.data_type = + cmd_i2c_continuous_rd->header.data_type; + i2c_list->i2c_settings.size = + cmd_i2c_continuous_rd->header.count; + i2c_list->i2c_settings.reg_setting[0].reg_addr = + cmd_i2c_continuous_rd->reg_addr; + + *offset = cnt; + *list = &(i2c_list->list); + } + + return rc; +} + static int cam_sensor_handle_slave_info( struct camera_io_master *io_master, uint32_t *cmd_buf) @@ -271,8 +399,11 @@ static int cam_sensor_handle_slave_info( /** * Name : cam_sensor_i2c_command_parser * Description : Parse CSL CCI packet and apply register settings - * Parameters : s_ctrl input/output sub_device - * arg input cam_control + * Parameters : io_master input master information + * i2c_reg_settings output register settings to fill + * cmd_desc input command description + * num_cmd_buffers input number of command buffers to process + * io_cfg input buffer details for read operation only * Description : * Handle multiple I2C RD/WR and WAIT cmd formats in one command * buffer, for example, a command buffer of m x RND_WR + 1 x HW_ @@ -283,11 +414,12 @@ int cam_sensor_i2c_command_parser( struct camera_io_master *io_master, struct i2c_settings_array *i2c_reg_settings, struct cam_cmd_buf_desc *cmd_desc, - int32_t num_cmd_buffers) + int32_t num_cmd_buffers, + struct cam_buf_io_cfg *io_cfg) { int16_t rc = 0, i = 0; size_t len_of_buff = 0; - uintptr_t generic_ptr; + uintptr_t generic_ptr; uint16_t cmd_length_in_bytes = 0; size_t remain_len = 0; size_t tot_size = 0; @@ -472,7 +604,7 @@ int cam_sensor_i2c_command_parser( } case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: { if (remain_len - byte_cnt < - sizeof(struct cam_cmd_i2c_info)) { + sizeof(struct cam_cmd_i2c_info)) { CAM_ERR(CAM_SENSOR, "Not enough buffer space"); rc = -EINVAL; @@ -493,6 +625,88 @@ int cam_sensor_i2c_command_parser( byte_cnt += cmd_length_in_bytes; break; } + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_RD: { + uint16_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_random_rd *i2c_random_rd = + (struct cam_cmd_i2c_random_rd *)cmd_buf; + + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_random_rd)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + + tot_size = sizeof(struct i2c_rdwr_header) + + (sizeof(struct cam_cmd_read) * + i2c_random_rd->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided %d, %d, %d", + tot_size, remain_len, byte_cnt); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_random_read( + i2c_random_rd, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list, + io_cfg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in random read %d", rc); + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: { + uint16_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_continuous_rd + *i2c_continuous_rd = + (struct cam_cmd_i2c_continuous_rd *)cmd_buf; + + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_continuous_rd)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + + tot_size = + sizeof(struct cam_cmd_i2c_continuous_rd); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided %d, %d, %d", + tot_size, remain_len, byte_cnt); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_continuous_read( + i2c_continuous_rd, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list, + io_cfg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in continuous read %d", rc); + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } default: CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d", cmm_hdr->cmd_type); @@ -576,6 +790,90 @@ int cam_sensor_util_i2c_apply_setting( return rc; } +int32_t cam_sensor_i2c_read_data( + struct i2c_settings_array *i2c_settings, + struct camera_io_master *io_master_info) +{ + int32_t rc = 0; + struct i2c_settings_list *i2c_list; + uint32_t cnt = 0; + uint8_t *read_buff = NULL; + uint32_t buff_length = 0; + uint32_t read_length = 0; + + list_for_each_entry(i2c_list, + &(i2c_settings->list_head), list) { + read_buff = i2c_list->i2c_settings.read_buff; + buff_length = i2c_list->i2c_settings.read_buff_len; + if ((read_buff == NULL) || (buff_length == 0)) { + CAM_ERR(CAM_SENSOR, + "Invalid input buffer, buffer: %pK, length: %d", + read_buff, buff_length); + return -EINVAL; + } + + if (i2c_list->op_code == CAM_SENSOR_I2C_READ_RANDOM) { + read_length = i2c_list->i2c_settings.data_type * + i2c_list->i2c_settings.size; + if ((read_length > buff_length) || + (read_length < i2c_list->i2c_settings.size)) { + CAM_ERR(CAM_SENSOR, + "Invalid size, readLen:%d, bufLen:%d, size: %d", + read_length, buff_length, + i2c_list->i2c_settings.size); + return -EINVAL; + } + for (cnt = 0; cnt < (i2c_list->i2c_settings.size); + cnt++) { + struct cam_sensor_i2c_reg_array *reg_setting = + &(i2c_list->i2c_settings.reg_setting[cnt]); + rc = camera_io_dev_read(io_master_info, + reg_setting->reg_addr, + ®_setting->reg_data, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed: random read I2C settings: %d", + rc); + return rc; + } + if (i2c_list->i2c_settings.data_type < + CAMERA_SENSOR_I2C_TYPE_MAX) { + memcpy(read_buff, + ®_setting->reg_data, + i2c_list->i2c_settings.data_type); + read_buff += + i2c_list->i2c_settings.data_type; + } + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_READ_SEQ) { + read_length = i2c_list->i2c_settings.size; + if (read_length > buff_length) { + CAM_ERR(CAM_SENSOR, + "Invalid buffer size, readLen: %d, bufLen: %d", + read_length, buff_length); + return -EINVAL; + } + rc = camera_io_dev_read_seq( + io_master_info, + i2c_list->i2c_settings.reg_setting[0].reg_addr, + read_buff, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "failed: seq read I2C settings: %d", + rc); + return rc; + } + } + } + + return rc; +} + int32_t msm_camera_fill_vreg_params( struct cam_hw_soc_info *soc_info, struct cam_sensor_power_setting *power_setting, diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h index c923efe61dc5..3600b5636cab 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -30,11 +30,16 @@ int msm_camera_pinctrl_init int cam_sensor_i2c_command_parser(struct camera_io_master *io_master, struct i2c_settings_array *i2c_reg_settings, - struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers); + struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers, + struct cam_buf_io_cfg *io_cfg); int cam_sensor_util_i2c_apply_setting(struct camera_io_master *io_master_info, struct i2c_settings_list *i2c_list); +int32_t cam_sensor_i2c_read_data( + struct i2c_settings_array *i2c_settings, + struct camera_io_master *io_master_info); + int32_t delete_request(struct i2c_settings_array *i2c_array); int cam_sensor_util_request_gpio_table( struct cam_hw_soc_info *soc_info, int gpio_en); -- GitLab From b9dd84cc47bc8be2b90dd0dca8fc223e575e7aee Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 21 Nov 2019 22:45:46 +0530 Subject: [PATCH 173/410] msm: camera: isp: prioritize RUP over EPOCH in bottom half When epoch comes along with RUP we report bubble as per current state machine. This was because in camif_bottom_half handler we are handling EPOCH before RUP. This change prioritize RUP over EPOCH and EOF over SOF to handle race. CRs-Fixed: 2567120 Change-Id: I236bcc44b609f8ef7f963f19d33d46a3d95ba0d2 Signed-off-by: Vikram Sharma --- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 0ed1c6ede3ce..c776888c9871 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -709,6 +709,16 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, CAM_DBG(CAM_ISP, "irq_status_0 = 0x%x irq_status_1 = 0x%x", irq_status0, irq_status1); + if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + if (irq_status0 & camif_priv->reg_data->sof_irq_mask) { if ((camif_priv->enable_sof_irq_debug) && (camif_priv->irq_debug_cnt <= @@ -732,16 +742,6 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_SUCCESS; } - if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { - CAM_DBG(CAM_ISP, "Received EPOCH"); - - if (camif_priv->event_cb) - camif_priv->event_cb(camif_priv->priv, - CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); - - ret = CAM_VFE_IRQ_STATUS_SUCCESS; - } - if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) { CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); @@ -752,12 +752,12 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_SUCCESS; } - if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { - CAM_DBG(CAM_ISP, "Received EOF"); + if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, - CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); ret = CAM_VFE_IRQ_STATUS_SUCCESS; } -- GitLab From a838b9ec2105f3cef4f307ce0d71a11e04290ed9 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Fri, 22 Nov 2019 10:35:25 +0530 Subject: [PATCH 174/410] msm: camera: req_mgr: Link state check before process trigger workq Due to scheduling delays, process trigger workq can be delayed. In the meantime, link state can be reset to IDLE. This can cause abnormal behaviour resulting in stability issues. Also, at the time of apply fail for flash, failed_dev is not updated. This causes crash while notifying the error on link. This commit prevents the execution of workq process trigger if the link has been reset to IDLE state. Also, failed_dev is updated if the apply for flash fails. CRs-Fixed: 2572511 Change-Id: Iaea1e0a7a24afc9e408a1530a5875f6b6c41a45b Signed-off-by: Gaurav Jindal --- drivers/cam_req_mgr/cam_req_mgr_core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 0a4af3c097d0..d229f04510d2 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -681,8 +681,10 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, apply_req.trigger_point = trigger; if (dev->ops && dev->ops->apply_req) { rc = dev->ops->apply_req(&apply_req); - if (rc) + if (rc) { + *failed_dev = dev; return rc; + } CAM_DBG(CAM_REQ, "SEND: link_hdl: %x pd: %d req_id %lld", link->link_hdl, pd, apply_req.request_id); @@ -2456,6 +2458,14 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) link->link_hdl, in_q->rd_idx, in_q->slot[in_q->rd_idx].status); spin_lock_bh(&link->link_state_spin_lock); + + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto release_lock; + } + if (link->state == CAM_CRM_LINK_STATE_ERR) CAM_WARN(CAM_CRM, "Error recovery idx %d status %d", in_q->rd_idx, -- GitLab From 3de84e066b71833edf44cd3694672a738b025402 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 2 Dec 2019 16:36:43 +0530 Subject: [PATCH 175/410] msm: camera: csiphy: Update common sequence for csiphy v1.2 Add a high-to-low transition in the CTRL0 register during the common power-up sequence. CRs-Fixed: 2580437 Change-Id: I66541d3d787fa2f161e5d8e647fb11c8075a1947 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 3bed231e0246..179ccebddc54 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,7 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 6, + .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 18, .csiphy_3ph_config_array_size = 33, @@ -24,6 +24,7 @@ struct csiphy_reg_t csiphy_common_reg_1_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, -- GitLab From 7c74d4e031ffc687b87d07fddb0776d395ac744b Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 25 Oct 2019 15:36:03 +0530 Subject: [PATCH 176/410] msm: camera: reqmgr: reset the slot on buf_done Reset the slot with the valid request on receiving the buf_done which is reported on next EPOCH. In case of back to back irqs slot is marked as skip idx it will apply the request and try to reset a slot based on MAX_PD + 1 calculation which might have the request for which we have got a bubble. To make sure this does not happen, reset a slot only on the buf_done for valid request. If STOP ioctl is called from UMD for ISP, it will flush all the lists. But this is not notified to CRM which might have a stale entry of the half applied request, so on STOP ioctl clear all the slots. In case of SAT mode if one of the link has generated bubble, while the sync_link has the sync_request slot reset sync_link will not let the link recover of the bubble. To make sure the recovery sync_mode is set to 0 for two consecutive slots of the link. CRs-Fixed: 2551701 Change-Id: If4b6f8a4a831ffddcef2cae6292d066778c18b04 Signed-off-by: Tejas Prajapati --- drivers/cam_isp/cam_isp_context.c | 36 +++++- drivers/cam_isp/cam_isp_context.h | 14 +++ drivers/cam_req_mgr/cam_req_mgr_core.c | 115 +++++++++++++++++++- drivers/cam_req_mgr/cam_req_mgr_core.h | 2 + drivers/cam_req_mgr/cam_req_mgr_interface.h | 17 +++ 5 files changed, 179 insertions(+), 5 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 1a66070585e5..6433389c4ba4 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -658,6 +658,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request( CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); + ctx_isp->req_info.last_bufdone_req_id = req->request_id; } __cam_isp_ctx_update_state_monitor_array(ctx_isp, @@ -857,6 +858,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -1027,7 +1029,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, * If no wait req in epoch, this is an error case. * The recovery is to go back to sof state */ - CAM_ERR(CAM_ISP, "No wait request"); + CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; /* Send SOF event as empty frame*/ @@ -1043,7 +1045,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, req_isp->bubble_detected = true; req_isp->reapply = true; - CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); + CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; @@ -1192,7 +1195,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( * If no pending req in epoch, this is an error case. * Just go back to the bubble state. */ - CAM_ERR(CAM_ISP, "No pending request."); + CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); @@ -1204,6 +1207,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); req_isp->reapply = true; if (req_isp->bubble_report && ctx->ctx_crm_intf && @@ -1542,6 +1547,7 @@ static int __cam_isp_ctx_fs2_sof_in_sof_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -1719,6 +1725,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2406,6 +2413,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2502,9 +2510,10 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); req_isp->reapply = true; - CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; @@ -2603,6 +2612,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2675,6 +2685,7 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( notify.dev_hdl = ctx->dev_hdl; notify.frame_id = ctx_isp->frame_id; notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; ctx->ctx_crm_intf->notify_trigger(¬ify); @@ -2872,6 +2883,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; + ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -2932,6 +2944,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx_isp->hw_acquired = false; ctx_isp->init_received = false; ctx_isp->rdi_only_context = false; + ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -3862,6 +3875,18 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); + if (ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_stop) { + struct cam_req_mgr_notify_stop notify; + + notify.link_hdl = ctx->link_hdl; + CAM_DBG(CAM_ISP, + "Notify CRM about device stop ctx %u link 0x%x", + ctx->ctx_id, ctx->link_hdl); + ctx->ctx_crm_intf->notify_stop(¬ify); + } else + CAM_ERR(CAM_ISP, "cb not present"); + while (!list_empty(&ctx->pending_req_list)) { req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); @@ -3909,11 +3934,13 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( } list_add_tail(&req->list, &ctx->free_req_list); } + ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; ctx_isp->bubble_frame_cnt = 0; ctx_isp->last_applied_req_id = 0; + ctx_isp->req_info.last_bufdone_req_id = 0; atomic_set(&ctx_isp->process_bubble, 0); atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -4372,6 +4399,7 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->frame_id = 0; ctx->active_req_cnt = 0; ctx->reported_req_id = 0; + ctx->req_info.last_bufdone_req_id = 0; ctx->bubble_frame_cnt = 0; ctx->hw_ctx = NULL; ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 34f899f65b27..503e46526dee 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -149,6 +149,18 @@ struct cam_isp_context_state_monitor { }; /** + * struct cam_isp_context_req_id_info - ISP context request id + * information for bufdone. + * + *@last_bufdone_req_id: Last bufdone request id + * + */ + +struct cam_isp_context_req_id_info { + int64_t last_bufdone_req_id; +}; +/** + * * struct cam_isp_context - ISP context object * * @base: Common context object pointer @@ -170,6 +182,7 @@ struct cam_isp_context_state_monitor { * will invoke CRM cb at those event. * @last_applied_req_id: Last applied request id * @state_monitor_head: Write index to the state monitoring array + * @req_info Request id information about last buf done * @cam_isp_ctx_state_monitor: State monitoring array * @rdi_only_context: Get context type information. * true, if context is rdi only context @@ -202,6 +215,7 @@ struct cam_isp_context { atomic64_t state_monitor_head; struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; + struct cam_isp_context_req_id_info req_info; bool rdi_only_context; bool hw_acquired; bool init_received; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index d229f04510d2..e7b5994963fe 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -480,7 +480,9 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status); /* Check if CSL has already pushed new request*/ - if (slot->status == CRM_SLOT_STATUS_REQ_ADDED) + if (slot->status == CRM_SLOT_STATUS_REQ_ADDED || + in_q->last_applied_idx == idx || + idx < 0) return; /* Reset input queue slot */ @@ -1500,6 +1502,10 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, reset_step = link->sync_link->max_delay; } + + if (slot->req_id > 0) + in_q->last_applied_idx = idx; + __cam_req_mgr_dec_idx( &idx, reset_step + 1, in_q->num_slots); @@ -2403,6 +2409,12 @@ int cam_req_mgr_process_error(void *priv, void *data) __cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl); in_q->rd_idx = idx; in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED; + if (link->sync_link) { + in_q->slot[idx].sync_mode = 0; + __cam_req_mgr_inc_idx(&idx, 1, + link->req.l_tbl->num_slots); + in_q->slot[idx].sync_mode = 0; + } spin_lock_bh(&link->link_state_spin_lock); link->state = CAM_CRM_LINK_STATE_ERR; spin_unlock_bh(&link->link_state_spin_lock); @@ -2415,6 +2427,31 @@ int cam_req_mgr_process_error(void *priv, void *data) return rc; } +/** + * cam_req_mgr_process_stop() + * + * @brief: This runs in workque thread context. stop notification. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_stop(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + __cam_req_mgr_flush_req_slot(link); +end: + return rc; +} + /** * cam_req_mgr_process_trigger() * @@ -2428,6 +2465,7 @@ int cam_req_mgr_process_error(void *priv, void *data) static int cam_req_mgr_process_trigger(void *priv, void *data) { int rc = 0; + int32_t idx = -1; struct cam_req_mgr_trigger_notify *trigger_data = NULL; struct cam_req_mgr_core_link *link = NULL; struct cam_req_mgr_req_queue *in_q = NULL; @@ -2450,6 +2488,17 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) in_q = link->req.in_q; mutex_lock(&link->req.lock); + + if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) { + idx = __cam_req_mgr_find_slot_for_req(in_q, + trigger_data->req_id); + if (idx >= 0) { + if (idx == in_q->last_applied_idx) + in_q->last_applied_idx = -1; + __cam_req_mgr_reset_req_slot(link, idx); + } + } + /* * Check if current read index is in applied state, if yes make it free * and increment read index to next slot. @@ -2714,6 +2763,68 @@ static int cam_req_mgr_cb_notify_timer( return rc; } +/* + * cam_req_mgr_cb_notify_stop() + * + * @brief : Stop received from device, resets the morked slots + * @err_info : contains information about error occurred like bubble/overflow + * + * @return : 0 on success, negative in case of failure + * + */ +static int cam_req_mgr_cb_notify_stop( + struct cam_req_mgr_notify_stop *stop_info) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_notify_stop *notify_stop; + struct crm_task_payload *task_data; + + if (!stop_info) { + CAM_ERR(CAM_CRM, "stop_info is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(stop_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", stop_info->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state != CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + crm_timer_reset(link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "no empty task"); + rc = -EBUSY; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_ERR; + notify_stop = (struct cam_req_mgr_notify_stop *)&task_data->u; + notify_stop->link_hdl = stop_info->link_hdl; + task->process_cb = &cam_req_mgr_process_stop; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + +end: + return rc; +} + + + /** * cam_req_mgr_cb_notify_trigger() * @@ -2774,6 +2885,7 @@ static int cam_req_mgr_cb_notify_trigger( notify_trigger->link_hdl = trigger_data->link_hdl; notify_trigger->dev_hdl = trigger_data->dev_hdl; notify_trigger->trigger = trigger_data->trigger; + notify_trigger->req_id = trigger_data->req_id; notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val; task->process_cb = &cam_req_mgr_process_trigger; rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); @@ -2787,6 +2899,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { .notify_err = cam_req_mgr_cb_notify_err, .add_req = cam_req_mgr_cb_add_req, .notify_timer = cam_req_mgr_cb_notify_timer, + .notify_stop = cam_req_mgr_cb_notify_stop, }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 0afdc69b0445..14cf4ff06a36 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -253,12 +253,14 @@ struct cam_req_mgr_slot { * @slot : request slot holding incoming request id and bubble info. * @rd_idx : indicates slot index currently in process. * @wr_idx : indicates slot index to hold new upcoming req. + * @last_applied_idx : indicates slot index last applied successfully. */ struct cam_req_mgr_req_queue { int32_t num_slots; struct cam_req_mgr_slot slot[MAX_REQ_SLOTS]; int32_t rd_idx; int32_t wr_idx; + int32_t last_applied_idx; }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index 5df13b26e215..68ab7917e947 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -15,6 +15,7 @@ struct cam_req_mgr_trigger_notify; struct cam_req_mgr_error_notify; struct cam_req_mgr_add_request; struct cam_req_mgr_timer_notify; +struct cam_req_mgr_notify_stop; struct cam_req_mgr_device_info; struct cam_req_mgr_core_dev_link_setup; struct cam_req_mgr_apply_request; @@ -37,6 +38,7 @@ typedef int (*cam_req_mgr_notify_trigger)( typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *); typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *); +typedef int (*cam_req_mgr_notify_stop)(struct cam_req_mgr_notify_stop *); /** * @brief: cam req mgr to camera device drivers @@ -61,12 +63,14 @@ typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *); * @notify_trigger : payload for trigger indication event * @notify_err : payload for different error occurred at device * @add_req : payload to inform which device and what request is received + * @notify_stop : payload to inform stop event */ struct cam_req_mgr_crm_cb { cam_req_mgr_notify_trigger notify_trigger; cam_req_mgr_notify_err notify_err; cam_req_mgr_add_req add_req; cam_req_mgr_notify_timer notify_timer; + cam_req_mgr_notify_stop notify_stop; }; /** @@ -142,6 +146,7 @@ enum cam_req_mgr_device_error { CRM_KMD_ERR_PAGE_FAULT, CRM_KMD_ERR_OVERFLOW, CRM_KMD_ERR_TIMEOUT, + CRM_KMD_ERR_STOPPED, CRM_KMD_ERR_MAX, }; @@ -200,6 +205,7 @@ enum cam_req_mgr_link_evt_type { * @trigger : trigger point of this notification, CRM will send apply * only to the devices which subscribe to this point. * @sof_timestamp_val: Captured time stamp value at sof hw event + * @req_id : req id which returned buf_done */ struct cam_req_mgr_trigger_notify { int32_t link_hdl; @@ -207,6 +213,7 @@ struct cam_req_mgr_trigger_notify { int64_t frame_id; uint32_t trigger; uint64_t sof_timestamp_val; + uint64_t req_id; }; /** @@ -253,6 +260,16 @@ struct cam_req_mgr_add_request { }; +/** + * struct cam_req_mgr_notify_stop + * @link_hdl : link identifier + * + */ +struct cam_req_mgr_notify_stop { + int32_t link_hdl; +}; + + /* CRM to KMD devices */ /** * struct cam_req_mgr_device_info -- GitLab From 287da8d3c81c2851d3612e43ae01ee356a987670 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Wed, 4 Dec 2019 14:33:28 +0530 Subject: [PATCH 177/410] msm: camera: isp: Change master slave combination for dual IFE For some targets, there is a requirement to have the lower IFE as master. Current implementation selects the higher IFE as the master. This commit changes the acquire logic to reserve the lower IFE first and then the higher IFE as slave. This logic is for dual ife use cases. For single IFE use case, acquire logic is not changed. Also, removes the hard coded check for master hw index during the irq handling. Stores the master hw index in ife hardware manager context and check against it. Change-Id: Ifd3a28e80a0a4d16e3d9278b7ed61290c620ec79 CRs-Fixed: 2571273 Signed-off-by: Gaurav Jindal --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 154 +++++++++++--------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 4 + 2 files changed, 93 insertions(+), 65 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 94f1c75f6d20..80857bba45af 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1036,7 +1036,7 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( /*TBD */ vfe_acquire.vfe_out.is_master = 1; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->slave_hw_idx; } else { vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = @@ -1047,7 +1047,7 @@ static int cam_ife_hw_mgr_acquire_res_bus_rd( CAM_ISP_HW_SPLIT_RIGHT; vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->master_hw_idx; } rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire, @@ -1229,7 +1229,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( /*TBD */ vfe_acquire.vfe_out.is_master = 1; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->slave_hw_idx; } else { vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = @@ -1240,9 +1240,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( CAM_ISP_HW_SPLIT_RIGHT; vfe_acquire.vfe_out.is_master = 0; vfe_acquire.vfe_out.dual_slave_core = - (hw_intf->hw_idx == 0) ? 1 : 0; + ife_ctx->master_hw_idx; } - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire, sizeof(struct cam_vfe_acquire_args)); @@ -1659,6 +1658,54 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( return rc; } +static int cam_ife_hw_mgr_acquire_csid_hw( + struct cam_ife_hw_mgr *ife_hw_mgr, + struct cam_csid_hw_reserve_resource_args *csid_acquire, + bool is_start_lower_idx) +{ + int i; + int rc = -1; + struct cam_hw_intf *hw_intf; + + if (!ife_hw_mgr || !csid_acquire) { + CAM_ERR(CAM_ISP, + "Invalid args ife hw mgr %pK csid_acquire %pK", + ife_hw_mgr, csid_acquire); + return -EINVAL; + } + + if (is_start_lower_idx) { + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + csid_acquire, + sizeof(struct + cam_csid_hw_reserve_resource_args)); + if (!rc) + return rc; + } + return rc; + } + + for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + csid_acquire, + sizeof(struct + cam_csid_hw_reserve_resource_args)); + if (!rc) + return rc; + } + + return rc; +} + static int cam_ife_mgr_acquire_cid_res( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_generic_info *in_port, @@ -1751,52 +1798,21 @@ static int cam_ife_mgr_acquire_cid_res( } /* Acquire Left if not already acquired */ - if (ife_ctx->is_fe_enable) { - for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { - if (!ife_hw_mgr->csid_devices[i]) - continue; - - hw_intf = ife_hw_mgr->csid_devices[i]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) - continue; - else { - cid_res_temp->hw_res[acquired_cnt++] = - csid_acquire.node_res; - break; - } - } - if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { - CAM_ERR(CAM_ISP, - "Can not acquire ife cid resource for path %d", - path_res_id); - goto put_res; - } - } else { - for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { - if (!ife_hw_mgr->csid_devices[i]) - continue; + /* For dual IFE cases, start acquiring the lower idx first */ + if (ife_ctx->is_fe_enable || in_port->usage_type) + rc = cam_ife_hw_mgr_acquire_csid_hw(ife_hw_mgr, + &csid_acquire, true); + else + rc = cam_ife_hw_mgr_acquire_csid_hw(ife_hw_mgr, + &csid_acquire, false); - hw_intf = ife_hw_mgr->csid_devices[i]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) - continue; - else { - cid_res_temp->hw_res[acquired_cnt++] = - csid_acquire.node_res; - break; - } - } - if (i == -1 || !csid_acquire.node_res) { - CAM_ERR(CAM_ISP, - "Can not acquire ife cid resource for path %d", - path_res_id); - goto put_res; - } + if (rc || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; } - + cid_res_temp->hw_res[acquired_cnt++] = csid_acquire.node_res; acquire_successful: CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", @@ -1807,7 +1823,9 @@ static int cam_ife_mgr_acquire_cid_res( cid_res_temp->res_id = csid_acquire.node_res->res_id; cid_res_temp->is_dual_vfe = in_port->usage_type; ife_ctx->is_dual = (bool)in_port->usage_type; - + if (ife_ctx->is_dual) + ife_ctx->master_hw_idx = + cid_res_temp->hw_res[0]->hw_intf->hw_idx; if (in_port->num_out_res) cid_res_temp->is_secure = out_port->secure_mode; @@ -1844,6 +1862,8 @@ static int cam_ife_mgr_acquire_cid_res( goto end; } cid_res_temp->hw_res[1] = csid_acquire.node_res; + ife_ctx->slave_hw_idx = + cid_res_temp->hw_res[1]->hw_intf->hw_idx; CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d", in_port->usage_type); } @@ -6249,9 +6269,10 @@ static int cam_ife_hw_mgr_handle_hw_rup( switch (event_info->res_id) { case CAM_ISP_HW_VFE_IN_CAMIF: - if (ife_hw_mgr_ctx->is_dual) - if (event_info->hw_idx != 1) - break; + if ((ife_hw_mgr_ctx->is_dual) && + (event_info->hw_idx != + ife_hw_mgr_ctx->master_hw_idx)) + break; if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) break; @@ -6292,8 +6313,8 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( { int32_t rc = -1; uint32_t *event_cnt = NULL; - uint32_t core_idx0 = 0; - uint32_t core_idx1 = 1; + uint32_t master_hw_idx; + uint32_t slave_hw_idx; if (!ife_hw_mgr_ctx->is_dual) return 0; @@ -6312,24 +6333,27 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( return 0; } - if (event_cnt[core_idx0] == event_cnt[core_idx1]) { + master_hw_idx = ife_hw_mgr_ctx->master_hw_idx; + slave_hw_idx = ife_hw_mgr_ctx->slave_hw_idx; + + if (event_cnt[master_hw_idx] == event_cnt[slave_hw_idx]) { - event_cnt[core_idx0] = 0; - event_cnt[core_idx1] = 0; + event_cnt[master_hw_idx] = 0; + event_cnt[slave_hw_idx] = 0; rc = 0; return rc; } - if ((event_cnt[core_idx0] && - (event_cnt[core_idx0] - event_cnt[core_idx1] > 1)) || - (event_cnt[core_idx1] && - (event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) { + if ((event_cnt[master_hw_idx] && + (event_cnt[master_hw_idx] - event_cnt[slave_hw_idx] > 1)) || + (event_cnt[slave_hw_idx] && + (event_cnt[slave_hw_idx] - event_cnt[master_hw_idx] > 1))) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "One of the VFE could not generate hw event %d core_0_cnt %d core_1_cnt %d", - hw_event_type, event_cnt[core_idx0], - event_cnt[core_idx1]); + "One of the VFE could not generate hw event %d master[%d] core_cnt %d slave[%d] core_cnt %d", + hw_event_type, master_hw_idx, event_cnt[master_hw_idx], + slave_hw_idx, event_cnt[slave_hw_idx]); rc = -1; return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 7e6b91bab916..17a9e11834df 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -101,6 +101,8 @@ struct cam_ife_hw_mgr_debug { * @list: used by the ctx list. * @common: common acquired context data * @ctx_index: acquired context id. + * @master_hw_idx: hw index for master core + * @slave_hw_idx: hw index for slave core * @hw_mgr: IFE hw mgr which owns this context * @ctx_in_use: flag to tell whether context is active * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be @@ -144,6 +146,8 @@ struct cam_ife_hw_mgr_ctx { struct cam_isp_hw_mgr_ctx common; uint32_t ctx_index; + uint32_t master_hw_idx; + uint32_t slave_hw_idx; struct cam_ife_hw_mgr *hw_mgr; uint32_t ctx_in_use; -- GitLab From d59ca83371bc38106221ea4ea683215ca30931ac Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Tue, 3 Dec 2019 21:39:28 +0530 Subject: [PATCH 178/410] msm: camera: sensor: Add null check for read buffer Add proper null checks for function arguments, including read buffer, before dereferencing them. CRs-Fixed: 2581538 Change-Id: I8c49bbc419e2ac5579341c7dc789da0ed1c4d123 Signed-off-by: Shravan Nevatia --- .../cam_sensor_module/cam_sensor_utils/cam_sensor_util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 078e3e08657a..cf10ee5d7edf 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -241,6 +241,12 @@ static int32_t cam_sensor_get_io_buffer( size_t buf_size = 0; int32_t rc = 0; + if (io_cfg == NULL || i2c_settings == NULL) { + CAM_ERR(CAM_SENSOR, + "Invalid args, io buf or i2c settings is NULL"); + return -EINVAL; + } + if (io_cfg->direction == CAM_BUF_OUTPUT) { rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], &buf_addr, &buf_size); -- GitLab From 928edd9316a4acaf083a96de2761f3ffde1617ed Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Tue, 3 Dec 2019 18:10:44 +0530 Subject: [PATCH 179/410] msm: camera: jpeg: Add mutex lock to protect jpeg list corruption Due to race conditions, situation can arise where the process_irq and flush for jpeg are being handled in parallel. This will cause the jpeg list corruption. This commit protects the code of adding back to free list in process_irq with the mutex. CRs-Fixed: 2578247 Change-Id: I28ee48bc0d5cfcf3ae4a936b2eb2976226ad88d5 Signed-off-by: Gaurav Jindal --- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 09b4b8d3e0f6..c1b867af4914 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -177,7 +177,9 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) PTR_TO_U64(p_cfg_req->hw_cfg_args.priv); ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data); + mutex_lock(&g_jpeg_hw_mgr.hw_mgr_mutex); list_add_tail(&p_cfg_req->list, &hw_mgr->free_req_list); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); return rc; } -- GitLab From 1411dd923f48e6beed02097609e9728624a050d4 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Fri, 13 Dec 2019 09:49:16 +0530 Subject: [PATCH 180/410] msm: camera: cpas: Reorder sequence of cleanup in cpas probe failure if cpas probe fails during initialization of soc resources soc data is being accessed after freeing the memory. This change handling the sequence on failure. CRs-Fixed: 2585085 Change-Id: Ia89b02bce9cfb6512b33f8e7366a552635317ccd Signed-off-by: Alok Pandey --- drivers/cam_cpas/cam_cpas_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index ae0368acdb05..5ae03680ad2f 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1860,10 +1860,10 @@ int cam_cpas_hw_probe(struct platform_device *pdev, cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client); client_cleanup: cam_cpas_util_client_cleanup(cpas_hw); + cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); deinit_platform_res: cam_cpas_soc_deinit_resources(&cpas_hw->soc_info); release_workq: - cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); flush_workqueue(cpas_core->work_queue); destroy_workqueue(cpas_core->work_queue); release_mem: -- GitLab From c7011c037e80004490cbb742f784223e2ceb4617 Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Wed, 20 Nov 2019 22:23:37 -0800 Subject: [PATCH 181/410] msm: camera: jpeg: Increase number of jpeg contexts Fixed out of memory issue in triple camera usecase by increasing number of logical jpeg contexts. CRs-Fixed: 2587592 Change-Id: I25c99c0be8d3986bc11fbc2894a0dbf27c645d4e Signed-off-by: Suraj Dongre Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_jpeg/cam_jpeg_dev.c | 6 +++--- drivers/cam_jpeg/cam_jpeg_dev.h | 6 +++--- drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h | 3 +-- drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h | 4 +++- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c index 0a68ce997283..85da82cea7ba 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/cam_jpeg/cam_jpeg_dev.c @@ -97,7 +97,7 @@ static int cam_jpeg_dev_remove(struct platform_device *pdev) int rc; int i; - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) { rc = cam_jpeg_context_deinit(&g_jpeg_dev.ctx_jpeg[i]); if (rc) CAM_ERR(CAM_JPEG, "JPEG context %d deinit failed %d", @@ -135,7 +135,7 @@ static int cam_jpeg_dev_probe(struct platform_device *pdev) goto unregister; } - for (i = 0; i < CAM_CTX_MAX; i++) { + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) { rc = cam_jpeg_context_init(&g_jpeg_dev.ctx_jpeg[i], &g_jpeg_dev.ctx[i], &node->hw_mgr_intf, @@ -147,7 +147,7 @@ static int cam_jpeg_dev_probe(struct platform_device *pdev) } } - rc = cam_node_init(node, &hw_mgr_intf, g_jpeg_dev.ctx, CAM_CTX_MAX, + rc = cam_node_init(node, &hw_mgr_intf, g_jpeg_dev.ctx, CAM_JPEG_CTX_MAX, CAM_JPEG_DEV_NAME); if (rc) { CAM_ERR(CAM_JPEG, "JPEG node init failed %d", rc); diff --git a/drivers/cam_jpeg/cam_jpeg_dev.h b/drivers/cam_jpeg/cam_jpeg_dev.h index 4961527de1a7..d07a1f94b425 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.h +++ b/drivers/cam_jpeg/cam_jpeg_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_JPEG_DEV_H_ @@ -24,8 +24,8 @@ struct cam_jpeg_dev { struct cam_subdev sd; struct cam_node *node; - struct cam_context ctx[CAM_CTX_MAX]; - struct cam_jpeg_context ctx_jpeg[CAM_CTX_MAX]; + struct cam_context ctx[CAM_JPEG_CTX_MAX]; + struct cam_jpeg_context ctx_jpeg[CAM_JPEG_CTX_MAX]; struct mutex jpeg_mutex; int32_t open_cnt; }; diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h index 1b93547fdf25..3deb9dd73b32 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_HW_INTF_H @@ -8,7 +8,6 @@ #include "cam_cpas_api.h" -#define CAM_JPEG_CTX_MAX 8 #define CAM_JPEG_DEV_PER_TYPE_MAX 1 #define CAM_JPEG_CMD_BUF_MAX_SIZE 128 diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h index 30c51f7cfcfd..b83a308f7d78 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_HW_MGR_INTF_H @@ -10,6 +10,8 @@ #include #include +#define CAM_JPEG_CTX_MAX 16 + int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, int *iommu_hdl); -- GitLab From 322ade59518d741146af7b8b1266923f283225fb Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 19 Nov 2019 18:26:47 -0800 Subject: [PATCH 182/410] msm: camera: icp: Increase the wait time for abort ACK This change attempts to retry waiting atleast 1 time for a duration of 1 second for the abort ACK from FW. Also adds some debug messages during flush and removes mutex usage during page fault dump. CRs-Fixed: 2588575 Change-Id: I2f273baa3d56ab2dc0368d882470360a3702c53c Signed-off-by: Karthik Anantha Ram --- drivers/cam_icp/cam_icp_context.c | 3 - .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 62 +++++++++++++++++-- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 7d2ef39e0aeb..180ea7152a76 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -37,8 +37,6 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, return -EINVAL; } - mutex_lock(&ctx->ctx_mutex); - if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", ctx->ctx_id, ctx->state); @@ -64,7 +62,6 @@ static int cam_icp_context_dump_active_request(void *data, unsigned long iova, } end: - mutex_unlock(&ctx->ctx_mutex); return rc; } 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 8bc550bc188d..1c2e72c9a58b 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 @@ -3031,6 +3031,36 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hw_mgr->a5_jtag_debug); } +static int cam_icp_retry_wait_for_abort( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int retry_cnt = 1; + unsigned long rem_jiffies; + int timeout = 1000; + + CAM_WARN(CAM_ICP, "FW timeout in abort ctx: %u retry_left: %d", + ctx_data->ctx_id, retry_cnt); + while (retry_cnt > 0) { + rem_jiffies = wait_for_completion_timeout( + &ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + retry_cnt--; + if (retry_cnt > 0) { + CAM_WARN(CAM_ICP, + "FW timeout in abort ctx: %u retry_left: %u", + ctx_data->ctx_id, retry_cnt); + continue; + } + } + + if (retry_cnt > 0) + return 0; + } + + return -ETIMEDOUT; +} + static int cam_icp_mgr_abort_handle( struct cam_icp_hw_ctx_data *ctx_data) { @@ -3074,10 +3104,14 @@ static int cam_icp_mgr_abort_handle( rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, msecs_to_jiffies((timeout))); if (!rem_jiffies) { - rc = -ETIMEDOUT; - CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); - cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); - cam_hfi_queue_dump(); + rc = cam_icp_retry_wait_for_abort(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, + "FW timeout/err in abort handle command ctx: %u", + ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } } kfree(abort_cmd); @@ -4805,6 +4839,24 @@ static int cam_icp_mgr_flush_req(struct cam_icp_hw_ctx_data *ctx_data, return 0; } +static void cam_icp_mgr_flush_info_dump( + struct cam_hw_flush_args *flush_args, uint32_t ctx_id) +{ + int i; + + for (i = 0; i < flush_args->num_req_active; i++) { + CAM_DBG(CAM_ICP, "Flushing active request %lld in ctx %u", + *(int64_t *)flush_args->flush_req_active[i], + ctx_id); + } + + for (i = 0; i < flush_args->num_req_pending; i++) { + CAM_DBG(CAM_ICP, "Flushing pending request %lld in ctx %u", + *(int64_t *)flush_args->flush_req_pending[i], + ctx_id); + } +} + static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -4838,6 +4890,8 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) if (!atomic_read(&hw_mgr->recovery) && flush_args->num_req_active) { mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_flush_info_dump(flush_args, + ctx_data->ctx_id); cam_icp_mgr_abort_handle(ctx_data); } else { mutex_unlock(&hw_mgr->hw_mgr_mutex); -- GitLab From 1cd4d0ec4f0b1ced197bc01a607285ddd256d487 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Sat, 9 Nov 2019 00:59:33 +0530 Subject: [PATCH 183/410] msm: camera: cpas: Add cpas support for camera v170_200 platform Add register information. Initial QoS settings info to program camera static settings for chipsets having camera v170_200. Also change the logic to get the camera and cpas versions. Added the map table corresponding to camera and cpas versions. For any new CPAS version support, just need to add the entries to the map. This removes the complexity of if-else cases while fetching the cpas hw information. CRs-Fixed: 2571273 Change-Id: I7d54b8bc038aa90ecb39f5048e7809ac10c4476f Signed-off-by: Gaurav Jindal Signed-off-by: Chandan Kumar Jha --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 181 +++++-- drivers/cam_cpas/cpas_top/cpastop_v170_200.h | 538 +++++++++++++++++++ drivers/cam_cpas/include/cam_cpas_api.h | 53 ++ 3 files changed, 718 insertions(+), 54 deletions(-) create mode 100644 drivers/cam_cpas/cpas_top/cpastop_v170_200.h diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 1f52e1993a5c..c284350e2142 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -16,6 +16,7 @@ #include "cam_cpas_soc.h" #include "cpastop100.h" #include "cpastop_v150_100.h" +#include "cpastop_v170_200.h" #include "cpastop_v170_110.h" #include "cpastop_v175_100.h" #include "cpastop_v175_101.h" @@ -37,6 +38,110 @@ static const char * const camnoc_salve_err_code[] = { "Unknown Error", /* unknown err code */ }; +static const uint32_t cam_cpas_hw_version_map + [CAM_CPAS_CAMERA_VERSION_ID_MAX][CAM_CPAS_VERSION_ID_MAX] = { + /* for camera_150 */ + { + CAM_CPAS_TITAN_150_V100, + 0, + 0, + 0, + 0, + 0, + }, + /* for camera_170 */ + { + CAM_CPAS_TITAN_170_V100, + 0, + CAM_CPAS_TITAN_170_V110, + CAM_CPAS_TITAN_170_V120, + 0, + CAM_CPAS_TITAN_170_V200, + }, + /* for camera_175 */ + { + CAM_CPAS_TITAN_175_V100, + CAM_CPAS_TITAN_175_V101, + 0, + CAM_CPAS_TITAN_175_V120, + CAM_CPAS_TITAN_175_V130, + 0, + }, + /* for camera_480 */ + { + CAM_CPAS_TITAN_480_V100, + 0, + 0, + 0, + 0, + 0, + }, +}; + +static int cam_cpas_translate_camera_cpas_version_id( + uint32_t cam_version, + uint32_t cpas_version, + uint32_t *cam_version_id, + uint32_t *cpas_version_id) +{ + + switch (cam_version) { + + case CAM_CPAS_CAMERA_VERSION_150: + *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_150; + break; + + case CAM_CPAS_CAMERA_VERSION_170: + *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_170; + break; + + case CAM_CPAS_CAMERA_VERSION_175: + *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_175; + break; + + case CAM_CPAS_CAMERA_VERSION_480: + *cam_version_id = CAM_CPAS_CAMERA_VERSION_ID_480; + break; + + default: + CAM_ERR(CAM_CPAS, "Invalid cam version %u", + cam_version); + return -EINVAL; + } + + switch (cpas_version) { + + case CAM_CPAS_VERSION_100: + *cpas_version_id = CAM_CPAS_VERSION_ID_100; + break; + + case CAM_CPAS_VERSION_101: + *cpas_version_id = CAM_CPAS_VERSION_ID_101; + break; + case CAM_CPAS_VERSION_110: + *cpas_version_id = CAM_CPAS_VERSION_ID_110; + break; + + case CAM_CPAS_VERSION_120: + *cpas_version_id = CAM_CPAS_VERSION_ID_120; + break; + + case CAM_CPAS_VERSION_130: + *cpas_version_id = CAM_CPAS_VERSION_ID_130; + break; + + case CAM_CPAS_VERSION_200: + *cpas_version_id = CAM_CPAS_VERSION_ID_200; + break; + + default: + CAM_ERR(CAM_CPAS, "Invalid cpas version %u", + cpas_version); + return -EINVAL; + } + return 0; +} + static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, struct cam_cpas_hw_caps *hw_caps) { @@ -44,27 +149,30 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP]; uint32_t reg_value; + uint32_t cam_version, cpas_version; + uint32_t cam_version_id, cpas_version_id; + int rc; if (reg_indx == -1) return -EINVAL; hw_caps->camera_family = CAM_FAMILY_CPAS_SS; - reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x0); + cam_version = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x0); hw_caps->camera_version.major = - CAM_BITS_MASK_SHIFT(reg_value, 0xff0000, 0x10); + CAM_BITS_MASK_SHIFT(cam_version, 0xff0000, 0x10); hw_caps->camera_version.minor = - CAM_BITS_MASK_SHIFT(reg_value, 0xff00, 0x8); + CAM_BITS_MASK_SHIFT(cam_version, 0xff00, 0x8); hw_caps->camera_version.incr = - CAM_BITS_MASK_SHIFT(reg_value, 0xff, 0x0); + CAM_BITS_MASK_SHIFT(cam_version, 0xff, 0x0); - reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x4); + cpas_version = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x4); hw_caps->cpas_version.major = - CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c); + CAM_BITS_MASK_SHIFT(cpas_version, 0xf0000000, 0x1c); hw_caps->cpas_version.minor = - CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + CAM_BITS_MASK_SHIFT(cpas_version, 0xfff0000, 0x10); hw_caps->cpas_version.incr = - CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + CAM_BITS_MASK_SHIFT(cpas_version, 0xffff, 0x0); reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x8); hw_caps->camera_capability = reg_value; @@ -76,53 +184,15 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, hw_caps->cpas_version.incr, hw_caps->camera_capability); soc_info->hw_version = CAM_CPAS_TITAN_NONE; - - if ((hw_caps->camera_version.major == 1) && - (hw_caps->camera_version.minor == 7) && - (hw_caps->camera_version.incr == 0)) { - if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 0) && - (hw_caps->cpas_version.incr == 0)) - soc_info->hw_version = CAM_CPAS_TITAN_170_V100; - else if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 1) && - (hw_caps->cpas_version.incr == 0)) - soc_info->hw_version = CAM_CPAS_TITAN_170_V110; - else if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 2) && - (hw_caps->cpas_version.incr == 0)) - soc_info->hw_version = CAM_CPAS_TITAN_170_V120; - } else if ((hw_caps->camera_version.major == 1) && - (hw_caps->camera_version.minor == 7) && - (hw_caps->camera_version.incr == 5)) { - if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 0) && - (hw_caps->cpas_version.incr == 0)) - soc_info->hw_version = CAM_CPAS_TITAN_175_V100; - else if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 0) && - (hw_caps->cpas_version.incr == 1)) - soc_info->hw_version = CAM_CPAS_TITAN_175_V101; - else if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 2) && - (hw_caps->cpas_version.incr == 0)) - soc_info->hw_version = CAM_CPAS_TITAN_175_V120; - else if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 3) && - (hw_caps->cpas_version.incr == 0)) - soc_info->hw_version = CAM_CPAS_TITAN_175_V130; - } else if ((hw_caps->camera_version.major == 1) && - (hw_caps->camera_version.minor == 5) && - (hw_caps->camera_version.incr == 0)) { - if ((hw_caps->cpas_version.major == 1) && - (hw_caps->cpas_version.minor == 0) && - (hw_caps->cpas_version.incr == 0)) - soc_info->hw_version = CAM_CPAS_TITAN_150_V100; - } else if ((hw_caps->camera_version.major == 4) && - (hw_caps->camera_version.minor == 8) && - (hw_caps->camera_version.incr == 0)) { - soc_info->hw_version = CAM_CPAS_TITAN_480_V100; + rc = cam_cpas_translate_camera_cpas_version_id(cam_version, + cpas_version, &cam_version_id, &cpas_version_id); + if (rc) { + CAM_ERR(CAM_CPAS, "Invalid Version, Camera: 0x%x CPAS: 0x%x", + cam_version, cpas_version); + return -EINVAL; } + soc_info->hw_version = + cam_cpas_hw_version_map[cam_version_id][cpas_version_id]; CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); @@ -606,6 +676,9 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_170_V110: camnoc_info = &cam170_cpas110_camnoc_info; break; + case CAM_CPAS_TITAN_170_V200: + camnoc_info = &cam170_cpas200_camnoc_info; + break; case CAM_CPAS_TITAN_175_V100: camnoc_info = &cam175_cpas100_camnoc_info; break; diff --git a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h new file mode 100644 index 000000000000..98aabc984c87 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h @@ -0,0 +1,538 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V170_200_H_ +#define _CPASTOP_V170_200_H_ + +#define TEST_IRQ_ENABLE 0 +#define TCSR_CONN_RESET 0x0 +#define TCSR_CONN_SET 0x3 + +static struct cam_camnoc_irq_sbm cam_cpas_v170_200_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v170_200_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v170_200_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam170_cpas200_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam170_cpas200_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam170_cpas200_camnoc_info = { + .specific = &cam_cpas_v170_200_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v170_200_camnoc_specific), + .irq_sbm = &cam_cpas_v170_200_irq_sbm, + .irq_err = &cam_cpas_v170_200_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v170_200_irq_err), + .err_logger = &cam170_cpas200_err_logger_offsets, + .errata_wa_list = &cam170_cpas200_errata_wa_list, +}; + +#endif /* _CPASTOP_V170_200_H_ */ diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 7c551dfcf8a5..6bb226377056 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -32,6 +32,58 @@ enum cam_cpas_reg_base { CAM_CPAS_REG_MAX }; +/** + * enum cam_cpas_camera_version Enum for Titan Camera Versions + */ +enum cam_cpas_camera_version { + CAM_CPAS_CAMERA_VERSION_NONE = 0, + CAM_CPAS_CAMERA_VERSION_150 = 0x00010500, + CAM_CPAS_CAMERA_VERSION_170 = 0x00010700, + CAM_CPAS_CAMERA_VERSION_175 = 0x00010705, + CAM_CPAS_CAMERA_VERSION_480 = 0x00040800, + CAM_CPAS_CAMERA_VERSION_MAX +}; + +/** + * enum cam_cpas_version Enum for Titan CPAS Versions + */ +enum cam_cpas_version { + CAM_CPAS_VERSION_NONE = 0, + CAM_CPAS_VERSION_100 = 0x10000000, + CAM_CPAS_VERSION_101 = 0x10000001, + CAM_CPAS_VERSION_110 = 0x10010000, + CAM_CPAS_VERSION_120 = 0x10020000, + CAM_CPAS_VERSION_130 = 0x10030000, + CAM_CPAS_VERSION_200 = 0x20000000, + CAM_CPAS_VERSION_MAX +}; + +/** + * enum cam_cpas_camera_version_map_id Enum for camera version map id + * This enum is mapped with cam_cpas_camera_version + */ +enum cam_cpas_camera_version_map_id { + CAM_CPAS_CAMERA_VERSION_ID_150 = 0x0, + CAM_CPAS_CAMERA_VERSION_ID_170 = 0x1, + CAM_CPAS_CAMERA_VERSION_ID_175 = 0x2, + CAM_CPAS_CAMERA_VERSION_ID_480 = 0x3, + CAM_CPAS_CAMERA_VERSION_ID_MAX +}; + +/** + * enum cam_cpas_version_map_id Enum for cpas version map id + * This enum is mapped with cam_cpas_version + */ +enum cam_cpas_version_map_id { + CAM_CPAS_VERSION_ID_100 = 0x0, + CAM_CPAS_VERSION_ID_101 = 0x1, + CAM_CPAS_VERSION_ID_110 = 0x2, + CAM_CPAS_VERSION_ID_120 = 0x3, + CAM_CPAS_VERSION_ID_130 = 0x4, + CAM_CPAS_VERSION_ID_200 = 0x5, + CAM_CPAS_VERSION_ID_MAX +}; + /** * enum cam_cpas_hw_version - Enum for Titan CPAS HW Versions */ @@ -41,6 +93,7 @@ enum cam_cpas_hw_version { CAM_CPAS_TITAN_170_V100 = 0x170100, CAM_CPAS_TITAN_170_V110 = 0x170110, CAM_CPAS_TITAN_170_V120 = 0x170120, + CAM_CPAS_TITAN_170_V200 = 0x170200, CAM_CPAS_TITAN_175_V100 = 0x175100, CAM_CPAS_TITAN_175_V101 = 0x175101, CAM_CPAS_TITAN_175_V120 = 0x175120, -- GitLab From 350b15ad83527acad23235ff5bd71a0021295401 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Tue, 3 Dec 2019 14:35:26 -0800 Subject: [PATCH 184/410] msm: camera: memmgr: Add support to disable DelayedUnmap Add interface to umd to give an option whether to disable Delayed Unamp feature for a given buffer mapping. DelayedUnmap is enabled by default if umd doesn't explicitly asks for disable. CRs-Fixed: 2580128 Change-Id: I66f87a9dbdfc4d9cecdc02eb24c1c670c9985cae Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_req_mgr/cam_mem_mgr.c | 5 +++++ drivers/cam_smmu/cam_smmu_api.c | 36 +++++++++++++++++++------------ drivers/cam_smmu/cam_smmu_api.h | 7 +++--- include/uapi/media/cam_req_mgr.h | 1 + 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index a0b1e66f8e0c..eef1583451ba 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -505,12 +505,16 @@ static int cam_mem_util_map_hw_va(uint32_t flags, int i; int rc = -1; int dir = cam_mem_util_get_dma_dir(flags); + bool dis_delayed_unmap = false; if (dir < 0) { CAM_ERR(CAM_MEM, "fail to map DMA direction, dir=%d", dir); return dir; } + if (flags & CAM_MEM_FLAG_DISABLE_DELAYED_UNMAP) + dis_delayed_unmap = true; + CAM_DBG(CAM_MEM, "map_hw_va : fd = %d, flags = 0x%x, dir=%d, num_hdls=%d", fd, flags, dir, num_hdls); @@ -534,6 +538,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, for (i = 0; i < num_hdls; i++) { rc = cam_smmu_map_user_iova(mmu_hdls[i], fd, + dis_delayed_unmap, dir, (dma_addr_t *)hw_vaddr, len, diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 784ea62e0925..a26049140b36 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -218,8 +218,9 @@ static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, dma_addr_t virt_addr); static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, - enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, - size_t *len_ptr, enum cam_smmu_region_id region_id); + bool dis_delayed_unmap, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id); static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, struct dma_buf *buf, enum dma_data_direction dma_dir, @@ -1691,7 +1692,7 @@ EXPORT_SYMBOL(cam_smmu_release_sec_heap); static int cam_smmu_map_buffer_validate(struct dma_buf *buf, int idx, enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, size_t *len_ptr, enum cam_smmu_region_id region_id, - struct cam_dma_buff_info **mapping_info) + bool dis_delayed_unmap, struct cam_dma_buff_info **mapping_info) { struct dma_buf_attachment *attach = NULL; struct sg_table *table = NULL; @@ -1766,7 +1767,8 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, } iommu_cb_set.cb_info[idx].shared_mapping_size += *len_ptr; } else if (region_id == CAM_SMMU_REGION_IO) { - attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + if (!dis_delayed_unmap) + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; table = dma_buf_map_attachment(attach, dma_dir); if (IS_ERR_OR_NULL(table)) { @@ -1784,8 +1786,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, goto err_unmap_sg; } - CAM_DBG(CAM_SMMU, "iova=%pK, region_id=%d, paddr=%pK, len=%d", - iova, region_id, *paddr_ptr, *len_ptr); + CAM_DBG(CAM_SMMU, + "iova=%pK, region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", + iova, region_id, *paddr_ptr, *len_ptr, attach->dma_map_attrs); if (table->sgl) { CAM_DBG(CAM_SMMU, @@ -1853,8 +1856,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, - enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, - size_t *len_ptr, enum cam_smmu_region_id region_id) + bool dis_delayed_unmap, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id) { int rc = -1; struct cam_dma_buff_info *mapping_info = NULL; @@ -1864,7 +1868,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, buf = dma_buf_get(ion_fd); rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, - region_id, &mapping_info); + region_id, dis_delayed_unmap, &mapping_info); if (rc) { CAM_ERR(CAM_SMMU, "buffer validation failure"); @@ -1888,7 +1892,7 @@ static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, struct cam_dma_buff_info *mapping_info = NULL; rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, - region_id, &mapping_info); + region_id, false, &mapping_info); if (rc) { CAM_ERR(CAM_SMMU, "buffer validation failure"); @@ -1925,6 +1929,11 @@ static int cam_smmu_unmap_buf_and_remove_from_list( return -EINVAL; } + CAM_DBG(CAM_SMMU, + "region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", + mapping_info->region_id, mapping_info->paddr, mapping_info->len, + mapping_info->attach->dma_map_attrs); + if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) { CAM_DBG(CAM_SMMU, "Removing SHARED buffer paddr = %pK, len = %zu", @@ -1953,7 +1962,6 @@ static int cam_smmu_unmap_buf_and_remove_from_list( iommu_cb_set.cb_info[idx].shared_mapping_size -= mapping_info->len; } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) { - mapping_info->attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; iommu_cb_set.cb_info[idx].io_mapping_size -= mapping_info->len; } @@ -2706,7 +2714,7 @@ static int cam_smmu_map_iova_validate_params(int handle, return rc; } -int cam_smmu_map_user_iova(int handle, int ion_fd, +int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, size_t *len_ptr, enum cam_smmu_region_id region_id) { @@ -2757,8 +2765,8 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, goto get_addr_end; } - rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir, - paddr_ptr, len_ptr, region_id); + rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, + dis_delayed_unmap, dma_dir, paddr_ptr, len_ptr, region_id); if (rc < 0) { CAM_ERR(CAM_SMMU, "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d", diff --git a/drivers/cam_smmu/cam_smmu_api.h b/drivers/cam_smmu/cam_smmu_api.h index 6932505f0aaf..935e813d450a 100644 --- a/drivers/cam_smmu/cam_smmu_api.h +++ b/drivers/cam_smmu/cam_smmu_api.h @@ -98,6 +98,8 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); * * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) * @param ion_fd: ION handle identifying the memory buffer. + * @param dis_delayed_unmap: Whether to disable Delayed Unmap feature + * for this mapping * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, * DMA_TO_DEVICE or DMA_FROM_DEVICE * @dma_addr : Pointer to physical address where mapped address will be @@ -107,9 +109,8 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); * @len_ptr : Length of buffer mapped returned by CAM SMMU driver. * @return Status of operation. Negative in case of error. Zero otherwise. */ -int cam_smmu_map_user_iova(int handle, - int ion_fd, enum cam_smmu_map_dir dir, - dma_addr_t *dma_addr, size_t *len_ptr, +int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, + enum cam_smmu_map_dir dir, dma_addr_t *dma_addr, size_t *len_ptr, enum cam_smmu_region_id region_id); /** diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index adfc1cb32f78..5bab420a7b02 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -274,6 +274,7 @@ struct cam_req_mgr_link_control { #define CAM_MEM_FLAG_CACHE (1<<10) #define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11) #define CAM_MEM_FLAG_CDSP_OUTPUT (1<<12) +#define CAM_MEM_FLAG_DISABLE_DELAYED_UNMAP (1<<13) #define CAM_MEM_MMU_MAX_HANDLE 16 -- GitLab From 38692ba946dbeafde93f49617aa9132b6e922fe5 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Sat, 7 Dec 2019 04:00:45 -0800 Subject: [PATCH 185/410] msm: camera: smmu: Add support for non-contiguous mermory region Add support to discard a memory region inside the full dma map virtual address space region. CRs-Fixed: 2580128 Change-Id: I76cc778f2437a01a4efabec836ce92c47d983d61 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_icp/fw_inc/hfi_intf.h | 2 + drivers/cam_icp/fw_inc/hfi_reg.h | 2 + drivers/cam_icp/hfi.c | 17 +++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 74 ++++++++-- drivers/cam_smmu/cam_smmu_api.c | 136 +++++++++++++++++- drivers/cam_smmu/cam_smmu_api.h | 13 +- 6 files changed, 226 insertions(+), 18 deletions(-) diff --git a/drivers/cam_icp/fw_inc/hfi_intf.h b/drivers/cam_icp/fw_inc/hfi_intf.h index 1dcf4ee3668a..afd42d23b9fb 100644 --- a/drivers/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/cam_icp/fw_inc/hfi_intf.h @@ -32,6 +32,7 @@ struct hfi_mem { * @sec_heap: secondary heap hfi memory for firmware * @qdss: qdss mapped memory for fw * @io_mem: io memory info + * @io_mem2: 2nd io memory info * @icp_base: icp base address */ struct hfi_mem_info { @@ -44,6 +45,7 @@ struct hfi_mem_info { struct hfi_mem shmem; struct hfi_mem qdss; struct hfi_mem io_mem; + struct hfi_mem io_mem2; void __iomem *icp_base; }; diff --git a/drivers/cam_icp/fw_inc/hfi_reg.h b/drivers/cam_icp/fw_inc/hfi_reg.h index 2a30c1451201..df4ae01d7ef2 100644 --- a/drivers/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/cam_icp/fw_inc/hfi_reg.h @@ -39,6 +39,8 @@ #define HFI_REG_QDSS_IOVA_SIZE 0x70 #define HFI_REG_IO_REGION_IOVA 0x74 #define HFI_REG_IO_REGION_SIZE 0x78 +#define HFI_REG_IO2_REGION_IOVA 0x7C +#define HFI_REG_IO2_REGION_SIZE 0x80 /* end of ICP CSR registers */ diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index b5d340cb424a..89a95aca62e1 100644 --- a/drivers/cam_icp/hfi.c +++ b/drivers/cam_icp/hfi.c @@ -669,6 +669,15 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, icp_base + HFI_REG_IO_REGION_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova, + icp_base + HFI_REG_IO2_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len, + icp_base + HFI_REG_IO2_REGION_SIZE); + + CAM_INFO(CAM_HFI, "Resume IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]", + hfi_mem->io_mem.iova, hfi_mem->io_mem.len, + hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len); + return rc; } @@ -859,6 +868,14 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, icp_base + HFI_REG_IO_REGION_IOVA); cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, icp_base + HFI_REG_IO_REGION_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova, + icp_base + HFI_REG_IO2_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len, + icp_base + HFI_REG_IO2_REGION_SIZE); + + CAM_INFO(CAM_HFI, "Init IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]", + hfi_mem->io_mem.iova, hfi_mem->io_mem.len, + hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len); hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION); 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 1c2e72c9a58b..ce7bb36c38a1 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 @@ -2715,18 +2715,21 @@ static int cam_icp_allocate_qdss_mem(void) static int cam_icp_get_io_mem_info(void) { int rc; - size_t len; - dma_addr_t iova; + size_t len, discard_iova_len; + dma_addr_t iova, discard_iova_start; rc = cam_smmu_get_io_region_info(icp_hw_mgr.iommu_hdl, - &iova, &len); + &iova, &len, &discard_iova_start, &discard_iova_len); if (rc) return rc; icp_hw_mgr.hfi_mem.io_mem.iova_len = len; icp_hw_mgr.hfi_mem.io_mem.iova_start = iova; + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start = discard_iova_start; + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len = discard_iova_len; - CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len); + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu discard iova %llx len %llx", + iova, len, discard_iova_start, discard_iova_len); return rc; } @@ -3019,12 +3022,38 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; - hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; - hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start && + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start - + icp_hw_mgr.hfi_mem.io_mem.iova_start; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start + + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len; + hfi_mem.io_mem2.len = + icp_hw_mgr.hfi_mem.io_mem.iova_start + + icp_hw_mgr.hfi_mem.io_mem.iova_len - + hfi_mem.io_mem2.iova; + } else { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; - CAM_DBG(CAM_ICP, "IO region IOVA = %X length = %lld", - hfi_mem.io_mem.iova, - hfi_mem.io_mem.len); + /* IO Region 2 */ + hfi_mem.io_mem2.iova = 0x0; + hfi_mem.io_mem2.len = 0x0; + } + + CAM_DBG(CAM_ICP, + "IO region1 IOVA = %X length = %lld, IO region2 IOVA = %X length = %lld", + hfi_mem.io_mem.iova, + hfi_mem.io_mem.len, + hfi_mem.io_mem2.iova, + hfi_mem.io_mem2.len); return cam_hfi_resume(&hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, @@ -3440,8 +3469,31 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; - hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; - hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start && + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start - + icp_hw_mgr.hfi_mem.io_mem.iova_start; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start + + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len; + hfi_mem.io_mem2.len = + icp_hw_mgr.hfi_mem.io_mem.iova_start + + icp_hw_mgr.hfi_mem.io_mem.iova_len - + hfi_mem.io_mem2.iova; + } else { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = 0x0; + hfi_mem.io_mem2.len = 0x0; + } return cam_hfi_init(0, &hfi_mem, a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index a26049140b36..03a20f9917c7 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include #include @@ -134,6 +136,10 @@ struct cam_context_bank_info { size_t io_mapping_size; size_t shared_mapping_size; + + /* discard iova - non-zero values are valid */ + dma_addr_t discard_iova_start; + size_t discard_iova_len; }; struct cam_iommu_cb_set { @@ -1419,11 +1425,13 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl) EXPORT_SYMBOL(cam_smmu_dealloc_qdss); int cam_smmu_get_io_region_info(int32_t smmu_hdl, - dma_addr_t *iova, size_t *len) + dma_addr_t *iova, size_t *len, + dma_addr_t *discard_iova_start, size_t *discard_iova_len) { int32_t idx; - if (!iova || !len || (smmu_hdl == HANDLE_INIT)) { + if (!iova || !len || !discard_iova_start || !discard_iova_len || + (smmu_hdl == HANDLE_INIT)) { CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); return -EINVAL; } @@ -1445,10 +1453,15 @@ int cam_smmu_get_io_region_info(int32_t smmu_hdl, mutex_lock(&iommu_cb_set.cb_info[idx].lock); *iova = iommu_cb_set.cb_info[idx].io_info.iova_start; *len = iommu_cb_set.cb_info[idx].io_info.iova_len; + *discard_iova_start = + iommu_cb_set.cb_info[idx].io_info.discard_iova_start; + *discard_iova_len = + iommu_cb_set.cb_info[idx].io_info.discard_iova_len; CAM_DBG(CAM_SMMU, - "I/O area for hdl = %x start addr = %pK len = %zu", - smmu_hdl, *iova, *len); + "I/O area for hdl = %x Region:[%pK %zu] Discard:[%pK %zu]", + smmu_hdl, *iova, *len, + *discard_iova_start, *discard_iova_len); mutex_unlock(&iommu_cb_set.cb_info[idx].lock); return 0; @@ -3279,6 +3292,11 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, rc = -ENODEV; goto end; } + + if (cb->discard_iova_start) + iommu_dma_reserve_iova(dev, cb->discard_iova_start, + cb->discard_iova_len); + cb->state = CAM_SMMU_ATTACH; } else { CAM_ERR(CAM_SMMU, "Context bank does not have IO region"); @@ -3345,6 +3363,52 @@ static int cam_alloc_smmu_context_banks(struct device *dev) return 0; } +static int cam_smmu_get_discard_memory_regions(struct device_node *of_node, + dma_addr_t *discard_iova_start, size_t *discard_iova_len) +{ + uint32_t discard_iova[2] = { 0 }; + int num_values = 0; + int rc = 0; + + if (!discard_iova_start || !discard_iova_len) + return -EINVAL; + + *discard_iova_start = 0; + *discard_iova_len = 0; + + num_values = of_property_count_u32_elems(of_node, + "iova-region-discard"); + if (num_values <= 0) { + CAM_DBG(CAM_UTIL, "No discard region specified"); + return 0; + } else if (num_values != 2) { + CAM_ERR(CAM_UTIL, "Invalid discard region specified %d", + num_values); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, + "iova-region-discard", + discard_iova, num_values); + if (rc) { + CAM_ERR(CAM_UTIL, "Can not read discard region %d", num_values); + return rc; + } else if (!discard_iova[0] || !discard_iova[1]) { + CAM_ERR(CAM_UTIL, + "Incorrect Discard region specified [0x%x 0x%x]", + discard_iova[0], discard_iova[1]); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, "Discard region [0x%x 0x%x]", + discard_iova[0], discard_iova[0] + discard_iova[1]); + + *discard_iova_start = discard_iova[0]; + *discard_iova_len = discard_iova[1]; + + return 0; +} + static int cam_smmu_get_memory_regions_info(struct device_node *of_node, struct cam_context_bank_info *cb) { @@ -3443,6 +3507,16 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, cb->io_support = 1; cb->io_info.iova_start = region_start; cb->io_info.iova_len = region_len; + rc = cam_smmu_get_discard_memory_regions(child_node, + &cb->io_info.discard_iova_start, + &cb->io_info.discard_iova_len); + if (rc) { + CAM_ERR(CAM_SMMU, + "Invalid Discard region specified in IO region, rc=%d", + rc); + of_node_put(mem_map_node); + return -EINVAL; + } break; case CAM_SMMU_REGION_SECHEAP: cb->secheap_support = 1; @@ -3467,6 +3541,60 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, CAM_DBG(CAM_SMMU, "region_len -> %X", region_len); CAM_DBG(CAM_SMMU, "region_id -> %X", region_id); } + + if (cb->io_support) { + rc = cam_smmu_get_discard_memory_regions(of_node, + &cb->discard_iova_start, + &cb->discard_iova_len); + if (rc) { + CAM_ERR(CAM_SMMU, + "Invalid Discard region specified in CB, rc=%d", + rc); + of_node_put(mem_map_node); + return -EINVAL; + } + + /* Make sure Discard region is properly specified */ + if ((cb->discard_iova_start != + cb->io_info.discard_iova_start) || + (cb->discard_iova_len != + cb->io_info.discard_iova_len)) { + CAM_ERR(CAM_SMMU, + "Mismatch Discard region specified, [0x%x 0x%x] [0x%x 0x%x]", + cb->discard_iova_start, + cb->discard_iova_len, + cb->io_info.discard_iova_start, + cb->io_info.discard_iova_len); + of_node_put(mem_map_node); + return -EINVAL; + } else if (cb->discard_iova_start && cb->discard_iova_len) { + if ((cb->discard_iova_start <= + cb->io_info.iova_start) || + (cb->discard_iova_start >= + cb->io_info.iova_start + cb->io_info.iova_len) || + (cb->discard_iova_start + cb->discard_iova_len >= + cb->io_info.iova_start + cb->io_info.iova_len)) { + CAM_ERR(CAM_SMMU, + "[%s] : Incorrect Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", + cb->name, + cb->discard_iova_start, + cb->discard_iova_start + cb->discard_iova_len, + cb->io_info.iova_start, + cb->io_info.iova_start + cb->io_info.iova_len); + of_node_put(mem_map_node); + return -EINVAL; + } + + CAM_INFO(CAM_SMMU, + "[%s] : Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", + cb->name, + cb->discard_iova_start, + cb->discard_iova_start + cb->discard_iova_len, + cb->io_info.iova_start, + cb->io_info.iova_start + cb->io_info.iova_len); + } + } + of_node_put(mem_map_node); if (!num_regions) { diff --git a/drivers/cam_smmu/cam_smmu_api.h b/drivers/cam_smmu/cam_smmu_api.h index 935e813d450a..4a4a0d312f9d 100644 --- a/drivers/cam_smmu/cam_smmu_api.h +++ b/drivers/cam_smmu/cam_smmu_api.h @@ -60,12 +60,16 @@ typedef void (*cam_smmu_client_page_fault_handler)(struct iommu_domain *domain, /** * @brief : Structure to store region information * - * @param iova_start : Start address of region - * @param iova_len : length of region + * @param iova_start : Start address of region + * @param iova_len : length of region + * @param discard_iova_start : iova addr start from where should not be used + * @param discard_iova_len : length of discard iova region */ struct cam_smmu_region_info { dma_addr_t iova_start; size_t iova_len; + dma_addr_t discard_iova_start; + size_t discard_iova_len; }; /** @@ -387,10 +391,13 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl); * @param smmu_hdl: SMMU handle identifying the context bank * @param iova: IOVA address of allocated I/O region * @param len: Length of allocated I/O memory + * @param discard_iova_start: Start address of io space to discard + * @param discard_iova_len: Length of io space to discard * * @return Status of operation. Negative in case of error. Zero otherwise. */ int cam_smmu_get_io_region_info(int32_t smmu_hdl, - dma_addr_t *iova, size_t *len); + dma_addr_t *iova, size_t *len, + dma_addr_t *discard_iova_start, size_t *discard_iova_len); #endif /* _CAM_SMMU_API_H_ */ -- GitLab From 421e8ed8d42a71460d0e2eaf0f6135362befa8b6 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Mon, 16 Dec 2019 15:08:51 -0800 Subject: [PATCH 186/410] msm: camera: smmu: Use iommu best match algo for camera Use best fit match algo for smmu map instead of first match algo to avoid fragmentation in smmu virtual space. CRs-Fixed: 2580128 Change-Id: I434e6e4396bc713e6e12e3da7ae4b78cc2da6a42 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_smmu/cam_smmu_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 03a20f9917c7..e8df9813226c 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -3293,6 +3293,8 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, goto end; } + iommu_dma_enable_best_fit_algo(dev); + if (cb->discard_iova_start) iommu_dma_reserve_iova(dev, cb->discard_iova_start, cb->discard_iova_len); -- GitLab From c74240992b52a67d72ac4d885625ed412d5571dc Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Wed, 18 Dec 2019 16:27:40 +0530 Subject: [PATCH 187/410] msm: camera: cdm: Clear IRQ before reading userdata CDM driver read the user_data reg to inform CDM's clients about the request status being served. If before clearing the IRQ, the value of userdata register gets updated, then CDM will not receive another INLINE_IRQ for the updated userdata. This change will make sure that another interrupt is fired by clearing the IRQ first and reading the userdata later. CRs-Fixed: 2581559 Change-Id: I74edf1b8439ae2f88f30b6c2fdbf9ac9f3742503 Signed-off-by: Abhilash Kumar --- drivers/cam_cdm/cam_cdm_hw_core.c | 11 ++++++----- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index f54f9d61b55f..0663b8d0f30d 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -665,6 +665,12 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) kfree(payload); return IRQ_HANDLED; } + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR, + payload->irq_status)) + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ Clear"); + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR_CMD, 0x01)) + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd"); + if (payload->irq_status & CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_USR_DATA, @@ -677,11 +683,6 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) payload->hw = cdm_hw; INIT_WORK((struct work_struct *)&payload->work, cam_hw_cdm_work); - if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR, - payload->irq_status)) - CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ Clear"); - if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR_CMD, 0x01)) - CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd"); work_status = queue_work(cdm_core->work_queue, &payload->work); if (work_status == false) { CAM_ERR(CAM_CDM, "Failed to queue work for irq=0x%x", diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 80857bba45af..483f0622d764 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -3750,7 +3750,20 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) cam_ife_mgr_pause_hw(ctx); - wait_for_completion(&ctx->config_done_complete); + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(300)); + if (rc <= 0) { + CAM_WARN(CAM_ISP, + "config done completion timeout for last applied req_id=%llu rc=%d ctx_index %d", + ctx->applied_req_id, rc, ctx->ctx_index); + rc = -ETIMEDOUT; + } else { + CAM_DBG(CAM_ISP, + "config done Success for req_id=%llu ctx_index %d", + ctx->applied_req_id, ctx->ctx_index); + rc = 0; + } if (stop_isp->stop_only) goto end; -- GitLab From 5c5e3a28a290b86e0288d6d5a318c0be30eca537 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 17 Dec 2019 15:21:45 +0530 Subject: [PATCH 188/410] msm: camera: isp: Mask unused rdi interrupts Enable rdi interrupts from the required sources only, other unused interrupts from rdi sources should be masked. Also in the case where multiple rdi has been acquired in same context interrupts from only one of them should be enabled. CRs-Fixed: 2590476 Change-Id: Icd074d1566db0b758d25c7b127402b424e48efd9 Signed-off-by: Tejas Prajapati --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 7aaacde775f4..a0e7741e5505 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -212,7 +212,7 @@ static int cam_vfe_rdi_resource_start( struct cam_vfe_mux_rdi_data *rsrc_data; int rc = 0; uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; - uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t rdi_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; if (!rdi_res) { CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); @@ -230,10 +230,6 @@ static int cam_vfe_rdi_resource_start( rsrc_data->rdi_common_reg_data->error_irq_mask0; err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = rsrc_data->rdi_common_reg_data->error_irq_mask1; - irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = - rsrc_data->rdi_common_reg_data->subscribe_irq_mask0; - irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = - rsrc_data->rdi_common_reg_data->subscribe_irq_mask1; rdi_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; @@ -261,11 +257,19 @@ static int cam_vfe_rdi_resource_start( if (!rdi_res->rdi_only_ctx) goto end; + rdi_irq_mask[0] = + (rsrc_data->reg_data->reg_update_irq_mask | + rsrc_data->reg_data->sof_irq_mask); + + CAM_DBG(CAM_ISP, "RDI%d irq_mask 0x%x", + rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0, + rdi_irq_mask[0]); + if (!rsrc_data->irq_handle) { rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( rsrc_data->vfe_irq_controller, CAM_IRQ_PRIORITY_1, - irq_mask, + rdi_irq_mask, rdi_res, rdi_res->top_half_handler, rdi_res->bottom_half_handler, -- GitLab From 2f86e7386d510ea3e63a2ccb2bdc4ac4b360d54d Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Sun, 8 Dec 2019 12:56:06 -0800 Subject: [PATCH 189/410] msm: camera: icp: Enqueue the abort cmd in workq The request frame cmds are submitted to the FW in workq context. The abort cmd as part of flush is triggered in user thread context. This change will enqueue the abort as part of flush to FW in workq, thereby ensuring that if there are any pending frames they are submitted prior to the abort cmd. CRs-Fixed: 2588575 Change-Id: I5034ca500cf39dfa0e553c49917fedb8bd084b0b Signed-off-by: Karthik Anantha Ram --- drivers/cam_core/cam_context_utils.c | 1 + drivers/cam_core/cam_hw_mgr_intf.h | 3 + .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 109 +++++++++++++++++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 2 + drivers/cam_smmu/cam_smmu_api.c | 4 +- 5 files changed, 113 insertions(+), 6 deletions(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index dd5bcd455030..423961aaf2af 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -615,6 +615,7 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) ctx->dev_name, ctx->ctx_id); flush_args.num_req_pending = 0; + flush_args.last_flush_req = ctx->last_flush_req; while (true) { spin_lock(&ctx->lock); if (list_empty(&temp_list)) { diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 28426b8dc757..fe074734f389 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -258,6 +258,8 @@ struct cam_hw_config_args { * @num_req_active: Num request to flush, valid when flush type is REQ * @flush_req_active: Request active pointers to flush * @flush_type: The flush type + * @last_flush_req: last flush req_id notified to hw_mgr for the + * given stream * */ struct cam_hw_flush_args { @@ -267,6 +269,7 @@ struct cam_hw_flush_args { uint32_t num_req_active; void *flush_req_active[20]; enum flush_type_t flush_type; + uint32_t last_flush_req; }; /** 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 1c2e72c9a58b..1fd59ae86b0f 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 @@ -3061,11 +3061,63 @@ static int cam_icp_retry_wait_for_abort( return -ETIMEDOUT; } +static int cam_icp_mgr_abort_handle_wq( + void *priv, void *data) +{ + int rc; + size_t packet_size; + struct hfi_cmd_work_data *task_data = NULL; + struct cam_icp_hw_ctx_data *ctx_data; + struct hfi_cmd_ipebps_async *abort_cmd; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid params %pK %pK", data, priv); + return -EINVAL; + } + + task_data = (struct hfi_cmd_work_data *)data; + ctx_data = + (struct cam_icp_hw_ctx_data *)task_data->data; + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + sizeof(struct hfi_cmd_abort) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + abort_cmd = kzalloc(packet_size, GFP_KERNEL); + CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size); + if (!abort_cmd) { + rc = -ENOMEM; + return rc; + } + + abort_cmd->size = packet_size; + abort_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT; + else + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_ABORT; + + abort_cmd->num_fw_handles = 1; + abort_cmd->fw_handles[0] = ctx_data->fw_handle; + abort_cmd->user_data1 = PTR_TO_U64(ctx_data); + abort_cmd->user_data2 = (uint64_t)0x0; + + rc = hfi_write_cmd(abort_cmd); + if (rc) { + kfree(abort_cmd); + return rc; + } + CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK ctx_id %d", + ctx_data->fw_handle, ctx_data, ctx_data->ctx_id); + + kfree(abort_cmd); + return rc; +} + static int cam_icp_mgr_abort_handle( struct cam_icp_hw_ctx_data *ctx_data) { int rc = 0; - unsigned long rem_jiffies; + unsigned long rem_jiffies = 0; size_t packet_size; int timeout = 1000; struct hfi_cmd_ipebps_async *abort_cmd; @@ -3201,6 +3253,7 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id) hw_mgr->ctx_data[ctx_id].fw_handle = 0; hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0; + hw_mgr->ctx_data[ctx_id].last_flush_req = 0; for (i = 0; i < CAM_FRAME_CMD_MAX; i++) clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); @@ -3808,6 +3861,11 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd"); } + if (req_id <= ctx_data->last_flush_req) + CAM_WARN(CAM_ICP, + "Anomaly submitting flushed req %llu [last_flush %llu] in ctx %u", + req_id, ctx_data->last_flush_req, ctx_data->ctx_id); + rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); if (rc) goto config_err; @@ -4857,6 +4915,46 @@ static void cam_icp_mgr_flush_info_dump( } } +static int cam_icp_mgr_enqueue_abort( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int timeout = 1000, rc; + unsigned long rem_jiffies = 0; + struct hfi_cmd_work_data *task_data; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + return -ENOMEM; + } + + reinit_completion(&ctx_data->wait_complete); + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ctx_data; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_abort_handle_wq; + cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = cam_icp_retry_wait_for_abort(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, + "FW timeout/err in abort handle command ctx: %u", + ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + return rc; + } + } + + CAM_DBG(CAM_ICP, "Abort after flush is success"); + return 0; +} + static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -4881,9 +4979,10 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) return -EINVAL; } - CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d", - ctx_data->ctx_id, flush_args->flush_type); - + ctx_data->last_flush_req = flush_args->last_flush_req; + CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d last_flush_req %u", + ctx_data->ctx_id, flush_args->flush_type, + ctx_data->last_flush_req); switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: mutex_lock(&hw_mgr->hw_mgr_mutex); @@ -4892,7 +4991,7 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) mutex_unlock(&hw_mgr->hw_mgr_mutex); cam_icp_mgr_flush_info_dump(flush_args, ctx_data->ctx_id); - cam_icp_mgr_abort_handle(ctx_data); + cam_icp_mgr_enqueue_abort(ctx_data); } else { mutex_unlock(&hw_mgr->hw_mgr_mutex); } diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 7ca32efd9318..8cab9a80cd30 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -232,6 +232,7 @@ struct cam_ctx_clk_info { * @watch_dog: watchdog timer handle * @watch_dog_reset_counter: Counter for watch dog reset * @icp_dev_io_info: io config resource + * @last_flush_req: last flush req for this ctx */ struct cam_icp_hw_ctx_data { void *context_priv; @@ -253,6 +254,7 @@ struct cam_icp_hw_ctx_data { struct cam_req_mgr_timer *watch_dog; uint32_t watch_dog_reset_counter; struct cam_icp_acquire_dev_info icp_dev_io_info; + uint64_t last_flush_req; }; /** diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index a26049140b36..91cce54d682f 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -293,6 +293,7 @@ static void cam_smmu_page_fault_work(struct work_struct *work) buf_info); } } + cam_smmu_dump_cb_info(idx); kfree(payload); } @@ -425,8 +426,9 @@ static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr) if (closest_mapping) { buf_handle = GET_MEM_HANDLE(idx, closest_mapping->ion_fd); CAM_INFO(CAM_SMMU, - "Closest map fd %d 0x%lx 0x%lx-0x%lx buf=%pK mem %0x", + "Closest map fd %d 0x%lx %llu-%llu 0x%lx-0x%lx buf=%pK mem %0x", closest_mapping->ion_fd, current_addr, + mapping->len, closest_mapping->len, (unsigned long)closest_mapping->paddr, (unsigned long)closest_mapping->paddr + mapping->len, closest_mapping->buf, -- GitLab From cc9864193caa5fa3806974afad0dcae88cd1599f Mon Sep 17 00:00:00 2001 From: Prakasha Nayak Date: Thu, 12 Dec 2019 15:18:36 +0530 Subject: [PATCH 190/410] msm: camera: icp: Mapping fw error numbers with error names This change will print ICP error names based on error type. CRs-Fixed: 2456658 Change-Id: I975598a7404f7520912d7b3211b6baa249e7f238 Signed-off-by: Prakasha Nayak --- drivers/cam_icp/fw_inc/hfi_sys_defs.h | 6 ++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 95 +++++++++++++++++-- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/drivers/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/cam_icp/fw_inc/hfi_sys_defs.h index 905b85a53633..f62e8cc99430 100644 --- a/drivers/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/cam_icp/fw_inc/hfi_sys_defs.h @@ -82,6 +82,12 @@ #define CAMERAICP_EHWVIOLATION 11 #define CAMERAICP_ECDMERROR 12 +/* HFI Specific errors. */ +#define CAMERAICP_HFI_ERR_COMMAND_SIZE 1000 +#define CAMERAICP_HFI_ERR_MESSAGE_SIZE 1001 +#define CAMERAICP_HFI_QUEUE_EMPTY 1002 +#define CAMERAICP_HFI_QUEUE_FULL 1003 + /* Core level commands */ /* IPE/BPS core Commands */ #define HFI_CMD_IPE_BPS_COMMON_START \ 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 1fd59ae86b0f..addb59ccb89a 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 @@ -1955,6 +1955,70 @@ static int cam_icp_mgr_cleanup_ctx(struct cam_icp_hw_ctx_data *ctx_data) return 0; } +static const char *cam_icp_error_handle_id_to_type( + uint32_t error_handle) +{ + const char *name = NULL; + + switch (error_handle) { + case CAMERAICP_SUCCESS: + name = "SUCCESS"; + break; + case CAMERAICP_EFAILED: + name = "EFAILED"; + break; + case CAMERAICP_ENOMEMORY: + name = "ENOMEMORY"; + break; + case CAMERAICP_EBADSTATE: + name = "EBADSTATE"; + break; + case CAMERAICP_EBADPARM: + name = "EBADPARM"; + break; + case CAMERAICP_EBADITEM: + name = "EBADITEM"; + break; + case CAMERAICP_EINVALIDFORMAT: + name = "EINVALIDFORMAT"; + break; + case CAMERAICP_EUNSUPPORTED: + name = "EUNSUPPORTED"; + break; + case CAMERAICP_EOUTOFBOUND: + name = "EOUTOFBOUND"; + break; + case CAMERAICP_ETIMEDOUT: + name = "ETIMEDOUT"; + break; + case CAMERAICP_EABORTED: + name = "EABORTED"; + break; + case CAMERAICP_EHWVIOLATION: + name = "EHWVIOLATION"; + break; + case CAMERAICP_ECDMERROR: + name = "ECDMERROR"; + break; + case CAMERAICP_HFI_ERR_COMMAND_SIZE: + name = "HFI_ERR_COMMAND_SIZE"; + break; + case CAMERAICP_HFI_ERR_MESSAGE_SIZE: + name = "HFI_ERR_MESSAGE_SIZE"; + break; + case CAMERAICP_HFI_QUEUE_EMPTY: + name = "HFI_QUEUE_EMPTY"; + break; + case CAMERAICP_HFI_QUEUE_FULL: + name = "HFI_QUEUE_FULL"; + break; + default: + name = NULL; + break; + } + return name; +} + static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) { int i; @@ -2014,8 +2078,10 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) ctx_data->icp_dev_acquire_info->dev_type); else CAM_ERR(CAM_ICP, - "Done with error: %u on ctx_id %d dev %d for req %llu", + "Done with error: %u err_type= [%s] on ctx_id %d dev %d for req %llu", ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type), ctx_data->ctx_id, ctx_data->icp_dev_acquire_info->dev_type, request_id); @@ -2088,8 +2154,13 @@ static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr) ipe_config_ack = (struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data); if (ipe_config_ack->rc) { - CAM_ERR(CAM_ICP, "rc = %d err = %u", - ipe_config_ack->rc, ioconfig_ack->err_type); + CAM_ERR(CAM_ICP, "rc = %d failed with\n" + "err_no = [%u] err_type = [%s]", + ipe_config_ack->rc, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); + return -EIO; } ctx_data = (struct cam_icp_hw_ctx_data *) @@ -2254,9 +2325,13 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); - CAM_DBG(CAM_ICP, - "received IPE/BPS MAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + CAM_DBG(CAM_ICP, "received IPE/BPS\n" + "MAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; case HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP: ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; @@ -2265,8 +2340,12 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) complete(&ctx_data->wait_complete); CAM_DBG(CAM_ICP, - "received IPE/BPS UNMAP ACK:ctx_state =%d err_status =%u", - ctx_data->state, ioconfig_ack->err_type); + "received IPE/BPS UNMAP ACK:ctx_state =%d\n" + "failed with err_no = [%u] err_type = [%s]", + ctx_data->state, + ioconfig_ack->err_type, + cam_icp_error_handle_id_to_type( + ioconfig_ack->err_type)); break; default: CAM_ERR(CAM_ICP, "Invalid opcode : %u", -- GitLab From 3aa4b1b147936fc67be028072646c3c833570f03 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Tue, 17 Dec 2019 12:44:44 +0530 Subject: [PATCH 191/410] msm: camera: sync: correcting atomic read operation This change rectifies the reading of atomic variable. CRs-Fixed: 2591537 Change-Id: I13c289bc00a07d5c2289e2e3f13245bbc521d4ee Signed-off-by: Alok Pandey --- drivers/cam_sync/cam_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 33b14f17ceb7..5f205361d1e9 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -38,7 +38,7 @@ static void cam_sync_print_fence_table(void) sync_dev->sync_table[idx].name, sync_dev->sync_table[idx].type, sync_dev->sync_table[idx].state, - sync_dev->sync_table[idx].ref_cnt); + atomic_read(&sync_dev->sync_table[idx].ref_cnt)); spin_unlock_bh(&sync_dev->row_spinlocks[idx]); } } -- GitLab From 5ef070300b766abfca4120b6ebf77efad9b25f33 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 19 Dec 2019 12:55:45 +0530 Subject: [PATCH 192/410] msm: camera: isp: Update unlink handling to avoid race Expire timer after destroying workqueues so that we do not refer to watchdog timer while the link is getting unlinked from session handle. CRs-Fixed: 2585098 Change-Id: Ife2450ae66bd52ec704ac7d593b2daaeb20ba54d Signed-off-by: Vikram Sharma --- drivers/cam_req_mgr/cam_req_mgr_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index e7b5994963fe..5b3c57650719 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3149,12 +3149,13 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) } mutex_lock(&link->lock); - /* Destroy timer of link */ - crm_timer_exit(&link->watchdog); /* Destroy workq of link */ cam_req_mgr_workq_destroy(&link->workq); + /* Destroy timer of link */ + crm_timer_exit(&link->watchdog); + /* Cleanup request tables and unlink devices */ __cam_req_mgr_destroy_link_info(link); -- GitLab From 1e2365e777d224dd02703e3469d812dcc513eabe Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Fri, 20 Dec 2019 12:51:16 +0530 Subject: [PATCH 193/410] msm: camera: csiphy: Add combo phy settings for csiphy v1.2.2.2 As per HPG revision L, there's a difference in the DPHY combo-mode sequence settings between lito v1 and v2. This change adds a separate sequence for lito v2, csiphy version 1.2.2.2. CRs-Fixed: 2591712 Change-Id: Ic535bd2c98f47c33aa689d0e1bfe07d7dac8d9a2 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_soc.c | 22 ++++ .../include/cam_csiphy_1_2_2_hwreg.h | 115 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index c5a8033aaffb..3c1c01337bda 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -9,6 +9,7 @@ #include "include/cam_csiphy_1_0_hwreg.h" #include "include/cam_csiphy_1_2_hwreg.h" #include "include/cam_csiphy_1_2_1_hwreg.h" +#include "include/cam_csiphy_1_2_2_hwreg.h" #include "include/cam_csiphy_2_0_hwreg.h" #define CSIPHY_DIVISOR_16 16 @@ -310,6 +311,27 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->clk_lane = 0; csiphy_dev->ctrl_reg->data_rates_settings_table = &data_rate_delta_table_1_2; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2.2.2")) { + /* settings for lito v2 */ + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_2_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h new file mode 100644 index 000000000000..dd88ba7cca38 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_2_2_HWREG_H_ +#define _CAM_CSIPHY_1_2_2_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_t +csiphy_2ph_v1_2_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_1_2_2_HWREG_H_ */ -- GitLab From bc885682395ea0f3264aee999fcaa94dba940b48 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 16 Dec 2019 13:57:57 +0530 Subject: [PATCH 194/410] msm: camera: isp: Add support for IFE2 Add support for IFE2 hardware in ife hw manager, bus files. CRs-Fixed: 2571273 Change-Id: I6193b70707b15282b8d819e8dda5eb2e5fc4c345 Signed-off-by: Gaurav Jindal --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 10 ++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 15 +++++++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 3 ++- include/uapi/media/cam_isp.h | 1 + 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 483f0622d764..81f4e1f949be 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1470,6 +1470,16 @@ static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx) else if (hw_idx == 4) return CAM_ISP_IFE2_LITE_HW; break; + case CAM_CPAS_TITAN_170_V200: + if (hw_idx == 0) + return CAM_ISP_IFE0_HW; + else if (hw_idx == 1) + return CAM_ISP_IFE1_HW; + else if (hw_idx == 2) + return CAM_ISP_IFE2_HW; + else if (hw_idx == 3) + return CAM_ISP_IFE0_LITE_HW; + break; default: CAM_ERR(CAM_ISP, "Invalid hw_version: 0x%X", hw_version); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 9094f1409a66..90b45905aa8b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -319,6 +319,7 @@ static int cam_vfe_bus_ver2_get_intra_client_mask( case CAM_VFE_BUS_VER2_VFE_CORE_0: switch (dual_slave_core) { case CAM_VFE_BUS_VER2_VFE_CORE_1: + case CAM_VFE_BUS_VER2_VFE_CORE_2: *intra_client_mask = version_based_intra_client_mask; break; default: @@ -331,6 +332,20 @@ static int cam_vfe_bus_ver2_get_intra_client_mask( case CAM_VFE_BUS_VER2_VFE_CORE_1: switch (dual_slave_core) { case CAM_VFE_BUS_VER2_VFE_CORE_0: + case CAM_VFE_BUS_VER2_VFE_CORE_2: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_CORE_2: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER2_VFE_CORE_0: + case CAM_VFE_BUS_VER2_VFE_CORE_1: *intra_client_mask = version_based_intra_client_mask; break; default: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index cac3adf65a93..fc1608315330 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_BUS_VER2_H_ @@ -14,6 +14,7 @@ enum cam_vfe_bus_ver2_vfe_core_id { CAM_VFE_BUS_VER2_VFE_CORE_0, CAM_VFE_BUS_VER2_VFE_CORE_1, + CAM_VFE_BUS_VER2_VFE_CORE_2, CAM_VFE_BUS_VER2_VFE_CORE_MAX, }; diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index e4778cfc9cc2..6d6a16c5ffad 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -111,6 +111,7 @@ #define CAM_ISP_IFE0_LITE_HW 0x4 #define CAM_ISP_IFE1_LITE_HW 0x8 #define CAM_ISP_IFE2_LITE_HW 0x10 +#define CAM_ISP_IFE2_HW 0x100 #define CAM_ISP_PXL_PATH 0x1 #define CAM_ISP_PPP_PATH 0x2 -- GitLab From 94c9fb8c49ffdfcf7e9ed46a5c8b0adfb525de25 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Tue, 10 Dec 2019 18:45:03 +0530 Subject: [PATCH 195/410] msm: camera: isp: Dual VFE sync changes For lagoon, few changes in CSID and IFE to handle the dual vfe sync and halt. For CSID, while handling the halt, external and internal core configuration is changed. For VFE, 3 IFE support is possible with the combinations: 0-1, 1-2, 0-2. This requires changes in dual vfe sync handling. Also, CSID and IFE versions are updated. This commit adds the driver header files for the version and handles the hardware changes in the driver. CRs-Fixed: 2571273 Change-Id: I48fd3319692cc1044beb20c278cc2fe5676cb668 Signed-off-by: Gaurav Jindal --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 13 +- .../isp_hw/ife_csid_hw/cam_ife_csid170_200.h | 368 ++++++++ .../isp_hw/ife_csid_hw/cam_ife_csid17x.c | 12 +- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 163 ++-- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 4 +- .../isp_hw/include/cam_vfe_hw_intf.h | 6 +- .../isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c | 7 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 850 ++++++++++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 4 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 17 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.h | 4 +- 11 files changed, 1368 insertions(+), 80 deletions(-) create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h create mode 100644 drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 81f4e1f949be..f34e9ae69b91 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -1576,6 +1576,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( else vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + vfe_acquire.vfe_in.is_dual = csid_res->is_dual_vfe; break; case CAM_IFE_PIX_PATH_RES_PPP: @@ -1616,12 +1617,20 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( hw_intf = ife_hw_mgr->ife_devices[ csid_res->hw_res[i]->hw_intf->hw_idx]; + if (i == CAM_ISP_HW_SPLIT_LEFT && + ife_src_res->is_dual_vfe) { + vfe_acquire.vfe_in.dual_hw_idx = + ife_ctx->slave_hw_idx; + } /* fill in more acquire information as needed */ /* slave Camif resource, */ if (i == CAM_ISP_HW_SPLIT_RIGHT && - ife_src_res->is_dual_vfe) + ife_src_res->is_dual_vfe) { vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_SLAVE; + vfe_acquire.vfe_in.dual_hw_idx = + ife_ctx->master_hw_idx; + } rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h new file mode 100644 index 000000000000..47cb02492412 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h @@ -0,0 +1,368 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_170_200_H_ +#define _CAM_IFE_CSID_170_200_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_170_200_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .quad_cfa_bin_en_shift_val = 30, + .ccif_violation_en = 1, + .halt_master_sel_en = 1, + .halt_sel_internal_master_val = 3, +}; + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_170_200_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, + .halt_master_sel_en = 1, + .halt_sel_internal_master_val = 3, +}; + + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_170_200_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_170_200_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_170_200_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_170_200_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + .csid_csi2_rx_de_scramble_type3_cfg0_addr = 0x170, + .csid_csi2_rx_de_scramble_type3_cfg1_addr = 0x174, + .csid_csi2_rx_de_scramble_type2_cfg0_addr = 0x178, + .csid_csi2_rx_de_scramble_type2_cfg1_addr = 0x17c, + .csid_csi2_rx_de_scramble_type1_cfg0_addr = 0x180, + .csid_csi2_rx_de_scramble_type1_cfg1_addr = 0x184, + .csid_csi2_rx_de_scramble_type0_cfg0_addr = 0x188, + .csid_csi2_rx_de_scramble_type0_cfg1_addr = 0x18c, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x7, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_170_200_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_170_200_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0xFFFF, + .rdi_irq_mask_all = 0xFFFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_170_200_reg_offset = { + .cmn_reg = &cam_ife_csid_170_200_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_170_200_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_170_200_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_170_200_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_170_200_rdi_0_reg_offset, + &cam_ife_csid_170_200_rdi_1_reg_offset, + &cam_ife_csid_170_200_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_170_200_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_170_200_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c index d88347caa388..d06dafcbcbbc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include #include "cam_ife_csid_core.h" #include "cam_ife_csid170.h" +#include "cam_ife_csid170_200.h" #include "cam_ife_csid175.h" #include "cam_ife_csid175_200.h" #include "cam_ife_csid480.h" @@ -22,6 +23,11 @@ static struct cam_ife_csid_hw_info cam_ife_csid170_hw_info = { .hw_dts_version = CAM_CSID_VERSION_V170, }; +static struct cam_ife_csid_hw_info cam_ife_csid170_200_hw_info = { + .csid_reg = &cam_ife_csid_170_200_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V170, +}; + static struct cam_ife_csid_hw_info cam_ife_csid175_hw_info = { .csid_reg = &cam_ife_csid_175_reg_offset, .hw_dts_version = CAM_CSID_VERSION_V175, @@ -42,6 +48,10 @@ static const struct of_device_id cam_ife_csid17x_dt_match[] = { .compatible = "qcom,csid170", .data = &cam_ife_csid170_hw_info, }, + { + .compatible = "qcom,csid170_200", + .data = &cam_ife_csid170_200_hw_info, + }, { .compatible = "qcom,csid175", .data = &cam_ife_csid175_hw_info, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 2c58913ef1f3..dfacff2db25b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -763,6 +763,7 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: + case CAM_CPAS_TITAN_170_V200: if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && csid_hw->hw_intf->hw_idx != 2) { rc = -EINVAL; @@ -770,18 +771,20 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, } break; case CAM_CPAS_TITAN_480_V100: - if (cid_reserv->in_port->cust_node == 1) { - if (cid_reserv->in_port->usage_type == 1) { - CAM_ERR(CAM_ISP, "Dual IFE is not supported"); - rc = -EINVAL; - goto end; - } - if (csid_hw->hw_intf->hw_idx != 0) { - CAM_DBG(CAM_ISP, "CSID%d not eligible", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - goto end; - } + + if (cid_reserv->in_port->cust_node != 1) + break; + + if (cid_reserv->in_port->usage_type == 1) { + CAM_ERR(CAM_ISP, "Dual IFE is not supported"); + rc = -EINVAL; + goto end; + } + if (csid_hw->hw_intf->hw_idx != 0) { + CAM_DBG(CAM_ISP, "CSID%d not eligible", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; } break; default: @@ -796,28 +799,31 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, goto end; } - if (cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { - if (csid_hw->csi2_rx_cfg.lane_cfg != - cid_reserv->in_port->lane_cfg || - csid_hw->csi2_rx_cfg.lane_type != - cid_reserv->in_port->lane_type || - csid_hw->csi2_rx_cfg.lane_num != - cid_reserv->in_port->lane_num) { - rc = -EINVAL; - goto end; - } - } else { - if (csid_hw->tpg_cfg.in_format != - cid_reserv->in_port->format || - csid_hw->tpg_cfg.width != - cid_reserv->in_port->left_width || - csid_hw->tpg_cfg.height != - cid_reserv->in_port->height || - csid_hw->tpg_cfg.test_pattern != - cid_reserv->in_port->test_pattern) { - rc = -EINVAL; - goto end; - } + if ((cid_reserv->in_port->res_type != + CAM_ISP_IFE_IN_RES_TPG) && + (csid_hw->csi2_rx_cfg.lane_cfg != + cid_reserv->in_port->lane_cfg || + csid_hw->csi2_rx_cfg.lane_type != + cid_reserv->in_port->lane_type || + csid_hw->csi2_rx_cfg.lane_num != + cid_reserv->in_port->lane_num)) { + + rc = -EINVAL; + goto end; + } + if ((cid_reserv->in_port->res_type == + CAM_ISP_IFE_IN_RES_TPG) && + (csid_hw->tpg_cfg.in_format != + cid_reserv->in_port->format || + csid_hw->tpg_cfg.width != + cid_reserv->in_port->left_width || + csid_hw->tpg_cfg.height != + cid_reserv->in_port->height || + csid_hw->tpg_cfg.test_pattern != + cid_reserv->in_port->test_pattern)) { + + rc = -EINVAL; + goto end; } } @@ -902,39 +908,45 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->csi2_rx_cfg.lane_num = cid_reserv->in_port->lane_num; - if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG) { - csid_hw->csi2_rx_cfg.phy_sel = 0; - if (cid_reserv->in_port->format > - CAM_FORMAT_MIPI_RAW_16) { - CAM_ERR(CAM_ISP, " Wrong TPG format"); - rc = -EINVAL; - goto end; - } - csid_hw->tpg_cfg.in_format = - cid_reserv->in_port->format; - csid_hw->tpg_cfg.usage_type = - cid_reserv->in_port->usage_type; - if (cid_reserv->in_port->usage_type) - csid_hw->tpg_cfg.width = - (cid_reserv->in_port->right_stop + 1); - else - csid_hw->tpg_cfg.width = - cid_reserv->in_port->left_width; - - csid_hw->tpg_cfg.height = cid_reserv->in_port->height; - csid_hw->tpg_cfg.test_pattern = - cid_reserv->in_port->test_pattern; - - CAM_DBG(CAM_ISP, "CSID:%d TPG width:%d height:%d", - csid_hw->hw_intf->hw_idx, - csid_hw->tpg_cfg.width, - csid_hw->tpg_cfg.height); - - cid_data->tpg_set = 1; - } else { + if (cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { csid_hw->csi2_rx_cfg.phy_sel = (cid_reserv->in_port->res_type & 0xFF) - 1; + csid_hw->csi2_reserve_cnt++; + CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired", + csid_hw->hw_intf->hw_idx, + cid_reserv->node_res->res_id); + goto end; } + + /* Below code is executed only for TPG in_res type */ + csid_hw->csi2_rx_cfg.phy_sel = 0; + if (cid_reserv->in_port->format > + CAM_FORMAT_MIPI_RAW_16) { + CAM_ERR(CAM_ISP, " Wrong TPG format"); + rc = -EINVAL; + goto end; + } + csid_hw->tpg_cfg.in_format = + cid_reserv->in_port->format; + csid_hw->tpg_cfg.usage_type = + cid_reserv->in_port->usage_type; + if (cid_reserv->in_port->usage_type) + csid_hw->tpg_cfg.width = + (cid_reserv->in_port->right_stop + 1); + else + csid_hw->tpg_cfg.width = + cid_reserv->in_port->left_width; + + csid_hw->tpg_cfg.height = cid_reserv->in_port->height; + csid_hw->tpg_cfg.test_pattern = + cid_reserv->in_port->test_pattern; + + CAM_DBG(CAM_ISP, "CSID:%d TPG width:%d height:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->tpg_cfg.width, + csid_hw->tpg_cfg.height); + + cid_data->tpg_set = 1; } csid_hw->csi2_reserve_cnt++; @@ -1971,17 +1983,26 @@ static int cam_ife_csid_enable_pxl_path( CAM_DBG(CAM_ISP, "Enable %s path", (is_ipp) ? "IPP" : "PPP"); + /* Set master or slave path */ - if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) { /*Set halt mode as master */ - val = CSID_HALT_MODE_MASTER << 2; - else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + if (pxl_reg->halt_master_sel_en) + val = pxl_reg->halt_sel_internal_master_val << 4 | + CSID_HALT_MODE_MASTER << 2; + else + val = CSID_HALT_MODE_MASTER << 2; + } else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { /*Set halt mode as slave and set master idx */ - val = path_data->master_idx << 4 | CSID_HALT_MODE_SLAVE << 2; - else + if (pxl_reg->halt_master_sel_en) + val = CSID_HALT_MODE_SLAVE << 2; + else + val = path_data->master_idx << 4 | + CSID_HALT_MODE_SLAVE << 2; + } else { /* Default is internal halt mode */ val = 0; - + } /* * Resume at frame boundary if Master or No Sync. * Slave will get resume command from Master. diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 4c2ac18089af..c7a648daff86 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_HW_H_ @@ -139,6 +139,8 @@ struct cam_ife_csid_pxl_reg_offset { uint32_t quad_cfa_bin_en_shift_val; uint32_t ccif_violation_en; uint32_t overflow_ctrl_en; + uint32_t halt_master_sel_en; + uint32_t halt_sel_internal_master_val; }; struct cam_ife_csid_rdi_reg_offset { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index a1d1c6a60881..877066e13a1c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_HW_INTF_H_ @@ -137,14 +137,18 @@ struct cam_vfe_hw_vfe_out_acquire_args { * is successful * @res_id: Resource ID of resource to acquire if specific, * else CAM_ISP_HW_VFE_IN_MAX + * @dual_hw_idx: Slave core for this master core if dual vfe case * @cdm_ops: CDM operations * @sync_mode: In case of Dual VFE, this is Master or Slave. * (Default is Master in case of Single VFE) * @in_port: Input port details to acquire + * @is_dual: flag to indicate if dual vfe case */ struct cam_vfe_hw_vfe_in_acquire_args { struct cam_isp_resource_node *rsrc_node; uint32_t res_id; + uint32_t dual_hw_idx; + uint32_t is_dual; void *cdm_ops; enum cam_isp_hw_sync_mode sync_mode; struct cam_isp_in_port_generic_info *in_port; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c index 5336352a4797..9972e2f64a7c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include #include "cam_vfe170.h" +#include "cam_vfe170_150.h" #include "cam_vfe175.h" #include "cam_vfe175_130.h" #include "cam_vfe480.h" @@ -19,6 +20,10 @@ static const struct of_device_id cam_vfe_dt_match[] = { .compatible = "qcom,vfe170", .data = &cam_vfe170_hw_info, }, + { + .compatible = "qcom,vfe170_150", + .data = &cam_vfe170_150_hw_info, + }, { .compatible = "qcom,vfe175", .data = &cam_vfe175_hw_info, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h new file mode 100644 index 000000000000..df5cc3594b98 --- /dev/null +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -0,0 +1,850 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE170_150_H_ +#define _CAM_VFE170_150_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe170_150_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe170_150_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe170_150_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe170_150_camif_reg = { + .dual_vfe_sync = 0x00000100, + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_170_150_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0x0FFF7E80, + .enable_diagnostic_hw = 0x1, + .dual_vfe_sync_mask = 0x3, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_170_150_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_170_150_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_170_150_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_150_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe170_150_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_170_150_reg, + &stats_170_150_reg, + &color_170_150_reg, + &zoom_170_150_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe170_150_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_150_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_150_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_150_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe170_150_top_hw_info = { + .common_reg = &vfe170_150_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe170_150_top_common_reg, + .camif_reg = &vfe170_150_camif_reg, + .reg_data = &vfe_170_150_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = NULL, + .camif_lite_reg = NULL, + .reg_data = NULL, + }, + .rdi_hw_info = { + .common_reg = &vfe170_150_top_common_reg, + .rdi_reg = &vfe170_150_rdi_reg, + .reg_data = { + &vfe_170_150_rdi_0_data, + &vfe_170_150_rdi_1_data, + &vfe_170_150_rdi_2_data, + NULL, + }, + }, + .num_mux = 4, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe170_150_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client + vfe_170_150_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client + vfe_170_150_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe170_150_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe170_150_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + .debug_status_cfg = 0x0000226C, + .debug_status_0 = 0x00002270, + }, + .num_client = 20, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = + &vfe_170_150_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = + &vfe_170_150_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 18, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe170_150_hw_info = { + .irq_reg_info = &vfe170_150_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe170_150_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe170_150_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe170_150_camif_reg, + + .camif_lite_version = 0, + .camif_lite_reg = NULL, + +}; + +#endif /* _CAM_vfe170_150_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 90b45905aa8b..92f0e700a485 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -2591,6 +2591,7 @@ static void cam_vfe_bus_update_ubwc_meta_addr( case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: + case CAM_CPAS_TITAN_170_V200: ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *)regs; CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, @@ -2808,6 +2809,7 @@ static int cam_vfe_bus_update_ubwc_regs( case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: + case CAM_CPAS_TITAN_170_V200: rc = cam_vfe_bus_update_ubwc_legacy_regs( wm_data, camera_hw_version, reg_val_pair, i, j); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index c776888c9871..23cf5d1642f4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -48,6 +48,8 @@ struct cam_vfe_mux_camif_data { bool enable_sof_irq_debug; uint32_t irq_debug_cnt; uint32_t camif_debug; + uint32_t dual_hw_idx; + uint32_t is_dual; }; static int cam_vfe_camif_get_evt_payload( @@ -256,6 +258,11 @@ int cam_vfe_camif_ver2_acquire_resource( camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; camif_data->event_cb = acquire_data->event_cb; camif_data->priv = acquire_data->priv; + camif_data->is_dual = acquire_data->vfe_in.is_dual; + + if (acquire_data->vfe_in.is_dual) + camif_data->dual_hw_idx = + acquire_data->vfe_in.dual_hw_idx; CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", camif_res->hw_intf->hw_idx, @@ -328,6 +335,7 @@ static int cam_vfe_camif_resource_start( int rc = 0; uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t dual_vfe_sync_val; struct cam_vfe_soc_private *soc_private; if (!camif_res) { @@ -388,6 +396,7 @@ static int cam_vfe_camif_resource_start( case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: + case CAM_CPAS_TITAN_170_V200: cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, rsrc_data->mem_base + rsrc_data->camif_reg->epoch_irq); @@ -412,6 +421,12 @@ static int cam_vfe_camif_resource_start( break; } + if (rsrc_data->is_dual && rsrc_data->reg_data->dual_vfe_sync_mask) { + dual_vfe_sync_val = (rsrc_data->dual_hw_idx & + rsrc_data->reg_data->dual_vfe_sync_mask) + 1; + cam_io_w_mb(dual_vfe_sync_val, rsrc_data->mem_base + + rsrc_data->camif_reg->dual_vfe_sync); + } camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; /* Reg Update */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h index f071a0627bbc..26522594b97b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_CAMIF_VER2_H_ @@ -22,6 +22,7 @@ struct cam_vfe_camif_ver2_reg { uint32_t reg_update_cmd; uint32_t vfe_diag_config; uint32_t vfe_diag_sensor_status; + uint32_t dual_vfe_sync; }; struct cam_vfe_camif_reg_data { @@ -62,6 +63,7 @@ struct cam_vfe_camif_reg_data { uint32_t subscribe_irq_mask1; uint32_t enable_diagnostic_hw; + uint32_t dual_vfe_sync_mask; }; struct cam_vfe_camif_ver2_hw_info { -- GitLab From e7820624efbefe56b0eebdb7b9f649adc5e8cb69 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Mon, 23 Dec 2019 11:42:09 +0800 Subject: [PATCH 196/410] msm: camera: sensor: Fix an operator error - Fix an operator error in cam_sensor_flush_request CRs-Fixed: 2591694 Change-Id: I39a8b29f83db55d2a930dd5ccd2b765517e2c1d6 Signed-off-by: Depeng Shao --- drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 6902122b3f66..37f62fe95246 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -1319,8 +1319,8 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) } mutex_lock(&(s_ctrl->cam_sensor_mutex)); - if (s_ctrl->sensor_state != CAM_SENSOR_START || - s_ctrl->sensor_state != CAM_SENSOR_CONFIG) { + if ((s_ctrl->sensor_state != CAM_SENSOR_START) && + (s_ctrl->sensor_state != CAM_SENSOR_CONFIG)) { mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return rc; } -- GitLab From 374ee8b24d688bed0e9caf765a73ca910c35bfda Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 6 Jan 2020 11:41:06 +0530 Subject: [PATCH 197/410] msm: camera: isp: Get packet opcode from hw manager While processing the user space submitted isp packet, isp context need to know the packet opcode. Get the opcode from the hw manager than the direct accessing the opcode from packet. Ife umd sends different opcodes then tfe umd. Both ife and tfe kernel packet opcodes are same. So hw manager can consume this differences. CRs-Fixed: 2585713 Change-Id: I54813af233cd8bfa640f2688c1334510a5b85f1c Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/cam_isp_context.c | 23 +++++++++++++++++-- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 12 ++++++++++ .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 7 +++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 6433389c4ba4..a789b0ceac99 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -2986,6 +2986,9 @@ static int __cam_isp_ctx_config_dev_in_top_state( struct cam_req_mgr_add_request add_req; struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + uint32_t packet_opcode = 0; CAM_DBG(CAM_ISP, "get free request object......"); @@ -3034,7 +3037,23 @@ static int __cam_isp_ctx_config_dev_in_top_state( CAM_DBG(CAM_ISP, "Packet size 0x%x", packet->header.size); CAM_DBG(CAM_ISP, "packet op %d", packet->header.op_code); - if ((((packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_UPDATE_DEV) + /* Query the packet opcode */ + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_GET_PACKET_OPCODE; + isp_hw_cmd_args.cmd_data = (void *)packet; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_req; + } + + packet_opcode = isp_hw_cmd_args.u.packet_op_code; + CAM_DBG(CAM_ISP, "packet op %d", packet_opcode); + + if ((packet_opcode == CAM_ISP_PACKET_UPDATE_DEV) && (packet->header.request_id <= ctx->last_flush_req)) { CAM_INFO(CAM_ISP, "request %lld has been flushed, reject packet", diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index f34e9ae69b91..9064c4f81551 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -5837,6 +5837,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) struct cam_ife_hw_mgr_ctx *ctx = (struct cam_ife_hw_mgr_ctx *) hw_cmd_args->ctxt_to_hw_map; struct cam_isp_hw_cmd_args *isp_hw_cmd_args = NULL; + struct cam_packet *packet; if (!hw_mgr_priv || !cmd_args) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -5877,6 +5878,17 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) else isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX; break; + case CAM_ISP_HW_MGR_GET_PACKET_OPCODE: + packet = (struct cam_packet *) + isp_hw_cmd_args->cmd_data; + if (((packet->header.op_code + 1) & 0xF) == + CAM_ISP_PACKET_INIT_DEV) + isp_hw_cmd_args->u.packet_op_code = + CAM_ISP_PACKET_INIT_DEV; + else + isp_hw_cmd_args->u.packet_op_code = + CAM_ISP_PACKET_UPDATE_DEV; + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 6d5d0fd61c88..2d68f5271624 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_MGR_INTF_H_ @@ -222,6 +222,7 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_RESUME_HW, CAM_ISP_HW_MGR_CMD_SOF_DEBUG, CAM_ISP_HW_MGR_CMD_CTX_TYPE, + CAM_ISP_HW_MGR_GET_PACKET_OPCODE, CAM_ISP_HW_MGR_CMD_MAX, }; @@ -235,14 +236,18 @@ enum cam_isp_ctx_type { * struct cam_isp_hw_cmd_args - Payload for hw manager command * * @cmd_type HW command type + * @cmd_data command data * @sof_irq_enable To debug if SOF irq is enabled * @ctx_type RDI_ONLY, PIX and RDI, or FS2 + * @packet_op_code packet opcode */ struct cam_isp_hw_cmd_args { uint32_t cmd_type; + void *cmd_data; union { uint32_t sof_irq_enable; uint32_t ctx_type; + uint32_t packet_op_code; } u; }; -- GitLab From aeda4ac40d44173a7b442d9b1d4a19614115bb5d Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 7 Nov 2019 18:54:27 -0800 Subject: [PATCH 198/410] msm: camera: icp: Enable hang dump on failure In case user does not set any dump lvl, KMD will set to dump on failure as default. CRs-Fixed: 2579908 Change-Id: I036e91f5daceedf575815e7569c0e90c04f8de52 Signed-off-by: Karthik Anantha Ram --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 f32a95e05d66..5ebc96b94f5f 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -1890,6 +1890,8 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) goto err; } + /* Set default hang dump lvl */ + icp_hw_mgr.a5_fw_dump_lvl = HFI_FW_DUMP_ON_FAILURE; return rc; err: debugfs_remove_recursive(icp_hw_mgr.dentry); -- GitLab From 2269448c7403a64bf3cbefeae387206274ba69e2 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 8 Nov 2019 17:45:22 -0800 Subject: [PATCH 199/410] msm: camera: icp: Dump patching info in case of page faults Currently as part of the page fault handler we only dump the io_bufs. This change dumps all the patched addresses for this request as well. CRs-Fixed: 2579908 Change-Id: If5deec0ad3a8aec82824ef55366084c31a037515 Signed-off-by: Karthik Anantha Ram --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 + drivers/cam_utils/cam_packet_util.c | 55 ++++++++++++++++++- drivers/cam_utils/cam_packet_util.h | 16 +++++- 3 files changed, 71 insertions(+), 2 deletions(-) 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 5ebc96b94f5f..14e2d4e2c48c 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 @@ -4742,6 +4742,8 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, } } + cam_packet_dump_patch_info(packet, icp_hw_mgr.iommu_hdl, + icp_hw_mgr.iommu_sec_hdl); } static int cam_icp_mgr_config_stream_settings( diff --git a/drivers/cam_utils/cam_packet_util.c b/drivers/cam_utils/cam_packet_util.c index 4eadee666219..1569d5dbafa6 100644 --- a/drivers/cam_utils/cam_packet_util.c +++ b/drivers/cam_utils/cam_packet_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -154,6 +154,59 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, return rc; } +void cam_packet_dump_patch_info(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl) +{ + struct cam_patch_desc *patch_desc = NULL; + dma_addr_t iova_addr; + size_t dst_buf_len; + size_t src_buf_size; + int i, rc = 0; + int32_t hdl; + uintptr_t cpu_addr = 0; + uint32_t *dst_cpu_addr; + uint64_t value = 0; + + patch_desc = (struct cam_patch_desc *) + ((uint32_t *) &packet->payload + + packet->patch_offset/4); + + for (i = 0; i < packet->num_patches; i++) { + hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ? + sec_mmu_hdl : iommu_hdl; + rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, + hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, + "unable to get src buf address for hdl 0x%x", + hdl); + return; + } + + rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, + &cpu_addr, &dst_buf_len); + if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { + CAM_ERR(CAM_UTIL, "unable to get dst buf address"); + return; + } + + dst_cpu_addr = (uint32_t *)cpu_addr; + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + + patch_desc[i].dst_offset); + value = *((uint64_t *)dst_cpu_addr); + CAM_INFO(CAM_UTIL, + "i = %d src_buf 0x%llx src_hdl 0x%x src_buf_with_offset 0x%llx size 0x%llx dst %p dst_offset %u dst_hdl 0x%x value 0x%llx", + i, iova_addr, patch_desc[i].src_buf_hdl, + (iova_addr + patch_desc[i].src_offset), + src_buf_size, dst_cpu_addr, + patch_desc[i].dst_offset, + patch_desc[i].dst_buf_hdl, value); + + if (!(*dst_cpu_addr)) + CAM_ERR(CAM_ICP, "Null at dst addr %p", dst_cpu_addr); + } +} + int cam_packet_util_process_patches(struct cam_packet *packet, int32_t iommu_hdl, int32_t sec_mmu_hdl) { diff --git a/drivers/cam_utils/cam_packet_util.h b/drivers/cam_utils/cam_packet_util.h index d5fc8f70ec07..62866a962cc6 100644 --- a/drivers/cam_utils/cam_packet_util.h +++ b/drivers/cam_utils/cam_packet_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_PACKET_UTIL_H_ @@ -86,6 +86,20 @@ int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc); int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, struct cam_kmd_buf_info *kmd_buf_info); +/** + * cam_packet_dump_patch_info() + * + * @brief: Dump patch info in case of page fault + * + * @packet: Input packet containing Command Buffers and Patches + * @iommu_hdl: IOMMU handle of the HW Device that received the packet + * @sec_iommu_hdl: Secure IOMMU handle of the HW Device that + * received the packet + * + */ +void cam_packet_dump_patch_info(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl); + /** * cam_packet_util_process_patches() * -- GitLab From fdb064cef0a53634f633c5bc9879151291b5bbb0 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 9 Sep 2019 23:05:15 -0700 Subject: [PATCH 200/410] msm: camera: isp: Add check for cid acquire This change adds a check to validate the cid being acquired, when custom HW is in the pipeline. CRs-Fixed: 2524308 Change-Id: I32913e74bc946a4333f77f5e10757c4bd51eab67 Signed-off-by: Karthik Anantha Ram --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index dfacff2db25b..760334ef5f45 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -771,20 +771,40 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, } break; case CAM_CPAS_TITAN_480_V100: + /* + * Assigning existing two IFEs for custom in KONA, + * this needs to be addressed accordingly for + * upcoming targets + */ + if (cid_reserv->in_port->cust_node) { + if (cid_reserv->in_port->usage_type == + CAM_ISP_RES_USAGE_DUAL) { + CAM_ERR(CAM_ISP, + "Dual IFE is not supported for cust_node %u", + cid_reserv->in_port->cust_node); + rc = -EINVAL; + goto end; + } - if (cid_reserv->in_port->cust_node != 1) - break; + if (cid_reserv->in_port->cust_node == + CAM_ISP_ACQ_CUSTOM_PRIMARY) { + if (csid_hw->hw_intf->hw_idx != 0) { + CAM_ERR(CAM_ISP, "CSID%d not eligible", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + } - if (cid_reserv->in_port->usage_type == 1) { - CAM_ERR(CAM_ISP, "Dual IFE is not supported"); - rc = -EINVAL; - goto end; - } - if (csid_hw->hw_intf->hw_idx != 0) { - CAM_DBG(CAM_ISP, "CSID%d not eligible", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - goto end; + if (cid_reserv->in_port->cust_node == + CAM_ISP_ACQ_CUSTOM_SECONDARY) { + if (csid_hw->hw_intf->hw_idx != 1) { + CAM_ERR(CAM_ISP, "CSID%d not eligible", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + } } break; default: @@ -831,7 +851,7 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, case CAM_IFE_PIX_PATH_RES_IPP: if (csid_hw->ipp_res.res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { - CAM_DBG(CAM_ISP, + CAM_ERR(CAM_ISP, "CSID:%d IPP resource not available", csid_hw->hw_intf->hw_idx); rc = -EINVAL; -- GitLab From 6edca313244f326daa89e1a19f2962468a8757dc Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 9 Sep 2019 22:54:06 -0700 Subject: [PATCH 201/410] msm: camera: isp: Add support to obtain frame index This change captures the frame index as part of the IFE top register space at every epoch event. The index is then notified to userspace as part of shutter notification. CRs-Fixed: 2524308 Change-Id: Iac510c452f9ceda86e9f7d69528f22f81e614974 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/cam_isp_context.c | 44 +++++++++++++--- drivers/cam_isp/cam_isp_context.h | 47 +++++++++-------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 52 +++++++++++-------- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 3 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 4 +- .../isp_hw/include/cam_vfe_hw_intf.h | 4 ++ .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 5 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 28 +++++++++- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.h | 3 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h | 4 +- 10 files changed, 135 insertions(+), 59 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index a789b0ceac99..1ed49e8255ab 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -425,6 +425,7 @@ static void __cam_isp_ctx_send_sof_boot_timestamp( req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp; req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.frame_msg.sof_status = sof_event_status; + req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta; CAM_DBG(CAM_ISP, "request id:%lld frame number:%lld boot time stamp:0x%llx", @@ -452,6 +453,7 @@ static void __cam_isp_ctx_send_sof_timestamp( req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val; req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.frame_msg.sof_status = sof_event_status; + req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta; CAM_DBG(CAM_ISP, "request id:%lld frame number:%lld SOF time stamp:0x%llx", @@ -800,11 +802,20 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( struct cam_isp_context *ctx_isp, void *evt_data) { int rc = 0; + uint64_t request_id = 0; struct cam_req_mgr_trigger_notify notify; struct cam_context *ctx = ctx_isp->base; struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; - uint64_t request_id = 0; + struct cam_isp_hw_epoch_event_data *epoch_done_event_data = + (struct cam_isp_hw_epoch_event_data *)evt_data; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "invalid event data"); + return -EINVAL; + } + + ctx_isp->frame_id_meta = epoch_done_event_data->frame_id_meta; /* * notify reqmgr with sof signal. Note, due to scheduling delay @@ -1019,11 +1030,19 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, void *evt_data) { - struct cam_ctx_request *req; - struct cam_isp_ctx_req *req_isp; - struct cam_context *ctx = ctx_isp->base; - uint64_t request_id = 0; + uint64_t request_id = 0; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_epoch_event_data *epoch_done_event_data = + (struct cam_isp_hw_epoch_event_data *)evt_data; + if (!evt_data) { + CAM_ERR(CAM_ISP, "invalid event data"); + return -EINVAL; + } + + ctx_isp->frame_id_meta = epoch_done_event_data->frame_id_meta; if (list_empty(&ctx->wait_req_list)) { /* * If no wait req in epoch, this is an error case. @@ -1180,10 +1199,19 @@ static int __cam_isp_ctx_buf_done_in_bubble( static int __cam_isp_ctx_epoch_in_bubble_applied( struct cam_isp_context *ctx_isp, void *evt_data) { - struct cam_ctx_request *req; - struct cam_isp_ctx_req *req_isp; - struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_epoch_event_data *epoch_done_event_data = + (struct cam_isp_hw_epoch_event_data *)evt_data; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "invalid event data"); + return -EINVAL; + } + + ctx_isp->frame_id_meta = epoch_done_event_data->frame_id_meta; /* * This means we missed the reg upd ack. So we need to diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 503e46526dee..4b3c45b57c94 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_CONTEXT_H_ @@ -165,6 +165,8 @@ struct cam_isp_context_req_id_info { * * @base: Common context object pointer * @frame_id: Frame id tracking for the isp context + * @frame_id_meta: Frame id read every epoch for the ctx + * meta from the sensor * @substate_actiavted: Current substate for the activated state. * @process_bubble: Atomic variable to check if ctx is still * processing bubble. @@ -193,27 +195,28 @@ struct cam_isp_context_req_id_info { * */ struct cam_isp_context { - struct cam_context *base; - - int64_t frame_id; - enum cam_isp_ctx_activated_substate substate_activated; - atomic_t process_bubble; - uint32_t bubble_frame_cnt; - struct cam_ctx_ops *substate_machine; - struct cam_isp_ctx_irq_ops *substate_machine_irq; - - struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; - struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; - - void *hw_ctx; - uint64_t sof_timestamp_val; - uint64_t boot_timestamp; - int32_t active_req_cnt; - int64_t reported_req_id; - uint32_t subscribe_event; - int64_t last_applied_req_id; - atomic64_t state_monitor_head; - struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ + struct cam_context *base; + + int64_t frame_id; + uint32_t frame_id_meta; + uint32_t substate_activated; + atomic_t process_bubble; + uint32_t bubble_frame_cnt; + struct cam_ctx_ops *substate_machine; + struct cam_isp_ctx_irq_ops *substate_machine_irq; + + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; + + void *hw_ctx; + uint64_t sof_timestamp_val; + uint64_t boot_timestamp; + int32_t active_req_cnt; + int64_t reported_req_id; + uint32_t subscribe_event; + int64_t last_applied_req_id; + atomic64_t state_monitor_head; + struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; struct cam_isp_context_req_id_info req_info; bool rdi_only_context; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 9064c4f81551..fba3698baad8 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -4826,29 +4826,36 @@ static int cam_isp_blob_core_cfg_update( list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { clk_rate = 0; - if (!hw_mgr_res->hw_res[i] || - hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + if (!hw_mgr_res->hw_res[i]) continue; - hw_intf = hw_mgr_res->hw_res[i]->hw_intf; - if (hw_intf && hw_intf->hw_ops.process_cmd) { - vfe_core_config.node_res = - hw_mgr_res->hw_res[i]; - - memcpy(&vfe_core_config.core_config, - core_config, - sizeof(struct cam_isp_core_config)); - - rc = hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_ISP_HW_CMD_CORE_CONFIG, - &vfe_core_config, - sizeof( - struct cam_vfe_core_config_args)); - if (rc) - CAM_ERR(CAM_ISP, "Core cfg parse fail"); - } else { - CAM_WARN(CAM_ISP, "NULL hw_intf!"); + if ((hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_CAMIF) || + (hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_PDLIB)) { + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + vfe_core_config.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&vfe_core_config.core_config, + core_config, + sizeof( + struct cam_isp_core_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CORE_CONFIG, + &vfe_core_config, + sizeof( + struct cam_vfe_core_config_args) + ); + if (rc) + CAM_ERR(CAM_ISP, + "Core cfg parse fail"); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } } } } @@ -6429,6 +6436,9 @@ static int cam_ife_hw_mgr_handle_hw_epoch( if (!rc) { if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) break; + + epoch_done_event_data.frame_id_meta = + event_info->th_reg_val; ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); } diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 2d68f5271624..1214d908ec06 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -168,10 +168,11 @@ struct cam_isp_hw_reg_update_event_data { * struct cam_isp_hw_epoch_event_data - Event payload for CAM_HW_EVENT_EPOCH * * @timestamp: Time stamp for the epoch event - * + * @frame_id_meta: Frame id value corresponding to this frame */ struct cam_isp_hw_epoch_event_data { uint64_t timestamp; + uint32_t frame_id_meta; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 7ac79feb2a9f..35b9e943fe22 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_H_ @@ -165,6 +165,7 @@ struct cam_isp_resource_node { * @res_id: Unique resource ID * @hw_idx: IFE hw index * @err_type: Error type if any + * @th_reg_val: Any critical register value captured during th * */ struct cam_isp_hw_event_info { @@ -172,6 +173,7 @@ struct cam_isp_hw_event_info { uint32_t res_id; uint32_t hw_idx; uint32_t err_type; + uint32_t th_reg_val; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index 877066e13a1c..21efc83b551e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -263,11 +263,15 @@ struct cam_vfe_bw_control_args { * @list: list_head node for the payload * @irq_reg_val: IRQ and Error register values, read when IRQ was * handled + * @th_reg_val: Value of any critical register that needs to be + * read at th to avoid any latencies in bh processing + * * @ts: Timestamp */ struct cam_vfe_top_irq_evt_payload { struct list_head list; uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t th_reg_val; struct cam_isp_timestamp ts; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index ae65df7c1126..0cd59de02f46 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ @@ -77,6 +77,7 @@ static struct cam_vfe_camif_ver3_reg_data vfe_480_camif_reg_data = { .error_irq_mask0 = 0x82000200, .error_irq_mask2 = 0x30301F80, .subscribe_irq_mask1 = 0x00000007, + .frame_id_irq_mask = 0x400, .enable_diagnostic_hw = 0x1, .pp_camif_cfg_en_shift = 0, .pp_camif_cfg_ife_out_en_shift = 8, @@ -101,7 +102,7 @@ static struct cam_vfe_top_ver3_reg_offset_common vfe480_top_common_reg = { .ahb_cgc_ovd = 0x00000024, .noc_cgc_ovd = 0x00000028, .trigger_cdm_events = 0x00000090, - .sbi_frame_idx = 0x00000110, + .custom_frame_idx = 0x00000110, .dsp_status = 0x0000007C, .diag_config = 0x00000064, .diag_sensor_status_0 = 0x00000068, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 12cdcb19f2c0..ac03b3a132dc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include @@ -502,6 +502,9 @@ static int cam_vfe_camif_ver3_resource_start( irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = rsrc_data->reg_data->sof_irq_mask; + if (rsrc_data->cam_common_cfg.input_mux_sel_pp & 0x3) + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->frame_id_irq_mask; if (!rsrc_data->sof_irq_handle) { rsrc_data->sof_irq_handle = cam_irq_controller_subscribe_irq( @@ -1186,10 +1189,21 @@ static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, } cam_isp_hw_get_timestamp(&evt_payload->ts); + evt_payload->th_reg_val = 0; for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + /* Read frame_id meta at every epoch if custom hw is enabled */ + if (evt_payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->epoch0_irq_mask) { + if ((camif_priv->common_reg->custom_frame_idx) && + (camif_priv->cam_common_cfg.input_mux_sel_pp & 0x3)) + evt_payload->th_reg_val = cam_io_r_mb( + camif_priv->mem_base + + camif_priv->common_reg->custom_frame_idx); + } + th_payload->evt_payload_priv = evt_payload; CAM_DBG(CAM_ISP, "Exit"); @@ -1205,6 +1219,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; + uint32_t val = 0; int i = 0; if (!handler_priv || !evt_payload_priv) { @@ -1224,6 +1239,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, evt_info.hw_idx = camif_node->hw_intf->hw_idx; evt_info.res_id = camif_node->res_id; evt_info.res_type = camif_node->res_type; + evt_info.th_reg_val = 0; if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->sof_irq_mask) { @@ -1254,6 +1270,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); + evt_info.th_reg_val = payload->th_reg_val; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1289,6 +1306,15 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, cam_vfe_camif_ver3_reg_dump(camif_node); } + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_priv->reg_data->frame_id_irq_mask) { + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->custom_frame_idx); + CAM_DBG(CAM_ISP, + "VFE:%d Frame id change to: %u", evt_info.hw_idx, + val); + } + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h index 40d8e40ae852..303a9e5b0a6a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_CAMIF_VER3_H_ @@ -52,6 +52,7 @@ struct cam_vfe_camif_ver3_reg_data { uint32_t error_irq_mask0; uint32_t error_irq_mask2; uint32_t subscribe_irq_mask1; + uint32_t frame_id_irq_mask; uint32_t enable_diagnostic_hw; uint32_t pp_camif_cfg_en_shift; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h index 14c96097cdf6..4a24ba6ddf76 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_TOP_VER3_H_ @@ -41,7 +41,7 @@ struct cam_vfe_top_ver3_reg_offset_common { uint32_t reg_update_cmd; uint32_t trigger_cdm_events; uint32_t violation_status; - uint32_t sbi_frame_idx; + uint32_t custom_frame_idx; uint32_t dsp_status; uint32_t diag_config; uint32_t diag_sensor_status_0; -- GitLab From 1c478e75f0dc7eebc3f97064c5a626590ff6a16a Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 19 Nov 2019 13:40:02 -0800 Subject: [PATCH 202/410] msm: camera: reqmgr: Add uapi for new v4l2 event type Add event type to be notify custom events from the custom driver. Also adds a new custom message definition. CRs-Fixed: 2569823 Change-Id: I2ff701e79949ac3a467cbfe0c704065dbf0dc759 Signed-off-by: Karthik Anantha Ram --- include/uapi/media/cam_req_mgr.h | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 5bab420a7b02..88e5d3d4f698 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_LINUX_CAM_REQ_MGR_H @@ -51,6 +51,7 @@ #define V4L_EVENT_CAM_REQ_MGR_SOF 0 #define V4L_EVENT_CAM_REQ_MGR_ERROR 1 #define V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS 2 +#define V4L_EVENT_CAM_REQ_MGR_CUSTOM_EVT 3 /* SOF Event status */ #define CAM_REQ_MGR_SOF_EVENT_SUCCESS 0 @@ -459,11 +460,29 @@ struct cam_req_mgr_frame_msg { uint32_t reserved; }; +/** + * struct cam_req_mgr_custom_msg + * @custom_type: custom type + * @request_id: request id of the frame + * @frame_id: frame id of the frame + * @timestamp: timestamp of the frame + * @link_hdl: link handle associated with this message + * @custom_data: custom data + */ +struct cam_req_mgr_custom_msg { + uint32_t custom_type; + uint64_t request_id; + uint64_t frame_id; + uint64_t timestamp; + int32_t link_hdl; + uint64_t custom_data; +}; + /** * struct cam_req_mgr_message * @session_hdl: session to which the frame belongs to * @reserved: reserved field - * @u: union which can either be error or frame message + * @u: union which can either be error/frame/custom message */ struct cam_req_mgr_message { int32_t session_hdl; @@ -471,6 +490,7 @@ struct cam_req_mgr_message { union { struct cam_req_mgr_error_msg err_msg; struct cam_req_mgr_frame_msg frame_msg; + struct cam_req_mgr_custom_msg custom_msg; } u; }; #endif /* __UAPI_LINUX_CAM_REQ_MGR_H */ -- GitLab From 643c7c3ead38f969a99968e26b90de431c59ef47 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 13 Sep 2019 11:08:05 -0700 Subject: [PATCH 203/410] msm: camera: isp: Obtain timestamp as part of frame header In use-cases that involve custom HW retrieve the timestamp for shutter from frame header as opposed to csid registers. CRs-Fixed: 2524308 Change-Id: I5de789cf939546affbfe6d537d8090982f39189d Signed-off-by: Karthik Anantha Ram --- drivers/cam_core/cam_hw_mgr_intf.h | 6 +- drivers/cam_isp/cam_isp_context.c | 98 +++++++++++++--- drivers/cam_isp/cam_isp_context.h | 8 ++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 107 +++++++++++++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 6 +- .../hw_utils/cam_isp_packet_parser.c | 21 +++- .../hw_utils/include/cam_isp_packet_parser.h | 20 +++- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 8 +- .../isp_hw/include/cam_ife_csid_hw_intf.h | 8 +- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 4 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 24 +++- 11 files changed, 279 insertions(+), 31 deletions(-) diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index fe074734f389..c9ece0ae1427 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_HW_MGR_INTF_H_ @@ -101,6 +101,8 @@ struct cam_hw_done_event_data { * @num_acq: Total number of acquire in the payload * @acquire_info: Acquired resource array pointer * @ctxt_to_hw_map: HW context (returned) + * @custom_enabled: ctx has custom enabled + * @use_frame_header_ts: Use frame header for qtimer ts * @acquired_hw_id: Acquired hardware mask * @acquired_hw_path: Acquired path mask for an input * if input splits into multiple paths, @@ -115,6 +117,8 @@ struct cam_hw_acquire_args { uint32_t acquire_info_size; uintptr_t acquire_info; void *ctxt_to_hw_map; + bool custom_enabled; + bool use_frame_header_ts; uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 1ed49e8255ab..89209b8d33a3 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -248,9 +248,10 @@ static int __cam_isp_ctx_enqueue_init_request( struct cam_context *ctx, struct cam_ctx_request *req) { int rc = 0; - struct cam_ctx_request *req_old; - struct cam_isp_ctx_req *req_isp_old; - struct cam_isp_ctx_req *req_isp_new; + struct cam_ctx_request *req_old; + struct cam_isp_ctx_req *req_isp_old; + struct cam_isp_ctx_req *req_isp_new; + struct cam_isp_prepare_hw_update_data *hw_update_data; spin_lock_bh(&ctx->lock); if (list_empty(&ctx->pending_req_list)) { @@ -302,6 +303,13 @@ static int __cam_isp_ctx_enqueue_init_request( memcpy(&req_old->pf_data, &req->pf_data, sizeof(struct cam_hw_mgr_dump_pf_data)); + /* Update frame header params for EPCR */ + hw_update_data = &req_isp_new->hw_update_data; + req_isp_old->hw_update_data.frame_header_res_id = + req_isp_new->hw_update_data.frame_header_res_id; + req_isp_old->hw_update_data.frame_header_cpu_addr = + hw_update_data->frame_header_cpu_addr; + req_old->request_id = req->request_id; list_add_tail(&req->list, &ctx->free_req_list); @@ -428,9 +436,9 @@ static void __cam_isp_ctx_send_sof_boot_timestamp( req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta; CAM_DBG(CAM_ISP, - "request id:%lld frame number:%lld boot time stamp:0x%llx", + "request id:%lld frame number:%lld boot time stamp:0x%llx status:%u", request_id, ctx_isp->frame_id, - ctx_isp->boot_timestamp); + ctx_isp->boot_timestamp, sof_event_status); if (cam_req_mgr_notify_message(&req_msg, V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS, @@ -440,6 +448,41 @@ static void __cam_isp_ctx_send_sof_boot_timestamp( request_id); } +static void __cam_isp_ctx_send_sof_timestamp_frame_header( + struct cam_isp_context *ctx_isp, uint32_t *frame_header_cpu_addr, + uint64_t request_id, uint32_t sof_event_status) +{ + uint32_t *time32 = NULL; + uint64_t timestamp = 0; + struct cam_req_mgr_message req_msg; + + time32 = frame_header_cpu_addr; + timestamp = (uint64_t) time32[1]; + timestamp = timestamp << 24; + timestamp |= (uint64_t)(time32[0] >> 8); + timestamp = mul_u64_u32_div(timestamp, + CAM_IFE_QTIMER_MUL_FACTOR, + CAM_IFE_QTIMER_DIV_FACTOR); + + ctx_isp->sof_timestamp_val = timestamp; + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; + req_msg.u.frame_msg.request_id = request_id; + req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val; + req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.frame_msg.sof_status = sof_event_status; + + CAM_DBG(CAM_ISP, + "request id:%lld frame number:%lld SOF time stamp:0x%llx status:%u", + request_id, ctx_isp->frame_id, + ctx_isp->sof_timestamp_val, sof_event_status); + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the sof time for req id:%lld", + request_id); +} static void __cam_isp_ctx_send_sof_timestamp( struct cam_isp_context *ctx_isp, uint64_t request_id, @@ -447,6 +490,10 @@ static void __cam_isp_ctx_send_sof_timestamp( { struct cam_req_mgr_message req_msg; + if ((ctx_isp->use_frame_header_ts) && (request_id) && + (sof_event_status == CAM_REQ_MGR_SOF_EVENT_SUCCESS)) + goto end; + req_msg.session_hdl = ctx_isp->base->session_hdl; req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; req_msg.u.frame_msg.request_id = request_id; @@ -456,10 +503,9 @@ static void __cam_isp_ctx_send_sof_timestamp( req_msg.u.frame_msg.frame_id_meta = ctx_isp->frame_id_meta; CAM_DBG(CAM_ISP, - "request id:%lld frame number:%lld SOF time stamp:0x%llx", + "request id:%lld frame number:%lld SOF time stamp:0x%llx status:%u", request_id, ctx_isp->frame_id, - ctx_isp->sof_timestamp_val); - CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status); + ctx_isp->sof_timestamp_val, sof_event_status); if (cam_req_mgr_notify_message(&req_msg, V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT)) @@ -467,9 +513,9 @@ static void __cam_isp_ctx_send_sof_timestamp( "Error in notifying the sof time for req id:%lld", request_id); +end: __cam_isp_ctx_send_sof_boot_timestamp(ctx_isp, request_id, sof_event_status); - } static void __cam_isp_ctx_handle_buf_done_fail_log( @@ -511,9 +557,9 @@ static int __cam_isp_ctx_handle_buf_done_for_request( { int rc = 0; int i, j; - struct cam_isp_ctx_req *req_isp; + struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; - uint64_t buf_done_req_id; + uint64_t buf_done_req_id; trace_cam_buf_done("ISP", ctx, req); @@ -605,6 +651,14 @@ static int __cam_isp_ctx_handle_buf_done_for_request( req_isp->num_acked++; req_isp->fence_map_out[j].sync_id = -1; } + + if ((ctx_isp->use_frame_header_ts) && + (req_isp->hw_update_data.frame_header_res_id == + req_isp->fence_map_out[j].resource_handle)) + __cam_isp_ctx_send_sof_timestamp_frame_header( + ctx_isp, + req_isp->hw_update_data.frame_header_cpu_addr, + req->request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } if (req_isp->num_acked > req_isp->num_fence_map_out) { @@ -648,10 +702,14 @@ static int __cam_isp_ctx_handle_buf_done_for_request( ctx->ctx_id); } } else { - if (ctx_isp->reported_req_id < buf_done_req_id) { - ctx_isp->reported_req_id = buf_done_req_id; - __cam_isp_ctx_send_sof_timestamp(ctx_isp, - buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + if (!ctx_isp->use_frame_header_ts) { + if (ctx_isp->reported_req_id < buf_done_req_id) { + ctx_isp->reported_req_id = buf_done_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + buf_done_req_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } } list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); @@ -2906,6 +2964,8 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, } ctx->last_flush_req = 0; + ctx_isp->custom_enabled = false; + ctx_isp->use_frame_header_ts = false; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -3550,6 +3610,12 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, goto free_res; } + /* Set custom flag if applicable + * custom hw is supported only on v2 + */ + ctx_isp->custom_enabled = param.custom_enabled; + ctx_isp->use_frame_header_ts = param.use_frame_header_ts; + /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; @@ -4444,6 +4510,8 @@ int cam_isp_context_init(struct cam_isp_context *ctx, ctx->base = ctx_base; ctx->frame_id = 0; + ctx->custom_enabled = false; + ctx->use_frame_header_ts = false; ctx->active_req_cnt = 0; ctx->reported_req_id = 0; ctx->req_info.last_bufdone_req_id = 0; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 4b3c45b57c94..fd1977c52dca 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -14,6 +14,10 @@ #include "cam_context.h" #include "cam_isp_hw_mgr_intf.h" + +#define CAM_IFE_QTIMER_MUL_FACTOR 10000 +#define CAM_IFE_QTIMER_DIV_FACTOR 192 + /* * Maximum hw resource - This number is based on the maximum * output port resource. The current maximum resource number @@ -191,6 +195,8 @@ struct cam_isp_context_req_id_info { * @hw_acquired: Indicate whether HW resources are acquired * @init_received: Indicate whether init config packet is received * @split_acquire: Indicate whether a separate acquire is expected + * @custom_enabled: Custom HW enabled for this ctx + * @use_frame_header_ts: Use frame header for qtimer ts * @init_timestamp: Timestamp at which this context is initialized * */ @@ -223,6 +229,8 @@ struct cam_isp_context { bool hw_acquired; bool init_received; bool split_acquire; + bool custom_enabled; + bool use_frame_header_ts; unsigned int init_timestamp; }; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index fba3698baad8..4c3479c5190d 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2741,6 +2741,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) goto err; } + ife_ctx->custom_enabled = false; ife_ctx->common.cb_priv = acquire_args->context_data; for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++) ife_ctx->common.event_cb[i] = acquire_args->event_cb; @@ -2793,6 +2794,12 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } CAM_DBG(CAM_ISP, "in_res_type %x", in_port->res_type); + if ((in_port->cust_node) && (!ife_ctx->custom_enabled)) { + ife_ctx->custom_enabled = true; + /* This can be obtained from uapi */ + ife_ctx->use_frame_header_ts = true; + } + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, &num_pix_port_per_in, &num_rdi_port_per_in, &acquire_args->acquired_hw_id[i], @@ -2827,6 +2834,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } acquire_args->ctxt_to_hw_map = ife_ctx; + acquire_args->custom_enabled = ife_ctx->custom_enabled; + acquire_args->use_frame_header_ts = ife_ctx->use_frame_header_ts; ife_ctx->ctx_in_use = 1; acquire_args->valid_acquired_hw = @@ -4239,6 +4248,8 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->is_rdi_only_context = 0; ctx->cdm_handle = 0; ctx->cdm_ops = NULL; + ctx->custom_enabled = false; + ctx->use_frame_header_ts = false; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; @@ -5546,6 +5557,58 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, return rc; } +static int cam_ife_mgr_util_insert_frame_header( + struct cam_kmd_buf_info *kmd_buf, + struct cam_isp_prepare_hw_update_data *prepare_hw_data) +{ + int mmu_hdl = -1, rc = 0; + dma_addr_t iova_addr; + uint32_t frame_header_iova, padded_bytes = 0; + size_t len; + struct cam_ife_hw_mgr *hw_mgr = &g_ife_hw_mgr; + + mmu_hdl = cam_mem_is_secure_buf( + kmd_buf->handle) ? + hw_mgr->mgr_common.img_iommu_hdl_secure : + hw_mgr->mgr_common.img_iommu_hdl; + + rc = cam_mem_get_io_buf(kmd_buf->handle, mmu_hdl, + &iova_addr, &len); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to get io addr for handle = %d for mmu_hdl = %u", + kmd_buf->handle, mmu_hdl); + return rc; + } + + frame_header_iova = (uint32_t)iova_addr; + frame_header_iova += kmd_buf->offset; + + /* frame header address needs to be 16 byte aligned */ + if (frame_header_iova % 16) { + padded_bytes = (uint32_t)(16 - (frame_header_iova % 16)); + iova_addr += padded_bytes; + } + + prepare_hw_data->frame_header_iova = frame_header_iova; + + /* update the padding if any for the cpu addr as well */ + prepare_hw_data->frame_header_cpu_addr = kmd_buf->cpu_addr + + (padded_bytes / 4); + + CAM_DBG(CAM_ISP, + "Frame Header iova_addr: %pK cpu_addr: %pK padded_bytes: %llu", + prepare_hw_data->frame_header_iova, + prepare_hw_data->frame_header_cpu_addr, + padded_bytes); + + /* Reserve memory for frame header */ + kmd_buf->used_bytes += 128; + kmd_buf->offset += kmd_buf->used_bytes; + + return rc; +} + static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, void *prepare_hw_update_args) { @@ -5557,7 +5620,9 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, struct cam_kmd_buf_info kmd_buf; uint32_t i; bool fill_fence = true; + bool frame_header_enable = false; struct cam_isp_prepare_hw_update_data *prepare_hw_data; + struct cam_isp_frame_header_info frame_header_info; if (!hw_mgr_priv || !prepare_hw_update_args) { CAM_ERR(CAM_ISP, "Invalid args"); @@ -5584,6 +5649,15 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, if (rc) return rc; + if (ctx->use_frame_header_ts) { + rc = cam_ife_mgr_util_insert_frame_header(&kmd_buf, + prepare_hw_data); + if (rc) + return rc; + + frame_header_enable = true; + } + rc = cam_packet_util_process_patches(prepare->packet, hw_mgr->mgr_common.cmd_iommu_hdl, hw_mgr->mgr_common.cmd_iommu_hdl_secure); @@ -5632,13 +5706,23 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, } } + memset(&frame_header_info, 0, + sizeof(struct cam_isp_frame_header_info)); + if (frame_header_enable) { + frame_header_info.frame_header_enable = true; + frame_header_info.frame_header_iova_addr = + prepare_hw_data->frame_header_iova; + } + /* get IO buffers */ - rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl, + rc = cam_isp_add_io_buffers( + hw_mgr->mgr_common.img_iommu_hdl, hw_mgr->mgr_common.img_iommu_hdl_secure, prepare, ctx->base[i].idx, &kmd_buf, ctx->res_list_ife_out, &ctx->res_list_ife_in_rd, - CAM_IFE_HW_OUT_RES_MAX, fill_fence); + CAM_IFE_HW_OUT_RES_MAX, fill_fence, + &frame_header_info); if (rc) { CAM_ERR(CAM_ISP, @@ -5650,6 +5734,18 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, /* fence map table entries need to fill only once in the loop */ if (fill_fence) fill_fence = false; + + if (frame_header_info.frame_header_res_id && + frame_header_enable) { + frame_header_enable = false; + prepare_hw_data->frame_header_res_id = + frame_header_info.frame_header_res_id; + + CAM_DBG(CAM_ISP, + "Frame header enabled for res_id 0x%x cpu_addr %pK", + prepare_hw_data->frame_header_res_id, + prepare_hw_data->frame_header_cpu_addr); + } } /* @@ -6484,10 +6580,15 @@ static int cam_ife_hw_mgr_handle_hw_sof( rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, CAM_ISP_HW_EVENT_SOF); if (!rc) { - cam_ife_mgr_cmd_get_sof_timestamp(ife_hw_mgr_ctx, + cam_ife_mgr_cmd_get_sof_timestamp( + ife_hw_mgr_ctx, &sof_done_event_data.timestamp, &sof_done_event_data.boot_time); + /* if frame header is enabled reset qtimer ts */ + if (ife_hw_mgr_ctx->use_frame_header_ts) + sof_done_event_data.timestamp = 0x0; + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) break; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 17a9e11834df..438d3549eaef 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_HW_MGR_H_ @@ -139,6 +139,8 @@ struct cam_ife_hw_mgr_debug { * @init_done indicate whether init hw is done * @is_fe_enable indicate whether fetch engine\read path is enabled * @is_dual indicate whether context is in dual VFE mode + * @custom_enabled update the flag if context is connected to custom HW + * @use_frame_header_ts obtain qtimer ts using frame header * @ts captured timestamp when the ctx is acquired */ struct cam_ife_hw_mgr_ctx { @@ -186,6 +188,8 @@ struct cam_ife_hw_mgr_ctx { bool init_done; bool is_fe_enable; bool is_dual; + bool custom_enabled; + bool use_frame_header_ts; struct timespec64 ts; }; diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 86a14229915f..679ec02f9fbf 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -463,7 +463,8 @@ int cam_isp_add_io_buffers( struct cam_ife_hw_mgr_res *res_list_isp_out, struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, - bool fill_fence) + bool fill_fence, + struct cam_isp_frame_header_info *frame_header_info) { int rc = 0; dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; @@ -479,6 +480,7 @@ int cam_isp_add_io_buffers( uint32_t i, j, num_out_buf, num_in_buf; uint32_t res_id_out, res_id_in, plane_id; uint32_t io_cfg_used_bytes, num_ent; + uint64_t iova_addr; size_t size; int32_t hdl; int mmu_hdl; @@ -679,6 +681,21 @@ int cam_isp_add_io_buffers( wm_update.image_buf = io_addr; wm_update.num_buf = plane_id; wm_update.io_cfg = &io_cfg[i]; + wm_update.frame_header = 0; + iova_addr = frame_header_info->frame_header_iova_addr; + if ((frame_header_info->frame_header_enable) && + !(frame_header_info->frame_header_res_id)) { + wm_update.frame_header = iova_addr; + frame_header_info->frame_header_res_id = + res->res_id; + wm_update.local_id = + prepare->packet->header.request_id; + CAM_DBG(CAM_ISP, + "Frame header enabled for res: 0x%x iova: %pK", + frame_header_info->frame_header_res_id, + wm_update.frame_header); + } + update_buf.cmd.size = kmd_buf_remain_size; update_buf.wm_update = &wm_update; diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h index c9bd4c4430e9..0c0f1e4ea6ce 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_PARSER_H_ @@ -34,6 +34,19 @@ struct cam_isp_generic_blob_info { struct cam_kmd_buf_info *kmd_buf_info; }; +/* + * struct cam_isp_frame_header_info + * + * @frame_header_enable: Enable frame header + * @frame_header_iova_addr: frame header iova + * @frame_header_res_id: res id for which frame header is enabled + */ +struct cam_isp_frame_header_info { + bool frame_header_enable; + uint64_t frame_header_iova_addr; + uint32_t frame_header_res_id; +}; + /* * cam_isp_add_change_base() * @@ -127,7 +140,7 @@ int cam_isp_add_command_buffers( * @res_list_ife_in_rd: IFE /VFE in rd resource list * @size_isp_out: Size of the res_list_isp_out array * @fill_fence: If true, Fence map table will be filled - * + * @frame_header_info: Frame header related params * @return: 0 for success * -EINVAL for Fail */ @@ -140,7 +153,8 @@ int cam_isp_add_io_buffers( struct cam_ife_hw_mgr_res *res_list_isp_out, struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, - bool fill_fence); + bool fill_fence, + struct cam_isp_frame_header_info *frame_header_info); /* * cam_isp_add_reg_update() diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 1214d908ec06..9502fe44b436 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -119,6 +119,9 @@ struct cam_isp_bw_config_internal { * @packet_opcode_type: Packet header opcode in the packet header * this opcode defines, packet is init packet or * update packet + * @frame_header_cpu_addr: Frame header cpu addr + * @frame_header_iova: Frame header iova + * @frame_header_res_id: Out port res_id corresponding to frame header * @bw_config_version: BW config version indicator * @bw_config: BW config information * @bw_config_v2: BW config info for AXI bw voting v2 @@ -131,10 +134,13 @@ struct cam_isp_bw_config_internal { struct cam_isp_prepare_hw_update_data { struct cam_ife_hw_mgr_ctx *ife_mgr_ctx; uint32_t packet_opcode_type; + uint32_t *frame_header_cpu_addr; + uint64_t frame_header_iova; + uint32_t frame_header_res_id; uint32_t bw_config_version; struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; struct cam_isp_bw_config_internal_v2 bw_config_v2[CAM_IFE_HW_NUM_MAX]; - bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; + bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; struct cam_cmd_buf_desc reg_dump_buf_desc[ CAM_REG_DUMP_MAX_BUF_ENTRIES]; uint32_t num_reg_dump_buf; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 56ce59636dda..0474a2840460 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSID_HW_INTF_H_ @@ -187,9 +187,9 @@ struct cam_csid_reset_cfg_args { /** * struct cam_csid_get_time_stamp_args- time stamp capture arguments - * @res_node : resource to get the time stamp - * @time_stamp_val : captured time stamp - * @boot_timestamp : boot time stamp + * @node_res : resource to get the time stamp + * @time_stamp_val : captured time stamp + * @boot_timestamp : boot time stamp */ struct cam_csid_get_time_stamp_args { struct cam_isp_resource_node *node_res; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 35b9e943fe22..fe1159d4fc6a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -199,12 +199,16 @@ struct cam_isp_hw_cmd_buf_update { * * @ image_buf: image buffer address array * @ num_buf: Number of buffers in the image_buf array + * @ frame_header: frame header iova + * @ local_id: local id for the wm * @ io_cfg: IO buffer config information sent from UMD * */ struct cam_isp_hw_get_wm_update { dma_addr_t *image_buf; uint32_t num_buf; + uint64_t frame_header; + uint32_t local_id; struct cam_buf_io_cfg *io_cfg; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index cae125315895..ef54125f682b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ @@ -3007,6 +3007,7 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, uint32_t i, j, k, size = 0; uint32_t frame_inc = 0, val; uint32_t loop_size = 0; + bool frame_header_enable = false; bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; @@ -3040,6 +3041,27 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, wm_data = vfe_out_data->wm_res[i]->res_priv; ubwc_client = wm_data->hw_regs->ubwc_regs; + /* Disable frame header in case it was previously enabled */ + if ((wm_data->en_cfg) & (1 << 2)) + wm_data->en_cfg &= ~(1 << 2); + + if (update_buf->wm_update->frame_header && + !frame_header_enable) { + wm_data->en_cfg |= 1 << 2; + frame_header_enable = true; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_header_addr, + update_buf->wm_update->frame_header); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_header_cfg, + update_buf->wm_update->local_id); + CAM_DBG(CAM_ISP, + "WM: %d en_cfg 0x%x frame_header %pK local_id %u", + wm_data->index, wm_data->en_cfg, + update_buf->wm_update->frame_header, + update_buf->wm_update->local_id); + } + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->cfg, wm_data->en_cfg); CAM_DBG(CAM_ISP, "WM:%d en_cfg 0x%X", -- GitLab From aff901aeefaaa894f5a565e5be34db7cd5f2be24 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 14 Oct 2019 15:08:23 +0530 Subject: [PATCH 204/410] msm: camera: req_mgr: LDAR Debug framework implementation When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. To debug the cause for this situation and to dump the information, user space sends a dump command to the kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and dumps the relevant information in the buffer. This data is written to a file for offline processing. This commit implements the framework for traversal across the RT and NRT devices. CRs-Fixed: 2503859 Change-Id: I7e24006c20c23bfab163a2ad13b4ac6e2913bb9e Signed-off-by: Gaurav Jindal --- drivers/cam_core/cam_context.c | 65 ++++++++++ drivers/cam_core/cam_context.h | 49 ++++++++ drivers/cam_core/cam_context_utils.c | 127 ++++++++++++++++++++ drivers/cam_core/cam_context_utils.h | 3 +- drivers/cam_core/cam_hw_mgr_intf.h | 19 +++ drivers/cam_core/cam_node.c | 77 ++++++++++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 60 +++++++++ drivers/cam_req_mgr/cam_req_mgr_core.h | 6 + drivers/cam_req_mgr/cam_req_mgr_dev.c | 24 ++++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 24 ++++ include/uapi/media/cam_defs.h | 22 ++++ include/uapi/media/cam_req_mgr.h | 2 + 12 files changed, 477 insertions(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 1c17422d01d0..267b23dafa72 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -230,6 +230,34 @@ int cam_context_handle_crm_process_evt(struct cam_context *ctx, return rc; } +int cam_context_handle_crm_dump_req(struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump) +{ + int rc = 0; + + if (!ctx) { + CAM_ERR(CAM_CORE, "Invalid Context"); + return -EINVAL; + } + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context %s ctx_id %d is not ready", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + mutex_lock(&ctx->ctx_mutex); + + if (ctx->state_machine[ctx->state].crm_ops.dump_req) + rc = ctx->state_machine[ctx->state].crm_ops.dump_req(ctx, + dump); + else + CAM_ERR(CAM_CORE, "No crm dump req for %s dev %d, state %d", + ctx->dev_name, ctx->dev_hdl, ctx->state); + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, uint32_t buf_info) { @@ -524,6 +552,43 @@ int cam_context_handle_info_dump(void *context, return rc; } +int cam_context_handle_dump_dev(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc = 0; + + if (!ctx) { + CAM_ERR(CAM_CORE, "Invalid Context"); + return -EINVAL; + } + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context %s ctx_id %d is not ready", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, + "Context %s ctx_id %d Invalid dump command payload", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + CAM_DBG(CAM_CORE, "dump device in dev %d, name %s state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + if (ctx->state_machine[ctx->state].ioctl_ops.dump_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.dump_dev( + ctx, cmd); + else + CAM_WARN(CAM_CORE, "No dump device in dev %d, name %s state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + int cam_context_init(struct cam_context *ctx, const char *dev_name, uint64_t dev_id, diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 2c1c685e76b8..770451faadf2 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -23,6 +23,12 @@ struct cam_context; #define CAM_CTX_CFG_MAX 20 #define CAM_CTX_RES_MAX 20 +/* max tag dump header string length*/ +#define CAM_CTXT_DUMP_TAG_MAX_LEN 32 + +/* Number of words to be dumped for context*/ +#define CAM_CTXT_DUMP_NUM_WORDS 10 + /** * enum cam_ctx_state - context top level states * @@ -86,6 +92,7 @@ struct cam_ctx_request { * @flush_dev: Function pointer for flush device * @acquire_hw: Function pointer for acquire hw * @release_hw: Function pointer for release hw + * @dump_dev: Function pointer for dump dev * */ struct cam_ctx_ioctl_ops { @@ -103,6 +110,8 @@ struct cam_ctx_ioctl_ops { struct cam_flush_dev_cmd *cmd); int (*acquire_hw)(struct cam_context *ctx, void *args); int (*release_hw)(struct cam_context *ctx, void *args); + int (*dump_dev)(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd); }; /** @@ -114,6 +123,7 @@ struct cam_ctx_ioctl_ops { * @apply_req: Apply setting for the context * @flush_req: Flush request to remove request ids * @process_evt: Handle event notification from CRM.(optional) + * @dump_req: Dump information for the issue request * */ struct cam_ctx_crm_ops { @@ -129,6 +139,8 @@ struct cam_ctx_crm_ops { struct cam_req_mgr_flush_request *flush); int (*process_evt)(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *evt_data); + int (*dump_req)(struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump); }; @@ -219,6 +231,19 @@ struct cam_context { uint32_t last_flush_req; }; +/** + * struct cam_context_dump_header - Function for context dump header + * + * @tag : Tag for context dump header + * @size : Size of data + * @word_size : Word size of data + */ +struct cam_context_dump_header { + uint8_t tag[CAM_CTXT_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + /** * cam_context_shutdown() * @@ -301,6 +326,18 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx, int cam_context_handle_crm_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *process_evt); +/** + * cam_context_handle_crm_dump_req() + * + * @brief: Handle CRM dump request + * + * @ctx: Object pointer for cam_context + * @dump: Dump request command payload + * + */ +int cam_context_handle_crm_dump_req(struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump); + /** * cam_context_dump_pf_info() * @@ -410,6 +447,18 @@ int cam_context_handle_start_dev(struct cam_context *ctx, int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); +/** + * cam_context_handle_dump_dev() + * + * @brief: Handle dump device command + * + * @ctx: Object pointer for cam_context + * @cmd: Dump device command payload + * + */ +int cam_context_handle_dump_dev(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd); + /** * cam_context_handle_info_dump() * diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 423961aaf2af..87abebabaf00 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -1046,3 +1046,130 @@ int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx) end: return rc; } + +static int cam_context_dump_context(struct cam_context *ctx, + struct cam_hw_dump_args *dump_args) +{ + int rc; + int i; + size_t buf_len; + size_t remain_len; + uint8_t *dst; + uint64_t *addr, *start; + uint32_t min_len; + uintptr_t cpu_addr; + struct cam_ctx_request *req; + struct cam_context_dump_header *hdr; + + if (!ctx || !dump_args) { + CAM_ERR(CAM_CORE, "Invalid parameters %pK %pK", + ctx, dump_args); + return -EINVAL; + } + + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_CTXT, "[%s][%d] no active request", + ctx->dev_name, ctx->ctx_id); + spin_unlock_bh(&ctx->lock); + return -EIO; + } + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + spin_unlock_bh(&ctx->lock); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_CTXT, "Invalid hdl %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + if (dump_args->offset >= buf_len) { + CAM_WARN(CAM_CTXT, "dump buffer overshoot offset %zu len %zu", + dump_args->offset, buf_len); + return -ENOSPC; + } + + remain_len = buf_len - dump_args->offset; + min_len = sizeof(struct cam_context_dump_header) + + (CAM_CTXT_DUMP_NUM_WORDS + req->num_in_map_entries + + (req->num_out_map_entries * 2)) * sizeof(uint64_t); + + if (remain_len < min_len) { + CAM_WARN(CAM_CTXT, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + dst = (uint8_t *)cpu_addr + dump_args->offset; + hdr = (struct cam_context_dump_header *)dst; + scnprintf(hdr->tag, CAM_CTXT_DUMP_TAG_MAX_LEN, + "%s_CTXT_DUMP:", ctx->dev_name); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_context_dump_header)); + start = addr; + *addr++ = ctx->ctx_id; + *addr++ = refcount_read(&(ctx->refcount.refcount)); + *addr++ = ctx->last_flush_req; + *addr++ = ctx->state; + *addr++ = req->num_out_map_entries; + for (i = 0; i < req->num_out_map_entries; i++) { + *addr++ = req->out_map_entries[i].resource_handle; + *addr++ = req->out_map_entries[i].sync_id; + } + *addr++ = req->num_in_map_entries; + for (i = 0; i < req->num_in_map_entries; i++) + *addr++ = req->in_map_entries[i].sync_id; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_context_dump_header); + return rc; +} + +int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc = 0; + struct cam_hw_dump_args dump_args; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + return -EINVAL; + } + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + return -EFAULT; + } + memset(&dump_args, 0, sizeof(dump_args)); + if (ctx->hw_mgr_intf->hw_dump) { + dump_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + dump_args.buf_handle = cmd->buf_handle; + dump_args.offset = cmd->offset; + dump_args.request_id = cmd->issue_req_id; + dump_args.error_type = cmd->error_type; + rc = ctx->hw_mgr_intf->hw_dump( + ctx->hw_mgr_intf->hw_mgr_priv, + &dump_args); + if (rc) { + CAM_ERR(CAM_CTXT, "[%s][%d] handle[%u] failed", + ctx->dev_name, ctx->ctx_id, dump_args.buf_handle); + return rc; + } + /* Offset will change if the issue request id is found with + * the hw and has been lying with it beyond threshold time. + * If offset does not change, do not dump the context + * information as the current context has no problem with + * the provided request id. + */ + if (dump_args.offset > cmd->offset) { + cam_context_dump_context(ctx, &dump_args); + CAM_INFO(CAM_CTXT, "[%s] ctx: %d Filled Length %u", + ctx->dev_name, ctx->ctx_id, + dump_args.offset - cmd->offset); + cmd->offset = dump_args.offset; + } + } else { + CAM_DBG(CAM_CTXT, "%s hw dump not registered", ctx->dev_name); + } + return rc; +} diff --git a/drivers/cam_core/cam_context_utils.h b/drivers/cam_core/cam_context_utils.h index 087fdbf36544..79dec3142e8a 100644 --- a/drivers/cam_core/cam_context_utils.h +++ b/drivers/cam_core/cam_context_utils.h @@ -30,5 +30,6 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, struct cam_packet *packet, unsigned long iova, uint32_t buf_info, bool *mem_found); int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx); - +int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd); #endif /* _CAM_CONTEXT_UTILS_H_ */ diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index c9ece0ae1427..422a47bf354a 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -304,6 +304,23 @@ struct cam_hw_reset_args { void *ctxt_to_hw_map; }; +/** + * struct cam_hw_dump_args - Dump arguments + * + * @request_id: request_id + * @offset: Buffer offset. This is updated by the drivers. + * @buf_handle: Buffer handle + * @error_type: Error type, to be used to extend dump information + * @ctxt_to_hw_map: HW context from the acquire + */ +struct cam_hw_dump_args { + uint64_t request_id; + size_t offset; + uint32_t buf_handle; + uint32_t error_type; + void *ctxt_to_hw_map; +}; + /* enum cam_hw_mgr_command - Hardware manager command type */ enum cam_hw_mgr_command { CAM_HW_MGR_CMD_INTERNAL, @@ -359,6 +376,7 @@ struct cam_hw_cmd_args { * @hw_close: Function pointer for HW deinit * @hw_flush: Function pointer for HW flush * @hw_reset: Function pointer for HW reset + * @hw_dump: Function pointer for HW dump * */ struct cam_hw_mgr_intf { @@ -380,6 +398,7 @@ struct cam_hw_mgr_intf { int (*hw_close)(void *hw_priv, void *hw_close_args); int (*hw_flush)(void *hw_priv, void *hw_flush_args); int (*hw_reset)(void *hw_priv, void *hw_reset_args); + int (*hw_dump)(void *hw_priv, void *hw_dump_args); }; #endif /* _CAM_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 4fefa2f35db3..672ae35b6226 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -435,6 +435,39 @@ static int __cam_node_handle_release_dev(struct cam_node *node, return rc; } +static int __cam_node_handle_dump_dev(struct cam_node *node, + struct cam_dump_req_cmd *dump) +{ + int rc; + struct cam_context *ctx = NULL; + + if (!dump) + return -EINVAL; + + if (dump->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (dump->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(dump->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + dump->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_dump_dev(ctx, dump); + if (rc) + CAM_ERR(CAM_CORE, "Dump failure for node %s", node->name); + + return rc; +} + static int __cam_node_handle_release_hw_v1(struct cam_node *node, struct cam_release_hw_cmd_v1 *release) { @@ -575,6 +608,25 @@ static int __cam_node_crm_process_evt( return cam_context_handle_crm_process_evt(ctx, evt_data); } +static int __cam_node_crm_dump_req(struct cam_req_mgr_dump_info *dump) +{ + struct cam_context *ctx = NULL; + + if (!dump) { + CAM_ERR(CAM_CORE, "Invalid dump request payload"); + return -EINVAL; + } + + ctx = (struct cam_context *) cam_get_device_priv(dump->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + dump->dev_hdl); + return -EINVAL; + } + + return cam_context_handle_crm_dump_req(ctx, dump); +} + int cam_node_deinit(struct cam_node *node) { if (node) @@ -630,6 +682,7 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, node->crm_node_intf.link_setup = __cam_node_crm_link_setup; node->crm_node_intf.flush_req = __cam_node_crm_flush_req; node->crm_node_intf.process_evt = __cam_node_crm_process_evt; + node->crm_node_intf.dump_req = __cam_node_crm_dump_req; mutex_init(&node->list_mutex); INIT_LIST_HEAD(&node->free_ctx_list); @@ -877,6 +930,30 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) } break; } + case CAM_DUMP_REQ: { + struct cam_dump_req_cmd dump; + + if (copy_from_user(&dump, u64_to_user_ptr(cmd->handle), + sizeof(dump))) { + rc = -EFAULT; + break; + } + rc = __cam_node_handle_dump_dev(node, &dump); + if (rc) { + CAM_ERR(CAM_CORE, + "Dump device %s failed(rc = %d) ", + node->name, rc); + break; + } + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &dump, sizeof(dump))) { + CAM_ERR(CAM_CORE, + "Dump device %s copy_to_user fail", + node->name); + rc = -EFAULT; + } + break; + } default: CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code); rc = -EINVAL; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 5b3c57650719..91e3ee1cdc4d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3833,6 +3833,66 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) return rc; } +int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) +{ + int rc = 0; + int i; + struct cam_req_mgr_dump_info info; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_connected_device *device = NULL; + + if (!dump_req) { + CAM_ERR(CAM_CRM, "dump req is NULL"); + return -EFAULT; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ + session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(dump_req->session_handle); + if (!session) { + CAM_ERR(CAM_CRM, "Invalid session %x", + dump_req->session_handle); + rc = -EINVAL; + goto end; + } + if (session->num_links <= 0) { + CAM_WARN(CAM_CRM, "No active links in session %x", + dump_req->session_handle); + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(dump_req->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", dump_req->link_hdl); + rc = -EINVAL; + goto end; + } + info.offset = dump_req->offset; + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + info.link_hdl = dump_req->link_hdl; + info.dev_hdl = device->dev_hdl; + info.req_id = dump_req->issue_req_id; + info.buf_handle = dump_req->buf_handle; + info.error_type = dump_req->error_type; + if (device->ops && device->ops->dump_req) { + rc = device->ops->dump_req(&info); + if (rc) + CAM_ERR(CAM_REQ, + "Fail dump req %llu dev %d rc %d", + info.req_id, device->dev_hdl, rc); + } + } + dump_req->offset = info.offset; + CAM_INFO(CAM_REQ, "req %llu, offset %zu", + dump_req->issue_req_id, dump_req->offset); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return 0; +} int cam_req_mgr_core_device_init(void) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 14cf4ff06a36..df4a890079a8 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -505,4 +505,10 @@ void cam_req_mgr_handle_core_shutdown(void); */ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control); +/** + * cam_req_mgr_dump_request() + * @brief: Dumps the request information + * @dump_req: Dump request + */ +int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req); #endif diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 3f9db55ab9a1..9f9ae3e4e327 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -523,6 +523,30 @@ static long cam_private_ioctl(struct file *file, void *fh, rc = -EINVAL; } break; + case CAM_REQ_MGR_REQUEST_DUMP: { + struct cam_dump_req_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_dump_req_cmd))) { + rc = -EFAULT; + break; + } + rc = cam_req_mgr_dump_request(&cmd); + if (rc) { + CAM_ERR(CAM_CORE, "dump fail for dev %d req %llu rc %d", + cmd.dev_handle, cmd.issue_req_id, rc); + break; + } + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &cmd, sizeof(struct cam_dump_req_cmd))) + rc = -EFAULT; + } + break; default: return -ENOIOCTLCMD; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index 68ab7917e947..de3a4606be1d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -21,6 +21,7 @@ struct cam_req_mgr_core_dev_link_setup; struct cam_req_mgr_apply_request; struct cam_req_mgr_flush_request; struct cam_req_mgr_link_evt_data; +struct cam_req_mgr_dump_info; #define SKIP_NEXT_FRAME 0x100 @@ -49,6 +50,7 @@ typedef int (*cam_req_mgr_notify_stop)(struct cam_req_mgr_notify_stop *); * @cam_req_mgr_apply_req : CRM asks device to apply certain request id. * @cam_req_mgr_flush_req : Flush or cancel request * cam_req_mgr_process_evt : generic events + * @cam_req_mgr_dump_req : dump request */ typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *); typedef int (*cam_req_mgr_link_setup)( @@ -56,6 +58,7 @@ typedef int (*cam_req_mgr_link_setup)( typedef int (*cam_req_mgr_apply_req)(struct cam_req_mgr_apply_request *); typedef int (*cam_req_mgr_flush_req)(struct cam_req_mgr_flush_request *); typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *); +typedef int (*cam_req_mgr_dump_req)(struct cam_req_mgr_dump_info *); /** * @brief : cam_req_mgr_crm_cb - func table @@ -81,6 +84,7 @@ struct cam_req_mgr_crm_cb { * @apply_req : payload to apply request id on a device linked * @flush_req : payload to flush request * @process_evt : payload to generic event + * @dump_req : payload to dump request */ struct cam_req_mgr_kmd_ops { cam_req_mgr_get_dev_info get_dev_info; @@ -88,6 +92,7 @@ struct cam_req_mgr_kmd_ops { cam_req_mgr_apply_req apply_req; cam_req_mgr_flush_req flush_req; cam_req_mgr_process_evt process_evt; + cam_req_mgr_dump_req dump_req; }; /** @@ -366,4 +371,23 @@ struct cam_req_mgr_send_request { int32_t link_hdl; struct cam_req_mgr_req_queue *in_q; }; + +/** + * struct cam_req_mgr_dump_info + * @req_id : request id to dump + * @offset : offset of buffer + * @error_type : error type + * @buf_handle : buf handle + * @link_hdl : link identifier + * @dev_hdl : device handle for cross check + * + */ +struct cam_req_mgr_dump_info { + uint64_t req_id; + size_t offset; + uint32_t error_type; + uint32_t buf_handle; + int32_t link_hdl; + int32_t dev_hdl; +}; #endif diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index ce73b79f9590..9883517d74e0 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -26,6 +26,7 @@ #define CAM_COMMON_OPCODE_BASE_v2 0x150 #define CAM_ACQUIRE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x1) #define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2) +#define CAM_DUMP_REQ (CAM_COMMON_OPCODE_BASE_v2 + 0x3) #define CAM_EXT_OPCODE_BASE 0x200 #define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) @@ -856,5 +857,26 @@ struct cam_reg_dump_input_info { uint32_t dump_set_offsets[1]; }; +/** + * struct cam_dump_req_cmd - + * Dump the information of issue req id + * + * @issue_req_id : Issue Request Id + * @offset : Offset for the buffer + * @buf_handle : Buffer Handle + * @error_type : Error type, using it, dumping information can be extended + * @session_handle : Session Handle + * @link_hdl : link handle + * @dev_handle : Device Handle + */ +struct cam_dump_req_cmd { + uint64_t issue_req_id; + size_t offset; + uint32_t buf_handle; + uint32_t error_type; + int32_t session_handle; + int32_t link_hdl; + int32_t dev_handle; +}; #endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 88e5d3d4f698..45f5fdcd0ad2 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -260,6 +260,8 @@ struct cam_req_mgr_link_control { #define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) #define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) #define CAM_REQ_MGR_LINK_V2 (CAM_COMMON_OPCODE_MAX + 14) +#define CAM_REQ_MGR_REQUEST_DUMP (CAM_COMMON_OPCODE_MAX + 15) + /* end of cam_req_mgr opcodes */ #define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) -- GitLab From 299c1a13eee0347530646c719092570bfcf7b867 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 6 Jan 2020 15:11:49 -0800 Subject: [PATCH 205/410] msm: camera: custom: Disable overflow recovery This change disables overflow recovery/detection for custom CSID. Currently for QCOM CSID we enable overflow detection and freeze on overflow. But for custom HW the CSID needs to be free running, custom HW will take care of handling any backpressure from IFE pipeline/DDR. There is no need to backpressure to CSID in case of custom HW. CRs-Fixed: 2524308 Change-Id: I5de62eea0e87674d7ac24bb5ad2f11ff2a5a6b7c Signed-off-by: Karthik Anantha Ram --- .../cam_custom_csid/cam_custom_csid480.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h index a55bb002ffc2..da98ebf104c7 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CUSTOM_CSID_480_H_ @@ -56,7 +56,7 @@ static struct cam_ife_csid_udi_reg_offset .csid_udi_byte_cntr_pong_addr = 0x2e4, /* configurations */ .ccif_violation_en = 1, - .overflow_ctrl_en = 1, + .overflow_ctrl_en = 0, }; static struct cam_ife_csid_udi_reg_offset @@ -105,7 +105,7 @@ static struct cam_ife_csid_udi_reg_offset .csid_udi_byte_cntr_pong_addr = 0x3e4, /* configurations */ .ccif_violation_en = 1, - .overflow_ctrl_en = 1, + .overflow_ctrl_en = 0, }; static struct cam_ife_csid_udi_reg_offset @@ -155,7 +155,7 @@ static struct cam_ife_csid_udi_reg_offset .csid_udi_byte_cntr_pong_addr = 0x4e4, /* configurations */ .ccif_violation_en = 1, - .overflow_ctrl_en = 1, + .overflow_ctrl_en = 0, }; static struct cam_ife_csid_csi2_rx_reg_offset -- GitLab From 88b74d636be8f3a0db22a436a854e3e8193bb17e Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 14 Oct 2019 17:09:54 +0530 Subject: [PATCH 206/410] msm: camera: isp: LDAR Dump ISP information When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. In order to debug the cause for this situation and to dump the information, user space sends a dump command to the kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and dumps the relevant information in the buffer. This data is written to a file for offline processing. This commit dumps the IFE, CSID registers, LUT tables and context information, cmd buffers, timestamps information for submit, apply, RUP, epoch and buffdones of the last 20 requests. CRs-Fixed: 2602180 Change-Id: If83db59458c1e5ad778f3fa90cbc730122491c54 Signed-off-by: Gaurav Jindal --- drivers/cam_cdm/cam_cdm_util.c | 170 ++++++- drivers/cam_cdm/cam_cdm_util.h | 45 +- drivers/cam_isp/cam_isp_context.c | 446 +++++++++++++++++- drivers/cam_isp/cam_isp_context.h | 70 +++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 165 ++++++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 67 +++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 39 ++ .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 3 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 29 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 29 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 29 +- .../vfe_hw/vfe_top/cam_vfe_top_common.h | 30 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 142 +++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h | 3 +- drivers/cam_utils/cam_soc_util.c | 294 +++++++++++- drivers/cam_utils/cam_soc_util.h | 59 ++- 16 files changed, 1570 insertions(+), 50 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_util.c b/drivers/cam_cdm/cam_cdm_util.c index 278dadb18db4..9f440b778c17 100644 --- a/drivers/cam_cdm/cam_cdm_util.c +++ b/drivers/cam_cdm/cam_cdm_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -715,3 +715,171 @@ void cam_cdm_util_dump_cmd_buf( } } while (buf_now <= cmd_buf_end); } + +static uint32_t cam_cdm_util_dump_reg_cont_cmd_v2( + uint32_t *cmd_buf_addr, + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + int i; + long ret; + uint8_t *dst; + size_t remain_len; + uint32_t *temp_ptr = cmd_buf_addr; + uint32_t *addr, *start; + uint32_t min_len; + struct cdm_regcontinuous_cmd *p_regcont_cmd; + struct cam_cdm_cmd_dump_header *hdr; + + p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr; + temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + + min_len = (sizeof(uint32_t) * p_regcont_cmd->count) + + sizeof(struct cam_cdm_cmd_dump_header) + + (2 * sizeof(uint32_t)); + remain_len = dump_info->dst_max_size - dump_info->dst_offset; + + if (remain_len < min_len) { + CAM_WARN_RATE_LIMIT(CAM_CDM, + "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return ret; + } + + dst = (char *)dump_info->dst_start + dump_info->dst_offset; + hdr = (struct cam_cdm_cmd_dump_header *)dst; + scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_CONT:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header)); + start = addr; + *addr++ = p_regcont_cmd->offset; + *addr++ = p_regcont_cmd->count; + for (i = 0; i < p_regcont_cmd->count; i++) { + *addr = *temp_ptr; + temp_ptr++; + addr++; + ret++; + } + hdr->size = hdr->word_size * (addr - start); + dump_info->dst_offset += hdr->size + + sizeof(struct cam_cdm_cmd_dump_header); + + return ret; +} + +static uint32_t cam_cdm_util_dump_reg_random_cmd_v2( + uint32_t *cmd_buf_addr, + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + int i; + long ret; + uint8_t *dst; + uint32_t *temp_ptr = cmd_buf_addr; + uint32_t *addr, *start; + size_t remain_len; + uint32_t min_len; + struct cdm_regrandom_cmd *p_regrand_cmd; + struct cam_cdm_cmd_dump_header *hdr; + + p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr; + temp_ptr += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + ret = cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + + min_len = (2 * sizeof(uint32_t) * p_regrand_cmd->count) + + sizeof(struct cam_cdm_cmd_dump_header) + sizeof(uint32_t); + remain_len = dump_info->dst_max_size - dump_info->dst_offset; + + if (remain_len < min_len) { + CAM_WARN_RATE_LIMIT(CAM_CDM, + "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return ret; + } + + dst = (char *)dump_info->dst_start + dump_info->dst_offset; + hdr = (struct cam_cdm_cmd_dump_header *)dst; + scnprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_RANDOM:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header)); + start = addr; + *addr++ = p_regrand_cmd->count; + for (i = 0; i < p_regrand_cmd->count; i++) { + addr[0] = temp_ptr[0] & CAM_CDM_REG_OFFSET_MASK; + addr[1] = temp_ptr[1]; + temp_ptr += 2; + addr += 2; + ret += 2; + } + hdr->size = hdr->word_size * (addr - start); + dump_info->dst_offset += hdr->size + + sizeof(struct cam_cdm_cmd_dump_header); + return ret; +} + +int cam_cdm_util_dump_cmd_bufs_v2( + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + uint32_t cmd; + uint32_t *buf_now; + int rc = 0; + + if (!dump_info || !dump_info->src_start || !dump_info->src_end || + !dump_info->dst_start) { + CAM_INFO(CAM_CDM, "Invalid args"); + return -EINVAL; + } + + buf_now = dump_info->src_start; + do { + if (dump_info->dst_offset >= dump_info->dst_max_size) { + CAM_WARN(CAM_CDM, + "Dump overshoot offset %zu size %zu", + dump_info->dst_offset, + dump_info->dst_max_size); + return -ENOSPC; + } + cmd = *buf_now; + cmd = cmd >> CAM_CDM_COMMAND_OFFSET; + + switch (cmd) { + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_DMI_32: + case CAM_CDM_CMD_DMI_64: + buf_now += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); + break; + case CAM_CDM_CMD_REG_CONT: + buf_now += cam_cdm_util_dump_reg_cont_cmd_v2(buf_now, + dump_info); + break; + case CAM_CDM_CMD_REG_RANDOM: + buf_now += cam_cdm_util_dump_reg_random_cmd_v2(buf_now, + dump_info); + break; + case CAM_CDM_CMD_BUFF_INDIRECT: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_BUFF_INDIRECT); + break; + case CAM_CDM_CMD_GEN_IRQ: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_GEN_IRQ); + break; + case CAM_CDM_CMD_WAIT_EVENT: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_WAIT_EVENT); + break; + case CAM_CDM_CMD_CHANGE_BASE: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_CHANGE_BASE); + break; + case CAM_CDM_CMD_PERF_CTRL: + buf_now += cdm_get_cmd_header_size( + CAM_CDM_CMD_PERF_CTRL); + break; + default: + CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x", cmd); + buf_now++; + break; + } + } while (buf_now <= dump_info->src_end); + return rc; +} diff --git a/drivers/cam_cdm/cam_cdm_util.h b/drivers/cam_cdm/cam_cdm_util.h index 663eca92a5fe..30fcbe5c6c66 100644 --- a/drivers/cam_cdm/cam_cdm_util.h +++ b/drivers/cam_cdm/cam_cdm_util.h @@ -1,11 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_UTIL_H_ #define _CAM_CDM_UTIL_H_ +/* Max len for tag name for header while dumping cmd buffer*/ +#define CAM_CDM_CMD_TAG_MAX_LEN 32 + enum cam_cdm_command { CAM_CDM_CMD_UNUSED = 0x0, CAM_CDM_CMD_DMI = 0x1, @@ -144,6 +147,34 @@ void (*cdm_write_genirq)( uint32_t userdata); }; +/** + * struct cam_cdm_cmd_buf_dump_info; - Camera CDM dump info + * @dst_offset: dst offset + * @dst_max_size max size of destination buffer + * @src_start: source start address + * @src_end: source end address + * @dst_start: dst start address + */ +struct cam_cdm_cmd_buf_dump_info { + size_t dst_offset; + size_t dst_max_size; + uint32_t *src_start; + uint32_t *src_end; + uintptr_t dst_start; +}; + +/** + * struct cam_cdm_cmd_dump_header- Camera CDM dump header + * @tag: tag name for header + * @size: size of data + * @word_size: size of each word + */ +struct cam_cdm_cmd_dump_header { + uint8_t tag[CAM_CDM_CMD_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + /** * cam_cdm_util_log_cmd_bufs() * @@ -156,6 +187,18 @@ void (*cdm_write_genirq)( void cam_cdm_util_dump_cmd_buf( uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end); +/** + * cam_cdm_util_dump_cmd_bufs_v2() + * + * @brief: Util function to cdm command buffers + * to a buffer + * + * @dump_info: Information about source and destination buffers + * + * return SUCCESS/FAILURE + */ +int cam_cdm_util_dump_cmd_bufs_v2( + struct cam_cdm_cmd_buf_dump_info *dump_info); #endif /* _CAM_CDM_UTIL_H_ */ diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 89209b8d33a3..372af656cd71 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -24,9 +24,9 @@ static const char isp_dev_name[] = "cam-isp"; static struct cam_isp_ctx_debug isp_ctx_debug; -#define INC_STATE_MONITOR_HEAD(head, ret) \ +#define INC_HEAD(head, max_entries, ret) \ div_u64_rem(atomic64_add_return(1, head),\ - CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, (ret)) + max_entries, (ret)) static int cam_isp_context_dump_active_request(void *data, unsigned long iova, uint32_t buf_info); @@ -34,6 +34,150 @@ static int cam_isp_context_dump_active_request(void *data, unsigned long iova, static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); +static const char *__cam_isp_evt_val_to_type( + uint32_t evt_id) +{ + switch (evt_id) { + case CAM_ISP_CTX_EVENT_SUBMIT: + return "SUBMIT"; + case CAM_ISP_CTX_EVENT_APPLY: + return "APPLY"; + case CAM_ISP_CTX_EVENT_EPOCH: + return "EPOCH"; + case CAM_ISP_CTX_EVENT_RUP: + return "RUP"; + case CAM_ISP_CTX_EVENT_BUFDONE: + return "BUFDONE"; + default: + return "CAM_ISP_EVENT_INVALID"; + } +} + +static void __cam_isp_ctx_update_event_record( + struct cam_isp_context *ctx_isp, + enum cam_isp_ctx_event event, + struct cam_ctx_request *req) +{ + int iterator = 0; + ktime_t cur_time; + struct cam_isp_ctx_req *req_isp; + + if (!ctx_isp) { + CAM_ERR(CAM_ISP, "Invalid Args"); + return; + } + switch (event) { + case CAM_ISP_CTX_EVENT_EPOCH: + case CAM_ISP_CTX_EVENT_RUP: + case CAM_ISP_CTX_EVENT_BUFDONE: + break; + case CAM_ISP_CTX_EVENT_SUBMIT: + case CAM_ISP_CTX_EVENT_APPLY: + if (!req) { + CAM_ERR(CAM_ISP, "Invalid arg for event %d", event); + return; + } + break; + default: + break; + } + + INC_HEAD(&ctx_isp->event_record_head[event], + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES, &iterator); + cur_time = ktime_get(); + if (req) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + ctx_isp->event_record[event][iterator].req_id = + req->request_id; + req_isp->event_timestamp[event] = cur_time; + } else { + ctx_isp->event_record[event][iterator].req_id = 0; + } + ctx_isp->event_record[event][iterator].timestamp = cur_time; +} + +static int __cam_isp_ctx_dump_event_record( + struct cam_isp_context *ctx_isp, + uintptr_t cpu_addr, + size_t buf_len, + size_t *offset) +{ + int i, j; + int index; + size_t remain_len; + uint8_t *dst; + uint32_t oldest_entry, num_entries; + uint32_t min_len; + uint64_t *addr, *start; + uint64_t state_head; + struct timespec64 ts; + struct cam_isp_context_dump_header *hdr; + struct cam_isp_context_event_record *record; + + if (!cpu_addr || !buf_len || !offset || !ctx_isp) { + CAM_ERR(CAM_ISP, "Invalid args %pK %zu %pK %pK", + cpu_addr, buf_len, offset, ctx_isp); + return -EINVAL; + } + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) { + state_head = atomic64_read(&ctx_isp->event_record_head[i]); + + if (state_head == -1) { + return 0; + } else if (state_head < CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES) { + num_entries = state_head + 1; + oldest_entry = 0; + } else { + num_entries = CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES; + div_u64_rem(state_head + 1, + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES, + &oldest_entry); + } + index = oldest_entry; + + if (buf_len <= *offset) { + CAM_WARN(CAM_ISP, + "Dump buffer overshoot len %zu offset %zu", + buf_len, *offset); + return -ENOSPC; + } + + min_len = sizeof(struct cam_isp_context_dump_header) + + ((num_entries * CAM_ISP_CTX_DUMP_EVENT_NUM_WORDS) * + sizeof(uint64_t)); + remain_len = buf_len - *offset; + + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, + "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + dst = (uint8_t *)cpu_addr + *offset; + hdr = (struct cam_isp_context_dump_header *)dst; + scnprintf(hdr->tag, + CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, "ISP_EVT_%s:", + __cam_isp_evt_val_to_type(i)); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + + sizeof(struct cam_isp_context_dump_header)); + start = addr; + for (j = 0; j < num_entries; j++) { + record = &ctx_isp->event_record[i][index]; + ts = ktime_to_timespec64(record->timestamp); + *addr++ = record->req_id; + *addr++ = ts.tv_sec; + *addr++ = ts.tv_nsec/NSEC_PER_USEC; + index = (index + 1) % + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES; + } + hdr->size = hdr->word_size * (addr - start); + *offset += hdr->size + + sizeof(struct cam_isp_context_dump_header); + } + return 0; +} + static void __cam_isp_ctx_update_state_monitor_array( struct cam_isp_context *ctx_isp, enum cam_isp_state_change_trigger trigger_type, @@ -41,7 +185,8 @@ static void __cam_isp_ctx_update_state_monitor_array( { int iterator; - INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head, &iterator); + INC_HEAD(&ctx_isp->state_monitor_head, + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, &iterator); ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state = ctx_isp->substate_activated; @@ -162,13 +307,19 @@ static int cam_isp_context_info_dump(void *context, return 0; } -static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) +static int cam_isp_ctx_dump_req( + struct cam_isp_ctx_req *req_isp, + uintptr_t cpu_addr, + size_t buf_len, + size_t *offset, + bool dump_to_buff) { int i = 0, rc = 0; size_t len = 0; uint32_t *buf_addr; uint32_t *buf_start, *buf_end; size_t remain_len = 0; + struct cam_cdm_cmd_buf_dump_info dump_info; for (i = 0; i < req_isp->num_cfg; i++) { rc = cam_packet_util_get_cmd_mem_addr( @@ -182,7 +333,7 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) CAM_ERR(CAM_ISP, "Invalid offset exp %u actual %u", req_isp->cfg[i].offset, (uint32_t)len); - return; + return rc; } remain_len = len - req_isp->cfg[i].offset; @@ -192,16 +343,33 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) "Invalid len exp %u remain_len %u", req_isp->cfg[i].len, (uint32_t)remain_len); - return; + return rc; } buf_start = (uint32_t *)((uint8_t *) buf_addr + req_isp->cfg[i].offset); buf_end = (uint32_t *)((uint8_t *) buf_start + req_isp->cfg[i].len - 1); - cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + if (dump_to_buff) { + if (!cpu_addr || !offset || !buf_len) { + CAM_ERR(CAM_ISP, "Invalid args"); + break; + } + dump_info.src_start = buf_start; + dump_info.src_end = buf_end; + dump_info.dst_start = cpu_addr; + dump_info.dst_offset = *offset; + dump_info.dst_max_size = buf_len; + rc = cam_cdm_util_dump_cmd_bufs_v2(&dump_info); + *offset = dump_info.dst_offset; + if (rc) + return rc; + } else { + cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + } } } + return rc; } static int __cam_isp_ctx_enqueue_request_in_order( @@ -210,6 +378,7 @@ static int __cam_isp_ctx_enqueue_request_in_order( struct cam_ctx_request *req_current; struct cam_ctx_request *req_prev; struct list_head temp_list; + struct cam_isp_context *ctx_isp; INIT_LIST_HEAD(&temp_list); spin_lock_bh(&ctx->lock); @@ -240,6 +409,9 @@ static int __cam_isp_ctx_enqueue_request_in_order( } } } + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_SUBMIT, req); spin_unlock_bh(&ctx->lock); return 0; } @@ -724,6 +896,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request( __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_BUFDONE, req); return rc; } @@ -832,6 +1006,8 @@ static int __cam_isp_ctx_reg_upd_in_applied_state( CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, req); } else { /* no io config, so the request is completed. */ list_add_tail(&req->list, &ctx->free_req_list); @@ -939,6 +1115,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( if (req->request_id > ctx_isp->reported_req_id) { request_id = req->request_id; ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); break; } } @@ -1112,7 +1290,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, /* Send SOF event as empty frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); goto end; } @@ -1157,7 +1336,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, } __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( @@ -1284,6 +1464,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; goto end; @@ -1330,13 +1512,21 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( ctx_isp->reported_req_id = request_id; __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); - } else + + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); + } else { __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - } else + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); + } + } else { __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); + } ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( @@ -1426,7 +1616,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv; if (error_event_data->enable_req_dump) - cam_isp_ctx_dump_req(req_isp); + rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id); @@ -2093,6 +2283,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, req->request_id); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_APPLY, req); } end: return rc; @@ -2170,6 +2362,200 @@ static int __cam_isp_ctx_apply_req_in_bubble( return rc; } +static int __cam_isp_ctx_dump_req_info( + struct cam_context *ctx, + struct cam_ctx_request *req, + uintptr_t cpu_addr, + size_t buf_len, + size_t *offset) +{ + int i, rc; + uint8_t *dst; + int32_t *addr, *start; + uint32_t min_len; + size_t remain_len; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_context *ctx_isp; + struct cam_isp_context_dump_header *hdr; + + if (!req || !ctx || !offset || !cpu_addr || !buf_len) { + CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK %pK %zu", + req, ctx, offset, buf_len); + return -EINVAL; + } + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + ctx_isp = (struct cam_isp_context *)ctx->ctx_priv; + + if (buf_len <= *offset) { + CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu", + buf_len, *offset); + return -ENOSPC; + } + + remain_len = buf_len - *offset; + min_len = sizeof(struct cam_isp_context_dump_header) + + (CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS * + req_isp->num_fence_map_out * + sizeof(int32_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + dst = (uint8_t *)cpu_addr + *offset; + hdr = (struct cam_isp_context_dump_header *)dst; + hdr->word_size = sizeof(int32_t); + scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, + "ISP_OUT_FENCE:"); + addr = (int32_t *)(dst + sizeof(struct cam_isp_context_dump_header)); + start = addr; + for (i = 0; i < req_isp->num_fence_map_out; i++) { + *addr++ = req_isp->fence_map_out[i].resource_handle; + *addr++ = req_isp->fence_map_out[i].sync_id; + } + hdr->size = hdr->word_size * (addr - start); + *offset += hdr->size + sizeof(struct cam_isp_context_dump_header); + rc = cam_isp_ctx_dump_req(req_isp, cpu_addr, buf_len, + offset, true); + return rc; +} + +static int __cam_isp_ctx_dump_in_top_state( + struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump_info) +{ + int rc = 0; + bool dump_only_event_record = false; + size_t buf_len; + size_t remain_len; + uint8_t *dst; + ktime_t cur_time; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + uintptr_t cpu_addr; + struct timespec64 ts; + struct cam_isp_context *ctx_isp; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_ctx_request *req_temp; + struct cam_hw_dump_args dump_args; + struct cam_isp_context_dump_header *hdr; + + spin_lock_bh(&ctx->lock); + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + if (req->request_id == dump_info->req_id) { + CAM_INFO(CAM_ISP, "isp dump active list req: %lld", + dump_info->req_id); + goto hw_dump; + } + } + list_for_each_entry_safe(req, req_temp, + &ctx->wait_req_list, list) { + if (req->request_id == dump_info->req_id) { + CAM_INFO(CAM_ISP, "isp dump wait list req: %lld", + dump_info->req_id); + goto hw_dump; + } + } + spin_unlock_bh(&ctx->lock); + return rc; +hw_dump: + rc = cam_mem_get_cpu_buf(dump_info->buf_handle, + &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_ISP, "Invalid handle %u rc %d", + dump_info->buf_handle, rc); + spin_unlock_bh(&ctx->lock); + return rc; + } + if (buf_len <= dump_info->offset) { + spin_unlock_bh(&ctx->lock); + CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu", + buf_len, dump_info->offset); + return -ENOSPC; + } + + remain_len = buf_len - dump_info->offset; + min_len = sizeof(struct cam_isp_context_dump_header) + + (CAM_ISP_CTX_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + spin_unlock_bh(&ctx->lock); + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + cur_time = ktime_get(); + diff = ktime_us_delta( + req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY], + cur_time); + if (diff < CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_ISP, "req %lld found no error", + req->request_id); + dump_only_event_record = true; + } + dst = (uint8_t *)cpu_addr + dump_info->offset; + hdr = (struct cam_isp_context_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, + "ISP_CTX_DUMP:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + + sizeof(struct cam_isp_context_dump_header)); + start = addr; + *addr++ = req->request_id; + ts = ktime_to_timespec64( + req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]); + *addr++ = ts.tv_sec; + *addr++ = ts.tv_nsec/NSEC_PER_USEC; + ts = ktime_to_timespec64(cur_time); + *addr++ = ts.tv_sec; + *addr++ = ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_info->offset += hdr->size + + sizeof(struct cam_isp_context_dump_header); + + rc = __cam_isp_ctx_dump_event_record(ctx_isp, cpu_addr, + buf_len, &dump_info->offset); + if (rc) { + CAM_ERR(CAM_ISP, "Dump event fail %lld", + req->request_id); + spin_unlock_bh(&ctx->lock); + return rc; + } + if (dump_only_event_record) { + spin_unlock_bh(&ctx->lock); + return rc; + } + rc = __cam_isp_ctx_dump_req_info(ctx, req, cpu_addr, + buf_len, &dump_info->offset); + if (rc) { + CAM_ERR(CAM_ISP, "Dump Req info fail %lld", + req->request_id); + spin_unlock_bh(&ctx->lock); + return rc; + } + spin_unlock_bh(&ctx->lock); + + if (ctx->hw_mgr_intf->hw_dump) { + dump_args.offset = dump_info->offset; + dump_args.request_id = dump_info->req_id; + dump_args.buf_handle = dump_info->buf_handle; + dump_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + rc = ctx->hw_mgr_intf->hw_dump( + ctx->hw_mgr_intf->hw_mgr_priv, + &dump_args); + dump_info->offset = dump_args.offset; + } + return rc; +} + static int __cam_isp_ctx_flush_req(struct cam_context *ctx, struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req) { @@ -2788,12 +3174,15 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( CAM_DBG(CAM_ISP, "next Substate[%s]", __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, req); return 0; error: /* Send SOF event as idle frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, NULL); /* * There is no request in the pending list, move the sub state machine @@ -2953,6 +3342,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; + int i; if (ctx_isp->hw_ctx) { rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; @@ -2975,6 +3365,8 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); /* * Ideally, we should never have any active request here. * But we still add some sanity check code here to help the debug @@ -3004,6 +3396,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, struct cam_release_dev_cmd *cmd) { int rc = 0; + int i; struct cam_hw_release_args rel_arg; struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; @@ -3035,7 +3428,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); - + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); /* * Ideally, we should never have any active request here. * But we still add some sanity check code here to help the debug @@ -3260,6 +3654,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) { int rc = 0; + int i; struct cam_hw_acquire_args param; struct cam_isp_resource *isp_res = NULL; struct cam_create_dev_hdl req_hdl_param; @@ -3372,6 +3767,8 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); kfree(isp_res); isp_res = NULL; @@ -3422,6 +3819,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, void *args) { int rc = 0; + int i; struct cam_acquire_hw_cmd_v1 *cmd = (struct cam_acquire_hw_cmd_v1 *)args; struct cam_hw_acquire_args param; @@ -3527,6 +3925,9 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); + trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", @@ -3842,6 +4243,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; + int i; struct cam_isp_start_args start_isp; struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; @@ -3898,6 +4300,9 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); + /* * In case of CSID TPG we might receive SOF and RUP IRQs * before hw_mgr_intf->hw_start has returned. So move @@ -3928,7 +4333,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, ctx->state = CAM_CTX_READY; trace_cam_context_state("ISP", ctx); if (rc == -ETIMEDOUT) - cam_isp_ctx_dump_req(req_isp); + rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); goto end; @@ -4057,6 +4462,9 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( atomic_set(&ctx_isp->process_bubble, 0); atomic64_set(&ctx_isp->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx_isp->event_record_head[i], -1); + CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", ctx->state, ctx->ctx_id); @@ -4313,6 +4721,7 @@ static struct cam_ctx_ops .unlink = __cam_isp_ctx_unlink_in_acquired, .get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired, .flush_req = __cam_isp_ctx_flush_req_in_top_state, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, @@ -4329,6 +4738,7 @@ static struct cam_ctx_ops .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_ready, .flush_req = __cam_isp_ctx_flush_req_in_ready, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, @@ -4363,6 +4773,7 @@ static struct cam_ctx_ops .apply_req = __cam_isp_ctx_apply_req, .flush_req = __cam_isp_ctx_flush_req_in_top_state, .process_evt = __cam_isp_ctx_process_evt, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = __cam_isp_ctx_handle_irq_in_activated, .pagefault_ops = cam_isp_context_dump_active_request, @@ -4546,6 +4957,9 @@ int cam_isp_context_init(struct cam_isp_context *ctx, } atomic64_set(&ctx->state_monitor_head, -1); + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) + atomic64_set(&ctx->event_record_head[i], -1); + cam_isp_context_debug_register(); err: return rc; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index fd1977c52dca..d91f5eea02e9 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -36,6 +36,27 @@ */ #define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES 40 +/* + * Threshold response time in us beyond which a request is not expected + * to be with IFE hw + */ +#define CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD 100000 + +/* Number of words for dumping isp context */ +#define CAM_ISP_CTX_DUMP_NUM_WORDS 5 + +/* Number of words for dumping isp context events*/ +#define CAM_ISP_CTX_DUMP_EVENT_NUM_WORDS 3 + +/* Number of words for dumping request info*/ +#define CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS 2 + +/* Maximum entries in event record */ +#define CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES 20 + +/* Maximum length of tag while dumping */ +#define CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN 32 + /* forward declaration */ struct cam_isp_context; @@ -58,6 +79,19 @@ enum cam_isp_ctx_activated_substate { CAM_ISP_CTX_ACTIVATED_MAX, }; +/** + * enum cam_isp_ctx_event_type - events for a request + * + */ +enum cam_isp_ctx_event { + CAM_ISP_CTX_EVENT_SUBMIT, + CAM_ISP_CTX_EVENT_APPLY, + CAM_ISP_CTX_EVENT_EPOCH, + CAM_ISP_CTX_EVENT_RUP, + CAM_ISP_CTX_EVENT_BUFDONE, + CAM_ISP_CTX_EVENT_MAX +}; + /** * enum cam_isp_state_change_trigger - Different types of ISP events * @@ -112,6 +146,7 @@ struct cam_isp_ctx_irq_ops { * @bubble_report: Flag to track if bubble report is active on * current request * @hw_update_data: HW update data for this request + * @event_timestamp: Timestamp for different stage of request * @reapply: True if reapplying after bubble * */ @@ -128,6 +163,8 @@ struct cam_isp_ctx_req { uint32_t num_acked; int32_t bubble_report; struct cam_isp_prepare_hw_update_data hw_update_data; + ktime_t event_timestamp + [CAM_ISP_CTX_EVENT_MAX]; bool bubble_detected; bool reapply; }; @@ -163,8 +200,22 @@ struct cam_isp_context_state_monitor { struct cam_isp_context_req_id_info { int64_t last_bufdone_req_id; }; + /** * + * struct cam_isp_context_event_record - Information for last 20 Events + * for a request; Submit, Apply, EPOCH, RUP, Buf done. + * + * @req_id: Last applied request id + * @timestamp: Timestamp for the event + * + */ +struct cam_isp_context_event_record { + uint64_t req_id; + ktime_t timestamp; +}; + +/** * struct cam_isp_context - ISP context object * * @base: Common context object pointer @@ -190,6 +241,8 @@ struct cam_isp_context_req_id_info { * @state_monitor_head: Write index to the state monitoring array * @req_info Request id information about last buf done * @cam_isp_ctx_state_monitor: State monitoring array + * @event_record_head: Write index to the state monitoring array + * @event_record: Event record array * @rdi_only_context: Get context type information. * true, if context is rdi only context * @hw_acquired: Indicate whether HW resources are acquired @@ -225,6 +278,10 @@ struct cam_isp_context { struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; struct cam_isp_context_req_id_info req_info; + atomic64_t event_record_head[ + CAM_ISP_CTX_EVENT_MAX]; + struct cam_isp_context_event_record event_record[ + CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES]; bool rdi_only_context; bool hw_acquired; bool init_received; @@ -234,6 +291,19 @@ struct cam_isp_context { unsigned int init_timestamp; }; +/** + * struct cam_isp_context_dump_header - ISP context dump header + * @tag: Tag name for the header + * @word_size: Size of word + * @size: Size of data + * + */ +struct cam_isp_context_dump_header { + uint8_t tag[CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + /** * cam_isp_context_init() * diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 4c3479c5190d..dd9c6dd4c057 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -134,7 +134,9 @@ static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, struct cam_cmd_buf_desc *reg_dump_buf_desc, uint32_t num_reg_dump_buf, - uint32_t meta_type) + uint32_t meta_type, + void *soc_dump_args, + bool user_triggered_dump) { int rc = 0, i; @@ -157,7 +159,9 @@ static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, ®_dump_buf_desc[i], ctx->applied_req_id, - cam_ife_mgr_regspace_data_cb); + cam_ife_mgr_regspace_data_cb, + soc_dump_args, + user_triggered_dump); if (rc) { CAM_ERR(CAM_ISP, "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u", @@ -2478,7 +2482,8 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, cam_ife_mgr_handle_reg_dump(ctx, hw_update_data->reg_dump_buf_desc, hw_update_data->num_reg_dump_buf, - CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST); + CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST, + NULL, false); CAM_DBG(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", @@ -6024,7 +6029,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) ctx->last_dump_flush_req_id = ctx->applied_req_id; rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, ctx->num_reg_dump_buf, - CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH); + CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH, NULL, false); if (rc) { CAM_ERR(CAM_ISP, "Reg dump on flush failed req id: %llu rc: %d", @@ -6040,7 +6045,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) ctx->last_dump_err_req_id = ctx->applied_req_id; rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, ctx->num_reg_dump_buf, - CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR); + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR, NULL, false); if (rc) { CAM_ERR(CAM_ISP, "Reg dump on error failed req id: %llu rc: %d", @@ -6059,6 +6064,155 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) return rc; } +static int cam_ife_mgr_user_dump_hw( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_hw_dump_args *dump_args) +{ + int rc = 0; + struct cam_hw_soc_dump_args soc_dump_args; + + if (!ife_ctx || !dump_args) { + CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK", + ife_ctx, dump_args); + rc = -EINVAL; + goto end; + } + soc_dump_args.buf_handle = dump_args->buf_handle; + soc_dump_args.request_id = dump_args->request_id; + soc_dump_args.offset = dump_args->offset; + + rc = cam_ife_mgr_handle_reg_dump(ife_ctx, + ife_ctx->reg_dump_buf_desc, + ife_ctx->num_reg_dump_buf, + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR, + &soc_dump_args, + true); + if (rc) { + CAM_ERR(CAM_ISP, + "Dump failed req: %lld handle %u offset %u", + dump_args->request_id, + dump_args->buf_handle, + dump_args->offset); + goto end; + } + dump_args->offset = soc_dump_args.offset; +end: + return rc; +} + +static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args) +{ + struct cam_isp_hw_dump_args isp_hw_dump_args; + struct cam_hw_dump_args *dump_args = (struct cam_hw_dump_args *)args; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_ctx *ife_ctx = (struct cam_ife_hw_mgr_ctx *) + dump_args->ctxt_to_hw_map; + int i; + int rc = 0; + + /* for some targets, information about the IFE registers to be dumped + * is already submitted with the hw manager. In this case, we + * can dump just the related registers and skip going to core files. + */ + if (ife_ctx->num_reg_dump_buf) { + cam_ife_mgr_user_dump_hw(ife_ctx, dump_args); + goto end; + } + + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &isp_hw_dump_args.cpu_addr, + &isp_hw_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_ISP, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + + isp_hw_dump_args.offset = dump_args->offset; + isp_hw_dump_args.req_id = dump_args->request_id; + + list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (ife_ctx->is_rdi_only_context && + hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + case CAM_IFE_PIX_PATH_RES_IPP: + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + default: + CAM_DBG(CAM_ISP, "not a valid res %d", + hw_mgr_res->res_id); + break; + } + } + } + + list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + switch (hw_mgr_res->res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (ife_ctx->is_rdi_only_context && + hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + case CAM_ISP_HW_VFE_IN_CAMIF: + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + default: + CAM_DBG(CAM_ISP, "not a valid res %d", + hw_mgr_res->res_id); + break; + } + } + } + dump_args->offset = isp_hw_dump_args.offset; +end: + CAM_DBG(CAM_ISP, "offset %u", dump_args->offset); + return rc; +} + static int cam_ife_mgr_cmd_get_sof_timestamp( struct cam_ife_hw_mgr_ctx *ife_ctx, uint64_t *time_stamp, @@ -7053,6 +7207,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) hw_mgr_intf->hw_config = cam_ife_mgr_config_hw; hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd; hw_mgr_intf->hw_reset = cam_ife_mgr_reset; + hw_mgr_intf->hw_dump = cam_ife_mgr_dump; if (iommu_hdl) *iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 760334ef5f45..8051a601fd9d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -3798,6 +3798,70 @@ static int cam_ife_csid_set_csid_qcfa( return 0; } +static int cam_ife_csid_dump_hw( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + int i; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t min_len; + uint32_t num_reg; + size_t remain_len; + struct cam_isp_hw_dump_header *hdr; + struct cam_isp_hw_dump_args *dump_args = + (struct cam_isp_hw_dump_args *)cmd_args; + struct cam_hw_soc_info *soc_info; + + if (!dump_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + if (!dump_args->cpu_addr || !dump_args->buf_len) { + CAM_ERR(CAM_ISP, + "Invalid params %pK %zu", + (void *)dump_args->cpu_addr, + dump_args->buf_len); + return -EINVAL; + } + soc_info = &csid_hw->hw_info->soc_info; + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_ISP, + "Dump offset overshoot offset %zu buf_len %zu", + dump_args->offset, dump_args->buf_len); + return -ENOSPC; + } + min_len = soc_info->reg_map[0].size + + sizeof(struct cam_isp_hw_dump_header) + + sizeof(uint32_t); + remain_len = dump_args->buf_len - dump_args->offset; + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu, min %u", + remain_len, min_len); + return -ENOSPC; + } + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "CSID_REG:"); + addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header)); + + start = addr; + num_reg = soc_info->reg_map[0].size/4; + hdr->word_size = sizeof(uint32_t); + *addr = soc_info->index; + addr++; + for (i = 0; i < num_reg; i++) { + addr[0] = soc_info->mem_block[0]->start + (i*4); + addr[1] = cam_io_r(soc_info->reg_map[0].mem_base + + (i*4)); + addr += 2; + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset); + return 0; +} + static int cam_ife_csid_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -3835,6 +3899,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED: rc = cam_ife_csid_set_csid_qcfa(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_ife_csid_dump_hw(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index fe1159d4fc6a..13a1612dce7c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -13,6 +13,8 @@ #include "cam_irq_controller.h" #include "cam_hw_intf.h" +/* Maximum length of tag while dumping */ +#define CAM_ISP_HW_DUMP_TAG_MAX_LEN 32 /* * struct cam_isp_timestamp: * @@ -102,6 +104,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, + CAM_ISP_HW_CMD_DUMP_HW, CAM_ISP_HW_CMD_MAX, }; @@ -255,4 +258,40 @@ struct cam_isp_hw_dual_isp_update_args { struct cam_isp_resource_node *res; struct cam_isp_dual_config *dual_cfg; }; + +/* + * struct cam_isp_hw_dump_args: + * + * @Brief: isp hw dump args + * + * @ req_id: request id + * @ cpu_addr: cpu address + * @ buf_len: buf len + * @ offset: offset of buffer + * @ ctxt_to_hw_map: ctx to hw map + */ +struct cam_isp_hw_dump_args { + uint64_t req_id; + uintptr_t cpu_addr; + size_t buf_len; + size_t offset; + void *ctxt_to_hw_map; +}; + +/** + * struct cam_isp_hw_dump_header - ISP context dump header + * + * @Brief: isp hw dump header + * + * @tag: Tag name for the header + * @word_size: Size of word + * @size: Size of data + * + */ +struct cam_isp_hw_dump_header { + uint8_t tag[CAM_ISP_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + #endif /* _CAM_ISP_HW_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 11d6a602117c..cd32edbc0565 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -593,6 +593,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_BW_CONTROL: case CAM_ISP_HW_CMD_CORE_CONFIG: case CAM_ISP_HW_CMD_BW_UPDATE_V2: + case CAM_ISP_HW_CMD_DUMP_HW: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 663bc247b27f..63df625221cc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE170_H_ @@ -144,6 +144,32 @@ static struct cam_vfe_rdi_reg_data vfe_170_rdi_2_data = { .reg_update_irq_mask = 0x80, }; +struct cam_vfe_top_dump_data vfe170_dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1164, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x397C, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, +}; + static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .common_reg = &vfe170_top_common_reg, .camif_hw_info = { @@ -173,6 +199,7 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, }, + .dump_data = &vfe170_dump_data, }; static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index 6823b6386b91..4e9a1e232860 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE175_H_ @@ -178,6 +178,32 @@ static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { .reg_update_irq_mask = 0x80, }; +struct cam_vfe_top_dump_data vfe175_dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1164, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x397C, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, +}; + static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { .common_reg = &vfe175_top_common_reg, .camif_hw_info = { @@ -209,6 +235,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { CAM_VFE_RDI_VER_1_0, CAM_VFE_CAMIF_LITE_VER_2_0, }, + .dump_data = &vfe175_dump_data, }; static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 8acd77d1f1e2..1a80dc7f8f2e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE175_130_H_ @@ -226,6 +226,32 @@ static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_2_data = { .reg_update_irq_mask = 0x80, }; +struct cam_vfe_top_dump_data vfe175_130_dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1164, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x397C, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, +}; + static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { .common_reg = &vfe175_130_top_common_reg, .camif_hw_info = { @@ -263,6 +289,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { CAM_VFE_CAMIF_LITE_VER_2_0, CAM_VFE_IN_RD_VER_1_0, }, + .dump_data = &vfe175_130_dump_data, }; static struct cam_irq_register_set vfe175_130_bus_rd_irq_reg[1] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h index 03be713e6068..55607b6d886f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_TOP_COMMON_H_ @@ -13,6 +13,10 @@ #include "cam_vfe_hw_intf.h" #include "cam_vfe_soc.h" +#define CAM_VFE_TOP_MAX_REG_DUMP_ENTRIES 70 + +#define CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES 6 + struct cam_vfe_top_priv_common { struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_MUX_MAX]; uint32_t num_mux; @@ -26,6 +30,30 @@ struct cam_vfe_top_priv_common { enum cam_vfe_bw_control_action axi_vote_control[CAM_VFE_TOP_MUX_MAX]; }; +struct cam_vfe_top_reg_dump_entry { + uint32_t reg_dump_start; + uint32_t reg_dump_end; +}; + +struct cam_vfe_top_lut_dump_entry { + uint32_t lut_word_size; + uint32_t lut_bank_sel; + uint32_t lut_addr_size; +}; + +struct cam_vfe_top_dump_data { + uint32_t num_reg_dump_entries; + uint32_t num_lut_dump_entries; + uint32_t dmi_cfg; + uint32_t dmi_addr; + uint32_t dmi_data_path_hi; + uint32_t dmi_data_path_lo; + struct cam_vfe_top_reg_dump_entry + reg_entry[CAM_VFE_TOP_MAX_REG_DUMP_ENTRIES]; + struct cam_vfe_top_lut_dump_entry + lut_entry[CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES]; +}; + int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private, struct cam_vfe_top_priv_common *top_common, bool start_stop); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index c5225c540722..6774be8cda3d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -19,6 +19,7 @@ struct cam_vfe_top_ver2_common_data { struct cam_hw_soc_info *soc_info; struct cam_hw_intf *hw_intf; struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_top_dump_data *dump_data; }; struct cam_vfe_top_ver2_priv { @@ -184,6 +185,140 @@ int cam_vfe_top_get_hw_caps(void *device_priv, return -EPERM; } +static int cam_vfe_hw_dump( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, + uint32_t arg_size) +{ + int i, j; + uint8_t *dst; + uint32_t reg_start_offset; + uint32_t reg_dump_size = 0; + uint32_t lut_dump_size = 0; + uint32_t val; + uint32_t num_reg; + void __iomem *reg_base; + uint32_t *addr, *start; + size_t remain_len; + uint32_t min_len; + struct cam_hw_soc_info *soc_info; + struct cam_vfe_top_dump_data *dump_data; + struct cam_isp_hw_dump_header *hdr; + struct cam_isp_hw_dump_args *dump_args = + (struct cam_isp_hw_dump_args *)cmd_args; + + if (!dump_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + if (!dump_args->cpu_addr || !dump_args->buf_len) { + CAM_ERR(CAM_ISP, + "Invalid params %pK %zu", + (void *)dump_args->cpu_addr, + dump_args->buf_len); + return -EINVAL; + } + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_ISP, + "Dump offset overshoot offset %zu buf_len %zu", + dump_args->offset, dump_args->buf_len); + return -ENOSPC; + } + dump_data = top_priv->common_data.dump_data; + soc_info = top_priv->common_data.soc_info; + + /*Dump registers */ + for (i = 0; i < dump_data->num_reg_dump_entries; i++) + reg_dump_size += (dump_data->reg_entry[i].reg_dump_end - + dump_data->reg_entry[i].reg_dump_start); + /* + * We dump the offset as well, so the total size dumped becomes + * multiplied by 2 + */ + reg_dump_size *= 2; + for (i = 0; i < dump_data->num_lut_dump_entries; i++) + lut_dump_size += ((dump_data->lut_entry[i].lut_addr_size) * + (dump_data->lut_entry[i].lut_word_size/8)); + + /*Minimum len comprises of: + * soc_index + * lut_dump_size + reg_dump_size + sizeof dump_header + + * (num_lut_dump_entries--> represents number of banks) + */ + min_len = sizeof(uint32_t) + lut_dump_size + reg_dump_size + + sizeof(struct cam_isp_hw_dump_header) + + (dump_data->num_lut_dump_entries * sizeof(uint32_t)); + remain_len = dump_args->buf_len - dump_args->offset; + if (remain_len < min_len) { + CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu, min %u", + remain_len, min_len); + return -ENOSPC; + } + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + hdr->word_size = sizeof(uint32_t); + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "VFE_REG:"); + addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + for (i = 0; i < dump_data->num_reg_dump_entries; i++) { + num_reg = (dump_data->reg_entry[i].reg_dump_end - + dump_data->reg_entry[i].reg_dump_start)/4; + reg_start_offset = dump_data->reg_entry[i].reg_dump_start; + reg_base = soc_info->reg_map[0].mem_base + reg_start_offset; + for (j = 0; j < num_reg; j++) { + addr[0] = soc_info->mem_block[0]->start + + reg_start_offset + (j*4); + addr[1] = cam_io_r(reg_base + (j*4)); + addr += 2; + } + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + + /*dump LUT*/ + for (i = 0; i < dump_data->num_lut_dump_entries; i++) { + + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "LUT_REG:"); + hdr->word_size = dump_data->lut_entry[i].lut_word_size/8; + addr = (uint32_t *)(dst + + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = dump_data->lut_entry[i].lut_bank_sel; + val = 0x100 | dump_data->lut_entry[i].lut_bank_sel; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + dump_data->dmi_cfg); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + dump_data->dmi_addr); + for (j = 0; j < dump_data->lut_entry[i].lut_addr_size; + j++) { + if (dump_data->lut_entry[i].lut_word_size == 64) { + addr[0] = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_lo); + addr[1] = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_hi); + addr += 2; + } else { + *addr = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_lo); + addr++; + } + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + } + CAM_DBG(CAM_ISP, "offset %zu", dump_args->offset); + return 0; +} + int cam_vfe_top_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { @@ -505,6 +640,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_bw_control(soc_private, &top_priv->top_common, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_vfe_hw_dump(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); @@ -627,6 +766,7 @@ int cam_vfe_top_ver2_init( top_priv->common_data.hw_intf = hw_intf; top_priv->top_common.hw_idx = hw_intf->hw_idx; top_priv->common_data.common_reg = ver2_hw_info->common_reg; + top_priv->common_data.dump_data = ver2_hw_info->dump_data; return rc; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h index 961bf954aaa1..65d01da159ec 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_TOP_VER2_H_ @@ -49,6 +49,7 @@ struct cam_vfe_top_ver2_hw_info { struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; struct cam_vfe_fe_ver1_hw_info fe_hw_info; + struct cam_vfe_top_dump_data *dump_data; uint32_t num_mux; uint32_t mux_type[CAM_VFE_TOP_MUX_MAX]; }; diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 4e3dacaa822c..034733cada15 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include @@ -1998,9 +1998,268 @@ static int cam_soc_util_dump_dmi_reg_range( return rc; } +static int cam_soc_util_dump_dmi_reg_range_user_buf( + struct cam_hw_soc_info *soc_info, + struct cam_dmi_read_desc *dmi_read, uint32_t base_idx, + struct cam_hw_soc_dump_args *dump_args) +{ + int i; + int rc; + size_t buf_len = 0; + uint8_t *dst; + size_t remain_len; + uint32_t min_len; + uint32_t *waddr, *start; + uintptr_t cpu_addr; + struct cam_hw_soc_dump_header *hdr; + + if (!soc_info || !dump_args || !dmi_read) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_args: %pK", + soc_info, dump_args); + rc = -EINVAL; + goto end; + } + + if (dmi_read->num_pre_writes > CAM_REG_DUMP_DMI_CONFIG_MAX || + dmi_read->num_post_writes > CAM_REG_DUMP_DMI_CONFIG_MAX) { + CAM_ERR(CAM_UTIL, + "Invalid number of requested writes, pre: %d post: %d", + dmi_read->num_pre_writes, dmi_read->num_post_writes); + rc = -EINVAL; + goto end; + } + + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_UTIL, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + goto end; + } + + if (buf_len <= dump_args->offset) { + CAM_WARN(CAM_UTIL, "Dump offset overshoot offset %zu len %zu", + dump_args->offset, buf_len); + rc = -ENOSPC; + goto end; + } + remain_len = buf_len - dump_args->offset; + min_len = (dmi_read->num_pre_writes * 2 * sizeof(uint32_t)) + + (dmi_read->dmi_data_read.num_values * 2 * sizeof(uint32_t)) + + sizeof(uint32_t); + if (remain_len < min_len) { + CAM_WARN(CAM_UTIL, + "Dump Buffer exhaust read %d write %d remain %zu min %u", + dmi_read->dmi_data_read.num_values, + dmi_read->num_pre_writes, remain_len, + min_len); + rc = -ENOSPC; + goto end; + } + + dst = (uint8_t *)cpu_addr + dump_args->offset; + hdr = (struct cam_hw_soc_dump_header *)dst; + memset(hdr, 0, sizeof(struct cam_hw_soc_dump_header)); + scnprintf(hdr->tag, CAM_SOC_HW_DUMP_TAG_MAX_LEN, + "DMI_DUMP:"); + waddr = (uint32_t *)(dst + sizeof(struct cam_hw_soc_dump_header)); + start = waddr; + hdr->word_size = sizeof(uint32_t); + *waddr = soc_info->index; + waddr++; + for (i = 0; i < dmi_read->num_pre_writes; i++) { + if (dmi_read->pre_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->pre_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->pre_read_config[i].offset, + dmi_read->pre_read_config[i].value); + *waddr++ = dmi_read->pre_read_config[i].offset; + *waddr++ = dmi_read->pre_read_config[i].value; + } + + if (dmi_read->dmi_data_read.offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->dmi_data_read.offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) { + *waddr++ = dmi_read->dmi_data_read.offset; + *waddr++ = cam_soc_util_r_mb(soc_info, base_idx, + dmi_read->dmi_data_read.offset); + } + + for (i = 0; i < dmi_read->num_post_writes; i++) { + if (dmi_read->post_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->post_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->post_read_config[i].offset, + dmi_read->post_read_config[i].value); + } + hdr->size = (waddr - start) * hdr->word_size; + dump_args->offset += hdr->size + + sizeof(struct cam_hw_soc_dump_header); + +end: + return rc; +} + +static int cam_soc_util_dump_cont_reg_range_user_buf( + struct cam_hw_soc_info *soc_info, + struct cam_reg_range_read_desc *reg_read, + uint32_t base_idx, + struct cam_hw_soc_dump_args *dump_args) +{ + int i; + int rc = 0; + size_t buf_len; + uint8_t *dst; + size_t remain_len; + uint32_t min_len; + uint32_t *waddr, *start; + uintptr_t cpu_addr; + struct cam_hw_soc_dump_header *hdr; + + if (!soc_info || !dump_args || !reg_read) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK reg_read: %pK", + soc_info, dump_args, reg_read); + rc = -EINVAL; + goto end; + } + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &cpu_addr, &buf_len); + if (rc) { + CAM_ERR(CAM_UTIL, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + goto end; + } + if (buf_len <= dump_args->offset) { + CAM_WARN(CAM_UTIL, "Dump offset overshoot %zu %zu", + dump_args->offset, buf_len); + rc = -ENOSPC; + goto end; + } + remain_len = buf_len - dump_args->offset; + min_len = (reg_read->num_values * 2 * sizeof(uint32_t)) + + sizeof(struct cam_hw_soc_dump_header) + sizeof(uint32_t); + if (remain_len < min_len) { + CAM_WARN(CAM_UTIL, + "Dump Buffer exhaust read_values %d remain %zu min %u", + reg_read->num_values, + remain_len, + min_len); + rc = -ENOSPC; + goto end; + } + dst = (uint8_t *)cpu_addr + dump_args->offset; + hdr = (struct cam_hw_soc_dump_header *)dst; + memset(hdr, 0, sizeof(struct cam_hw_soc_dump_header)); + scnprintf(hdr->tag, CAM_SOC_HW_DUMP_TAG_MAX_LEN, "%s_REG:", + soc_info->dev_name); + waddr = (uint32_t *)(dst + sizeof(struct cam_hw_soc_dump_header)); + start = waddr; + hdr->word_size = sizeof(uint32_t); + *waddr = soc_info->index; + waddr++; + for (i = 0; i < reg_read->num_values; i++) { + if ((reg_read->offset + (i * sizeof(uint32_t))) > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + (reg_read->offset + (i * sizeof(uint32_t))), + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + waddr[0] = reg_read->offset + (i * sizeof(uint32_t)); + waddr[1] = cam_soc_util_r(soc_info, base_idx, + (reg_read->offset + (i * sizeof(uint32_t)))); + waddr += 2; + } + hdr->size = (waddr - start) * hdr->word_size; + dump_args->offset += hdr->size + + sizeof(struct cam_hw_soc_dump_header); +end: + return rc; +} + +static int cam_soc_util_user_reg_dump( + struct cam_reg_dump_desc *reg_dump_desc, + struct cam_hw_soc_dump_args *dump_args, + struct cam_hw_soc_info *soc_info, + uint32_t reg_base_idx) +{ + int rc = 0; + int i; + struct cam_reg_read_info *reg_read_info = NULL; + + if (!dump_args || !reg_dump_desc || !soc_info) { + CAM_ERR(CAM_UTIL, + "Invalid input parameters %pK %pK %pK", + dump_args, reg_dump_desc, soc_info); + return -EINVAL; + } + for (i = 0; i < reg_dump_desc->num_read_range; i++) { + + reg_read_info = ®_dump_desc->read_range[i]; + if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_CONT_RANGE) { + rc = cam_soc_util_dump_cont_reg_range_user_buf( + soc_info, + ®_read_info->reg_read, + reg_base_idx, + dump_args); + } else if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_DMI) { + rc = cam_soc_util_dump_dmi_reg_range_user_buf( + soc_info, + ®_read_info->dmi_read, + reg_base_idx, + dump_args); + } else { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump read type: %d", + reg_read_info->type); + rc = -EINVAL; + goto end; + } + + if (rc) { + CAM_ERR(CAM_UTIL, + "Reg range read failed rc: %d reg_base_idx: %d", + rc, reg_base_idx); + goto end; + } + } +end: + return rc; +} + int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, - cam_soc_util_regspace_data_cb reg_data_cb) + cam_soc_util_regspace_data_cb reg_data_cb, + struct cam_hw_soc_dump_args *soc_dump_args, + bool user_triggered_dump) { int rc = 0, i, j; uintptr_t cpu_addr = 0; @@ -2144,12 +2403,6 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, goto end; } - dump_out_buf = (struct cam_reg_dump_out_buffer *) - (cmd_buf_start + - (uintptr_t)reg_dump_desc->dump_buffer_offset); - dump_out_buf->req_id = req_id; - dump_out_buf->bytes_written = 0; - reg_base_type = reg_dump_desc->reg_base_type; if (reg_base_type == 0 || reg_base_type > CAM_REG_DUMP_BASE_TYPE_CAMNOC) { @@ -2181,6 +2434,31 @@ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, "Reg data callback success req_id: %llu base_type: %d base_idx: %d num_read_range: %d", req_id, reg_base_type, reg_base_idx, reg_dump_desc->num_read_range); + + /* If the dump request is triggered by user space + * buffer will be different from the buffer which is received + * in init packet. In this case, dump the data to the + * user provided buffer and exit. + */ + if (user_triggered_dump) { + rc = cam_soc_util_user_reg_dump(reg_dump_desc, + soc_dump_args, soc_info, reg_base_idx); + CAM_INFO(CAM_UTIL, + "%s reg_base_idx %d dumped offset %u", + soc_info->dev_name, reg_base_idx, + soc_dump_args->offset); + goto end; + } + + /* Below code is executed when data is dumped to the + * out buffer received in init packet + */ + dump_out_buf = (struct cam_reg_dump_out_buffer *) + (cmd_buf_start + + (uintptr_t)reg_dump_desc->dump_buffer_offset); + dump_out_buf->req_id = req_id; + dump_out_buf->bytes_written = 0; + for (j = 0; j < reg_dump_desc->num_read_range; j++) { CAM_DBG(CAM_UTIL, "Number of bytes written to cmd buffer: %u req_id: %llu", diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 64320ca7b91d..282183f3380e 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SOC_UTIL_H_ @@ -41,6 +41,9 @@ #define DDR_TYPE_LPDDR5 8 #define DDR_TYPE_LPDDR5X 9 +/* Maximum length of tag while dumping */ +#define CAM_SOC_HW_DUMP_TAG_MAX_LEN 32 + /** * enum cam_vote_level - Enum for voting level * @@ -216,6 +219,34 @@ struct cam_hw_soc_info { void *soc_private; }; +/** + * struct cam_hw_soc_dump_header - SOC dump header + * + * @Brief: soc hw dump header + * + * @tag: Tag name for the header + * @word_size: Size of each word + * @size: Total size of dumped data + */ +struct cam_hw_soc_dump_header { + uint8_t tag[CAM_SOC_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + +/** + * struct cam_hw_soc_dump_args: SOC Dump args + * + * @request_id: Issue request id + * @offset: Buffer offset, updated as the informaton is dumped + * @buf_handle: Buffer handle of the out buffer + */ +struct cam_hw_soc_dump_args { + uint64_t request_id; + size_t offset; + uint32_t buf_handle; +}; + /* * CAM_SOC_GET_REG_MAP_START * @@ -634,19 +665,23 @@ typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type, /** * cam_soc_util_reg_dump_to_cmd_buf() * - * @brief: Camera SOC util for dumping sets of register ranges to - * to command buffer - * - * @ctx: Context info from specific hardware manager - * @cmd_desc: Command buffer descriptor - * @req_id: Last applied req id for which reg dump is required - * @reg_data_cb: Callback function to get reg space info based on type - * in command buffer - * - * @return: Success or Failure + * @brief: Camera SOC util for dumping sets of register ranges + * command buffer + * + * @ctx: Context info from specific hardware manager + * @cmd_desc: Command buffer descriptor + * @req_id: Last applied req id for which reg dump is required + * @reg_data_cb: Callback function to get reg space info based on type + * in command buffer + * @soc_dump_args: Dump buffer args to dump the soc information. + * @user_triggered_dump: Flag to indicate if the dump request is issued by + * user. + * @return: Success or Failure */ int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, - cam_soc_util_regspace_data_cb reg_data_cb); + cam_soc_util_regspace_data_cb reg_data_cb, + struct cam_hw_soc_dump_args *soc_dump_args, + bool user_triggered_dump); #endif /* _CAM_SOC_UTIL_H_ */ -- GitLab From 4bb6a941d9079a2f90fa616f102277202c778e5c Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 28 Oct 2019 19:54:39 +0530 Subject: [PATCH 207/410] msm: camera: common: LDAR dump NRT devices information When user space detects an error or does not receive response for a request, Lets do a reset(LDAR) is triggered. Before LDAR, user space sends flush command to the kernel space. In order to debug the cause for this situation and to dump the information, user space sends a dump command to the kernel space before sending flush. As a part of this command, it passes the culprit request id and the buffer into which the information can be dumped. Kernel space traverses across the drivers and find the culprit hw and dumps the relevant information in the buffer. This data is written to a file for offline processing. This commit dumps the information for NRT devices; JPEG, LRME, FD and ICP. For LRME, FD, JPEG context information is dumped. FOR ICP, fw image is dumped. Change-Id: I123e9b8289521a40d88156ba9bd0003ad9602f01 CRs-Fixed: 2602180 Signed-off-by: Gaurav Jindal --- drivers/cam_fd/cam_fd_context.c | 16 +- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 135 +++++++++++++- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h | 10 +- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 81 ++++++++- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 34 +++- drivers/cam_icp/cam_icp_context.c | 17 +- drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 55 +++++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 111 ++++++++++++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 10 +- .../icp_hw_mgr/include/cam_a5_hw_intf.h | 3 +- .../icp_hw/include/cam_icp_hw_mgr_intf.h | 29 +++- drivers/cam_jpeg/cam_jpeg_context.c | 16 +- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 141 ++++++++++++++- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h | 10 +- .../jpeg_hw/include/cam_jpeg_hw_intf.h | 19 +- .../cam_jpeg_enc_hw_info_ver_4_2_0.h | 6 +- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 83 ++++++++- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h | 8 +- drivers/cam_lrme/cam_lrme_context.c | 18 +- .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 47 ++++- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c | 164 +++++++++++++++++- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h | 20 ++- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h | 21 ++- 23 files changed, 1032 insertions(+), 22 deletions(-) diff --git a/drivers/cam_fd/cam_fd_context.c b/drivers/cam_fd/cam_fd_context.c index ec6468f85dc0..99887d30242d 100644 --- a/drivers/cam_fd/cam_fd_context.c +++ b/drivers/cam_fd/cam_fd_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -117,6 +117,19 @@ static int __cam_fd_ctx_release_dev_in_activated(struct cam_context *ctx, return rc; } +static int __cam_fd_ctx_dump_dev_in_activated( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_FD, "Failed to dump device, rc=%d", rc); + + return rc; +} + static int __cam_fd_ctx_flush_dev_in_activated(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -198,6 +211,7 @@ static struct cam_ctx_ops .release_dev = __cam_fd_ctx_release_dev_in_activated, .config_dev = __cam_fd_ctx_config_dev_in_activated, .flush_dev = __cam_fd_ctx_flush_dev_in_activated, + .dump_dev = __cam_fd_ctx_dump_dev_in_activated, }, .crm_ops = {}, .irq_ops = __cam_fd_ctx_handle_irq_in_activated, diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index b33dfa699647..cfbb8840eb63 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -883,6 +883,7 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data) hw_device->cur_hw_ctx = hw_ctx; hw_device->req_id = frame_req->request_id; mutex_unlock(&hw_device->lock); + frame_req->submit_timestamp = ktime_get(); rc = cam_fd_mgr_util_put_frame_req( &hw_mgr->frame_processing_list, &frame_req); @@ -1504,6 +1505,137 @@ static int cam_fd_mgr_hw_flush(void *hw_mgr_priv, return rc; } +static int cam_fd_mgr_hw_dump( + void *hw_mgr_priv, + void *hw_dump_args) +{ + int rc; + uint8_t *dst; + ktime_t cur_time; + size_t remain_len; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + struct cam_fd_hw_mgr *hw_mgr; + struct cam_hw_dump_args *dump_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_hw_dump_args fd_dump_args; + struct cam_fd_hw_dump_header *hdr; + struct cam_fd_mgr_frame_request *frame_req, *req_temp; + + hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + dump_args = (struct cam_hw_dump_args *)hw_dump_args; + if (!hw_mgr || !dump_args) { + CAM_ERR(CAM_FD, "Invalid args %pK %pK", + hw_mgr, dump_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)dump_args->ctxt_to_hw_map; + + if (!hw_ctx) { + CAM_ERR(CAM_FD, "Invalid ctx"); + return -EINVAL; + } + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_processing_list, list) { + if (frame_req->request_id == dump_args->request_id) + goto hw_dump; + } + + CAM_DBG(CAM_FD, "fd dump cannot find req %llu", + dump_args->request_id); + return rc; +hw_dump: + cur_time = ktime_get(); + diff = ktime_us_delta(frame_req->submit_timestamp, cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(frame_req->submit_timestamp); + if (diff < CAM_FD_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_FD, "No Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + return 0; + } + CAM_INFO(CAM_FD, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &fd_dump_args.cpu_addr, &fd_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_FD, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + if (fd_dump_args.buf_len <= dump_args->offset) { + CAM_WARN(CAM_FD, "dump offset overshoot len %zu offset %zu", + fd_dump_args.buf_len, dump_args->offset); + return -ENOSPC; + } + remain_len = fd_dump_args.buf_len - dump_args->offset; + min_len = sizeof(struct cam_fd_hw_dump_header) + + (CAM_FD_HW_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_FD, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + dst = (uint8_t *)fd_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_fd_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_FD_HW_DUMP_TAG_MAX_LEN, + "FD_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_fd_hw_dump_header)); + start = addr; + *addr++ = frame_req->request_id; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_fd_hw_dump_header); + + fd_dump_args.request_id = dump_args->request_id; + fd_dump_args.offset = dump_args->offset; + if (hw_device->hw_intf->hw_ops.process_cmd) { + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, + CAM_FD_HW_CMD_HW_DUMP, + &fd_dump_args, + sizeof(struct + cam_fd_hw_dump_args)); + if (rc) { + CAM_ERR(CAM_FD, "Hw Dump cmd fails req %lld rc %d", + frame_req->request_id, rc); + return rc; + } + } + CAM_DBG(CAM_FD, "Offset before %zu after %zu", + dump_args->offset, fd_dump_args.offset); + dump_args->offset = fd_dump_args.offset; + return rc; +} + static int cam_fd_mgr_hw_stop(void *hw_mgr_priv, void *mgr_stop_args) { struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; @@ -1944,6 +2076,7 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, hw_mgr_intf->hw_write = NULL; hw_mgr_intf->hw_close = NULL; hw_mgr_intf->hw_flush = cam_fd_mgr_hw_flush; + hw_mgr_intf->hw_dump = cam_fd_mgr_hw_dump; return rc; diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h index 49bc5bbc1b07..bbbc77bef6a3 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_MGR_H_ @@ -21,6 +21,12 @@ #define CAM_FD_HW_MAX 1 #define CAM_FD_WORKQ_NUM_TASK 10 +/* + * Response time threshold in ms beyond which a request is not expected to be + * with FD hw + */ +#define CAM_FD_RESPONSE_TIME_THRESHOLD 100000 + struct cam_fd_hw_mgr; /** @@ -100,6 +106,7 @@ struct cam_fd_device { * @hw_update_entries : HW update entries corresponding to this request * which needs to be submitted to HW through CDM * @num_hw_update_entries : Number of HW update entries + * @submit_timestamp : Time stamp for submit req with hw */ struct cam_fd_mgr_frame_request { struct list_head list; @@ -108,6 +115,7 @@ struct cam_fd_mgr_frame_request { struct cam_fd_hw_req_private hw_req_private; struct cam_hw_update_entry hw_update_entries[CAM_FD_MAX_HW_ENTRIES]; uint32_t num_hw_update_entries; + ktime_t submit_timestamp; }; /** diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index c28fcdf3efc6..28628f93ff66 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_fd_hw_core.h" @@ -516,6 +516,80 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, return 0; } +static int cam_fd_hw_util_processcmd_hw_dump( + struct cam_hw_info *fd_hw, + void *args) +{ + int i, j; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t num_reg, min_len; + uint64_t remain_len; + struct cam_hw_soc_info *soc_info; + struct cam_fd_hw_dump_header *hdr; + struct cam_fd_hw_dump_args *dump_args; + + if (!fd_hw || !args) { + CAM_ERR(CAM_FD, "Invalid args %pK %pK", + fd_hw, args); + return -EINVAL; + } + + mutex_lock(&fd_hw->hw_mutex); + + if (fd_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_INFO(CAM_FD, "power off state"); + mutex_unlock(&fd_hw->hw_mutex); + return 0; + } + + dump_args = (struct cam_fd_hw_dump_args *)args; + soc_info = &fd_hw->soc_info; + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_FD, "dump offset overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + mutex_unlock(&fd_hw->hw_mutex); + return -ENOSPC; + } + + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_fd_hw_dump_header) + + soc_info->reg_map[0].size + sizeof(uint32_t); + + if (remain_len < min_len) { + CAM_WARN(CAM_FD, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + mutex_unlock(&fd_hw->hw_mutex); + return -ENOSPC; + } + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_fd_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_FD_HW_DUMP_TAG_MAX_LEN, + "FD_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_fd_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + + for (j = 0; j < soc_info->num_reg_map; j++) { + num_reg = soc_info->reg_map[j].size/4; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[j]->start + i*4; + *addr++ = cam_io_r(soc_info->reg_map[j].mem_base + + (i*4)); + } + } + + mutex_unlock(&fd_hw->hw_mutex); + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_fd_hw_dump_header); + CAM_DBG(CAM_FD, "%zu", dump_args->offset); + return 0; +} + irqreturn_t cam_fd_hw_irq(int irq_num, void *data) { struct cam_hw_info *fd_hw = (struct cam_hw_info *)data; @@ -1156,6 +1230,11 @@ int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type, cmd_frame_results); break; } + case CAM_FD_HW_CMD_HW_DUMP: { + rc = cam_fd_hw_util_processcmd_hw_dump(fd_hw, + cmd_args); + break; + } default: break; } diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h index e35e5e520b7b..11ef1b913f91 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_INTF_H_ @@ -24,6 +24,8 @@ #define CAM_FD_MAX_IO_BUFFERS 5 #define CAM_FD_MAX_HW_ENTRIES 5 +#define CAM_FD_HW_DUMP_TAG_MAX_LEN 32 +#define CAM_FD_HW_DUMP_NUM_WORDS 5 /** * enum cam_fd_hw_type - Enum for FD HW type @@ -81,12 +83,14 @@ enum cam_fd_hw_irq_type { * @CAM_FD_HW_CMD_UPDATE_SOC : Command to process soc update * @CAM_FD_HW_CMD_REGISTER_CALLBACK : Command to set hw mgr callback * @CAM_FD_HW_CMD_MAX : Indicates max cmd + * @CAM_FD_HW_CMD_HW_DUMP : Command to dump fd hw information */ enum cam_fd_hw_cmd_type { CAM_FD_HW_CMD_PRESTART, CAM_FD_HW_CMD_FRAME_DONE, CAM_FD_HW_CMD_UPDATE_SOC, CAM_FD_HW_CMD_REGISTER_CALLBACK, + CAM_FD_HW_CMD_HW_DUMP, CAM_FD_HW_CMD_MAX, }; @@ -279,4 +283,32 @@ struct cam_fd_hw_cmd_set_irq_cb { void *data; }; +/** + * struct cam_fd_hw_dump_args : Args for dump request + * + * @request_id : Issue request id + * @offset : offset of the buffer + * @buf_len : Length of target buffer + * @cpu_addr : start address of the target buffer + */ +struct cam_fd_hw_dump_args { + uint64_t request_id; + size_t offset; + size_t buf_len; + uintptr_t cpu_addr; +}; + +/** + * struct cam_fd_hw_dump_header : fd hw dump header + * + * @tag : fd hw dump header tag + * @size : Size of data + * @word_size : size of each word + */ +struct cam_fd_hw_dump_header { + uint8_t tag[CAM_FD_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + #endif /* _CAM_FD_HW_INTF_H_ */ diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 180ea7152a76..6a9f57b65f68 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -107,6 +107,19 @@ static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_icp_dump_dev_in_ready( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to dump device"); + + return rc; +} + static int __cam_icp_flush_dev_in_ready(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -230,6 +243,7 @@ static struct cam_ctx_ops .start_dev = __cam_icp_start_dev_in_acquired, .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, + .dump_dev = __cam_icp_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, @@ -242,6 +256,7 @@ static struct cam_ctx_ops .release_dev = __cam_icp_release_dev_in_ready, .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, + .dump_dev = __cam_icp_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index e4cb645b7af0..1ac27511f7ac 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -235,6 +235,53 @@ static int32_t cam_a5_download_fw(void *device_priv) return rc; } +static int cam_a5_fw_dump( + struct cam_icp_hw_dump_args *dump_args, + struct cam_a5_device_core_info *core_info) +{ + u8 *dest; + u8 *src; + uint64_t size_required; + struct cam_icp_dump_header *hdr; + + if (!core_info || !dump_args) { + CAM_ERR(CAM_ICP, "invalid params %pK %pK", + core_info, dump_args); + return -EINVAL; + } + if (!core_info->fw_kva_addr || !dump_args->cpu_addr) { + CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx", + core_info->fw_kva_addr, dump_args->cpu_addr); + return -EINVAL; + } + + size_required = core_info->fw_buf_len + + sizeof(struct cam_icp_dump_header); + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_ICP, "Dump offset overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + return -ENOSPC; + } + + if ((dump_args->buf_len - dump_args->offset) < size_required) { + CAM_WARN(CAM_ICP, "Dump buffer exhaust required %llu len %llu", + size_required, core_info->fw_buf_len); + return -ENOSPC; + } + + dest = (u8 *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_icp_dump_header *)dest; + scnprintf(hdr->tag, CAM_ICP_DUMP_TAG_MAX_LEN, "ICP_FW:"); + hdr->word_size = sizeof(u8); + hdr->size = core_info->fw_buf_len; + src = (u8 *)core_info->fw_kva_addr; + dest = (u8 *)dest + sizeof(struct cam_icp_dump_header); + memcpy_fromio(dest, src, core_info->fw_buf_len); + dump_args->offset += hdr->size + sizeof(struct cam_icp_dump_header); + return 0; +} + int cam_a5_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { @@ -543,6 +590,12 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, core_info->cpas_handle, &ahb_vote); break; } + case CAM_ICP_A5_CMD_HW_DUMP: { + struct cam_icp_hw_dump_args *dump_args = cmd_args; + + rc = cam_a5_fw_dump(dump_args, core_info); + break; + } default: break; } 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 14e2d4e2c48c..f0bf17855753 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 @@ -3982,6 +3982,7 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); ctx_data->hfi_frame_process.fw_process_flag[idx] = true; + ctx_data->hfi_frame_process.submit_timestamp[idx] = ktime_get(); CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, frame_info->io_config); @@ -5090,6 +5091,115 @@ static int cam_icp_mgr_enqueue_abort( return 0; } +static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args) +{ + int rc; + int i; + size_t remain_len; + uint8_t *dst; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + ktime_t cur_time; + struct cam_hw_intf *a5_dev_intf; + struct cam_icp_hw_mgr *hw_mgr; + struct cam_hw_dump_args *dump_args; + struct cam_icp_hw_ctx_data *ctx_data; + struct cam_icp_dump_header *hdr; + struct cam_icp_hw_dump_args icp_dump_args; + struct hfi_frame_process_info *frm_process; + + if ((!hw_priv) || (!hw_dump_args)) { + CAM_ERR(CAM_ICP, "Invalid params %pK %pK", + hw_priv, hw_dump_args); + return -EINVAL; + } + + dump_args = (struct cam_hw_dump_args *)hw_dump_args; + hw_mgr = hw_priv; + ctx_data = dump_args->ctxt_to_hw_map; + CAM_DBG(CAM_ICP, "Req %lld", dump_args->request_id); + frm_process = &ctx_data->hfi_frame_process; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) { + if ((frm_process->request_id[i] == + dump_args->request_id) && + frm_process->fw_process_flag[i]) + goto hw_dump; + } + return 0; +hw_dump: + cur_time = ktime_get(); + diff = ktime_us_delta(frm_process->submit_timestamp[i], cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(frm_process->submit_timestamp[i]); + + if (diff < CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_ICP, "No Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + return 0; + } + + CAM_INFO(CAM_ICP, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &icp_dump_args.cpu_addr, &icp_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_ICP, "Invalid addr %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + if (icp_dump_args.buf_len <= dump_args->offset) { + CAM_WARN(CAM_ICP, "dump buffer overshoot len %zu offset %zu", + icp_dump_args.buf_len, dump_args->offset); + return -ENOSPC; + } + + remain_len = icp_dump_args.buf_len - dump_args->offset; + min_len = sizeof(struct cam_icp_dump_header) + + (CAM_ICP_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_ICP, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + + dst = (uint8_t *)icp_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_icp_dump_header *)dst; + scnprintf(hdr->tag, CAM_ICP_DUMP_TAG_MAX_LEN, "ICP_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_icp_dump_header)); + start = addr; + *addr++ = frm_process->request_id[i]; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += (hdr->size + sizeof(struct cam_icp_dump_header)); + /* Dumping the fw image*/ + icp_dump_args.offset = dump_args->offset; + a5_dev_intf = hw_mgr->a5_dev_intf; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_HW_DUMP, &icp_dump_args, + sizeof(struct cam_icp_hw_dump_args)); + CAM_DBG(CAM_ICP, "Offset before %zu after %zu", + dump_args->offset, icp_dump_args.offset); + dump_args->offset = icp_dump_args.offset; + 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; @@ -5902,6 +6012,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_close = cam_icp_mgr_hw_close_u; hw_mgr_intf->hw_flush = cam_icp_mgr_hw_flush; hw_mgr_intf->hw_cmd = cam_icp_mgr_cmd; + hw_mgr_intf->hw_dump = cam_icp_mgr_hw_dump; icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE; mutex_init(&icp_hw_mgr.hw_mgr_mutex); diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 8cab9a80cd30..c438d438e892 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_ICP_HW_MGR_H @@ -67,6 +67,12 @@ /* Current appliacble vote paths, based on number of UAPI definitions */ #define CAM_ICP_MAX_PER_PATH_VOTES 6 +/* + * Response time threshold in ms beyond which a request is not expected + * to be with ICP hw + */ +#define CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD 300000 + /** * struct icp_hfi_mem_info * @qtbl: Memory info of queue table @@ -171,6 +177,7 @@ struct cam_icp_clk_bw_req_internal_v2 { * @clk_info: Clock information for a request * @clk_info_v2: Clock info for AXI bw voting v2 * @frame_info: information needed to process request + * @submit_timestamp: Submit timestamp to hw */ struct hfi_frame_process_info { struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX]; @@ -186,6 +193,7 @@ struct hfi_frame_process_info { struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX]; struct cam_icp_clk_bw_req_internal_v2 clk_info_v2[CAM_FRAME_CMD_MAX]; struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX]; + ktime_t submit_timestamp[CAM_FRAME_CMD_MAX]; }; /** diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h index af80a2eac15d..c3fefdc09ba9 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_A5_HW_INTF_H @@ -27,6 +27,7 @@ enum cam_icp_a5_cmd_type { CAM_ICP_A5_CMD_UBWC_CFG, CAM_ICP_A5_CMD_PC_PREP, CAM_ICP_A5_CMD_CLK_UPDATE, + CAM_ICP_A5_CMD_HW_DUMP, CAM_ICP_A5_CMD_MAX, }; diff --git a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index d87c7ef238df..84129cba7e19 100644 --- a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_ICP_HW_MGR_INTF_H @@ -27,6 +27,9 @@ #define CAM_ICP_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL #define CAM_ICP_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_READ +#define CAM_ICP_DUMP_TAG_MAX_LEN 32 +#define CAM_ICP_DUMP_NUM_WORDS 5 + int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, int *iommu_hdl); @@ -44,4 +47,28 @@ struct cam_icp_cpas_vote { uint32_t axi_vote_valid; }; +/** + * struct cam_icp_hw_dump_args + * @cpu_addr: kernel vaddr + * @buf_len: buffer length + * @offset: offset + */ +struct cam_icp_hw_dump_args { + uintptr_t cpu_addr; + size_t buf_len; + size_t offset; +}; + +/** + * struct cam_icp_dump_header + * @tag: tag of the packet + * @size: size of data in packet + * @word_size: size of each word in packet + */ +struct cam_icp_dump_header { + uint8_t tag[CAM_ICP_DUMP_TAG_MAX_LEN]; + uint64_t size; + int32_t word_size; +}; + #endif /* CAM_ICP_HW_MGR_INTF_H */ diff --git a/drivers/cam_jpeg/cam_jpeg_context.c b/drivers/cam_jpeg/cam_jpeg_context.c index b16a9dfed011..b28f8b667239 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.c +++ b/drivers/cam_jpeg/cam_jpeg_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -83,6 +83,19 @@ static int __cam_jpeg_ctx_release_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_jpeg_ctx_dump_dev_in_acquired( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to dump device, rc=%d", rc); + + return rc; +} + static int __cam_jpeg_ctx_flush_dev_in_acquired(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -145,6 +158,7 @@ static struct cam_ctx_ops .config_dev = __cam_jpeg_ctx_config_dev_in_acquired, .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, + .dump_dev = __cam_jpeg_ctx_dump_dev_in_acquired, }, .crm_ops = { }, .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index c1b867af4914..ac2612356448 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -484,6 +484,7 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) rc); goto end_callcb; } + p_cfg_req->submit_timestamp = ktime_get(); mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; @@ -1486,6 +1487,143 @@ static int cam_jpeg_init_devices(struct device_node *of_node, return rc; } +static int cam_jpeg_mgr_hw_dump(void *hw_mgr_priv, void *dump_hw_args) +{ + int rc; + uint8_t *dst; + ktime_t cur_time; + size_t remain_len; + uint32_t min_len; + uint32_t dev_type; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + struct cam_jpeg_hw_mgr *hw_mgr; + struct cam_hw_dump_args *dump_args; + struct cam_jpeg_hw_cfg_req *p_cfg_req; + struct cam_jpeg_hw_ctx_data *ctx_data; + struct cam_jpeg_hw_dump_args jpeg_dump_args; + struct cam_jpeg_hw_dump_header *hdr; + + if (!hw_mgr_priv || !dump_hw_args) { + CAM_ERR(CAM_JPEG, "Invalid args %pK %pK", + hw_mgr_priv, dump_hw_args); + return -EINVAL; + } + + hw_mgr = hw_mgr_priv; + dump_args = (struct cam_hw_dump_args *)dump_hw_args; + ctx_data = (struct cam_jpeg_hw_ctx_data *)dump_args->ctxt_to_hw_map; + + if (!ctx_data) { + CAM_ERR(CAM_JPEG, "Invalid context"); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + if (true == hw_mgr->device_in_use[dev_type][0]) { + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (p_cfg_req && p_cfg_req->req_id == + (uintptr_t)dump_args->request_id) + goto hw_dump; + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + +hw_dump: + cur_time = ktime_get(); + diff = ktime_us_delta(p_cfg_req->submit_timestamp, cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(p_cfg_req->submit_timestamp); + + if (diff < CAM_JPEG_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_JPEG, + "No error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + } + + CAM_INFO(CAM_JPEG, + "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &jpeg_dump_args.cpu_addr, &jpeg_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_JPEG, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -rc; + } + + if (jpeg_dump_args.buf_len <= dump_args->offset) { + CAM_WARN(CAM_JPEG, "dump offset overshoot len %zu offset %zu", + jpeg_dump_args.buf_len, dump_args->offset); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -ENOSPC; + } + + remain_len = jpeg_dump_args.buf_len - dump_args->offset; + min_len = sizeof(struct cam_jpeg_hw_dump_header) + + (CAM_JPEG_HW_DUMP_NUM_WORDS * sizeof(uint64_t)); + if (remain_len < min_len) { + CAM_WARN(CAM_JPEG, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -ENOSPC; + } + + dst = (uint8_t *)jpeg_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_jpeg_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_JPEG_HW_DUMP_TAG_MAX_LEN, + "JPEG_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_jpeg_hw_dump_header)); + start = addr; + *addr++ = dump_args->request_id; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_jpeg_hw_dump_header); + jpeg_dump_args.request_id = dump_args->request_id; + jpeg_dump_args.offset = dump_args->offset; + + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_HW_DUMP, + &jpeg_dump_args, sizeof(jpeg_dump_args)); + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_DBG(CAM_JPEG, "Offset before %u after %u", + dump_args->offset, jpeg_dump_args.offset); + dump_args->offset = jpeg_dump_args.offset; + return rc; +} + static int cam_jpeg_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -1539,6 +1677,7 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_flush = cam_jpeg_mgr_hw_flush; hw_mgr_intf->hw_stop = cam_jpeg_mgr_hw_stop; hw_mgr_intf->hw_cmd = cam_jpeg_mgr_cmd; + hw_mgr_intf->hw_dump = cam_jpeg_mgr_hw_dump; mutex_init(&g_jpeg_hw_mgr.hw_mgr_mutex); spin_lock_init(&g_jpeg_hw_mgr.hw_mgr_lock); diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h index e482c11a82bd..3a00e424ebc9 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_HW_MGR_H @@ -21,6 +21,12 @@ #define CAM_JPEG_WORKQ_TASK_MSG_TYPE 2 #define CAM_JPEG_HW_CFG_Q_MAX 50 +/* + * Response time threshold in ms beyond which a request is not expected + * to be with JPEG hw + */ +#define CAM_JPEG_RESPONSE_TIME_THRESHOLD 100000 + /** * struct cam_jpeg_process_frame_work_data_t * @@ -69,12 +75,14 @@ struct cam_jpeg_hw_cdm_info_t { * @hw_cfg_args: Hw config args * @dev_type: Dev type for cfg request * @req_id: Request Id + * @submit_timestamp: Timestamp of submitting request */ struct cam_jpeg_hw_cfg_req { struct list_head list; struct cam_hw_config_args hw_cfg_args; uint32_t dev_type; uintptr_t req_id; + ktime_t submit_timestamp; }; /** diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h index 3deb9dd73b32..df552c4d04cf 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h +++ b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_HW_INTF_H @@ -15,6 +15,9 @@ #define JPEG_VOTE 640000000 +#define CAM_JPEG_HW_DUMP_TAG_MAX_LEN 32 +#define CAM_JPEG_HW_DUMP_NUM_WORDS 5 + enum cam_jpeg_hw_type { CAM_JPEG_DEV_ENC, CAM_JPEG_DEV_DMA, @@ -27,9 +30,23 @@ struct cam_jpeg_set_irq_cb { uint32_t b_set_cb; }; +struct cam_jpeg_hw_dump_args { + uint64_t request_id; + uintptr_t cpu_addr; + size_t offset; + size_t buf_len; +}; + +struct cam_jpeg_hw_dump_header { + uint8_t tag[CAM_JPEG_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + enum cam_jpeg_cmd_type { CAM_JPEG_CMD_CDM_CFG, CAM_JPEG_CMD_SET_IRQ_CB, + CAM_JPEG_CMD_HW_DUMP, CAM_JPEG_CMD_MAX, }; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h index e610a9e7ee03..b75998bc586c 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_ENC_HW_INFO_TITAN170_H @@ -66,6 +66,10 @@ static struct cam_jpeg_enc_device_hw_info cam_jpeg_enc_hw_info = { .resetdone = CAM_JPEG_HW_MASK_COMP_RESET_ACK, .iserror = CAM_JPEG_HW_MASK_COMP_ERR, .stopdone = CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_MASK, + }, + .reg_dump = { + .start_offset = 0x0, + .end_offset = 0x33C, } }; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 4830bf58e89e..b9329a8173e5 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -378,6 +378,81 @@ int cam_jpeg_enc_stop_hw(void *data, return 0; } +int cam_jpeg_enc_hw_dump( + struct cam_hw_info *jpeg_enc_dev, + struct cam_jpeg_hw_dump_args *dump_args) +{ + + int i; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t num_reg, min_len; + uint32_t reg_start_offset; + size_t remain_len; + struct cam_hw_soc_info *soc_info; + struct cam_jpeg_hw_dump_header *hdr; + struct cam_jpeg_enc_device_hw_info *hw_info; + struct cam_jpeg_enc_device_core_info *core_info; + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mutex_lock(&core_info->core_mutex); + spin_lock(&jpeg_enc_dev->hw_lock); + + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } + + spin_unlock(&jpeg_enc_dev->hw_lock); + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_JPEG, "dump buffer overshoot %zu %zu", + dump_args->buf_len, dump_args->offset); + mutex_unlock(&core_info->core_mutex); + return -ENOSPC; + } + + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_jpeg_hw_dump_header) + + soc_info->reg_map[0].size + sizeof(uint32_t); + if (remain_len < min_len) { + CAM_WARN(CAM_JPEG, "dump buffer exhaust %zu %u", + remain_len, min_len); + mutex_unlock(&core_info->core_mutex); + return -ENOSPC; + } + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_jpeg_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_JPEG_HW_DUMP_TAG_MAX_LEN, + "JPEG_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_jpeg_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + num_reg = (hw_info->reg_dump.end_offset - + hw_info->reg_dump.start_offset)/4; + reg_start_offset = hw_info->reg_dump.start_offset; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[0]->start + + reg_start_offset + i*4; + *addr++ = cam_io_r(soc_info->reg_map[0].mem_base + (i*4)); + } + + mutex_unlock(&core_info->core_mutex); + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_jpeg_hw_dump_header); + CAM_DBG(CAM_JPEG, "offset %zu", dump_args->offset); + + return 0; +} + int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -418,6 +493,12 @@ int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, rc = 0; break; } + case CAM_JPEG_CMD_HW_DUMP: + { + rc = cam_jpeg_enc_hw_dump(jpeg_enc_dev, + cmd_args); + break; + } default: rc = -EINVAL; break; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h index df9341c90c77..ca83dccb193f 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef CAM_JPEG_ENC_CORE_H @@ -39,10 +39,16 @@ struct cam_jpeg_enc_int_status { uint32_t stopdone; }; +struct cam_jpeg_enc_reg_dump { + uint32_t start_offset; + uint32_t end_offset; +}; + struct cam_jpeg_enc_device_hw_info { struct cam_jpeg_enc_reg_offsets reg_offset; struct cam_jpeg_enc_regval reg_val; struct cam_jpeg_enc_int_status int_status; + struct cam_jpeg_enc_reg_dump reg_dump; }; enum cam_jpeg_enc_core_state { diff --git a/drivers/cam_lrme/cam_lrme_context.c b/drivers/cam_lrme/cam_lrme_context.c index fa544c7a089e..857aab9dd476 100644 --- a/drivers/cam_lrme/cam_lrme_context.c +++ b/drivers/cam_lrme/cam_lrme_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -86,6 +86,21 @@ static int __cam_lrme_ctx_config_dev_in_activated(struct cam_context *ctx, return rc; } +static int __cam_lrme_ctx_dump_dev_in_activated( + struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_LRME, "Failed to dump device"); + + return rc; +} + static int __cam_lrme_ctx_flush_dev_in_activated(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -199,6 +214,7 @@ static struct cam_ctx_ops .release_dev = __cam_lrme_ctx_release_dev_in_activated, .stop_dev = __cam_lrme_ctx_stop_dev_in_activated, .flush_dev = __cam_lrme_ctx_flush_dev_in_activated, + .dump_dev = __cam_lrme_ctx_dump_dev_in_activated, }, .crm_ops = {}, .irq_ops = __cam_lrme_ctx_handle_irq_in_activated, diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 40700bbce9e0..537fc48a619e 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -649,6 +649,50 @@ static int cam_lrme_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args) return rc; } +static int cam_lrme_mgr_hw_dump(void *hw_mgr_priv, void *hw_dump_args) +{ + struct cam_hw_dump_args *dump_args = hw_dump_args; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_lrme_device *hw_device; + int rc = 0; + uint32_t device_index; + struct cam_lrme_hw_dump_args lrme_dump_args; + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(dump_args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + CAM_DBG(CAM_LRME, "Start device index %d", device_index); + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw device"); + return rc; + } + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &lrme_dump_args.cpu_addr, + &lrme_dump_args.buf_len); + if (rc) { + CAM_ERR(CAM_LRME, "Invalid handle %u rc %d", + dump_args->buf_handle, rc); + return rc; + } + lrme_dump_args.offset = dump_args->offset; + lrme_dump_args.request_id = dump_args->request_id; + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_DUMP, + &lrme_dump_args, + sizeof(struct cam_lrme_hw_dump_args)); + CAM_DBG(CAM_LRME, "Offset before %zu after %zu", + dump_args->offset, lrme_dump_args.offset); + dump_args->offset = lrme_dump_args.offset; + return rc; +} + static int cam_lrme_mgr_hw_flush(void *hw_mgr_priv, void *hw_flush_args) { int rc = 0, i; struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; @@ -1147,6 +1191,7 @@ int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, hw_mgr_intf->hw_flush = cam_lrme_mgr_hw_flush; g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb; + hw_mgr_intf->hw_dump = cam_lrme_mgr_hw_dump; cam_lrme_mgr_create_debugfs_entry(); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index b736708fa99d..551191376af8 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ +#include #include "cam_lrme_hw_core.h" #include "cam_lrme_hw_soc.h" #include "cam_smmu_api.h" @@ -21,6 +22,159 @@ static void cam_lrme_dump_registers(void __iomem *base) cam_io_dump(base, 0x900, (0x928 - 0x900) / 0x4); } +static int cam_lrme_dump_regs_to_buf( + struct cam_lrme_frame_request *req, + struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_dump_args *dump_args) +{ + int i; + uint8_t *dst; + uint32_t *addr, *start; + uint32_t num_reg, min_len; + size_t remain_len; + struct cam_hw_soc_info *soc_info; + struct cam_lrme_hw_dump_header *hdr; + + if (!lrme_hw || !req || !dump_args) { + CAM_ERR(CAM_LRME, "Invalid params %pK, %pK, %pK", + lrme_hw, req, dump_args); + return -EINVAL; + } + soc_info = &lrme_hw->soc_info; + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_LRME, "dump buffer overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + return -ENOSPC; + } + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_lrme_hw_dump_header) + + soc_info->reg_map[0].size + sizeof(uint32_t); + + if (remain_len < min_len) { + CAM_WARN(CAM_LRME, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + return -ENOSPC; + } + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_lrme_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_LRME_HW_DUMP_TAG_MAX_LEN, + "LRME_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_lrme_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + num_reg = soc_info->reg_map[0].size/4; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[0]->start + (i*4); + *addr++ = cam_io_r(soc_info->reg_map[0].mem_base + (i*4)); + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_lrme_hw_dump_header); + CAM_DBG(CAM_LRME, "offset %zu", dump_args->offset); + return 0; +} + +static int cam_lrme_hw_dump( + struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_dump_args *dump_args) +{ + uint8_t *dst; + ktime_t cur_time; + size_t remain_len; + uint32_t min_len; + uint64_t diff; + uint64_t *addr, *start; + struct timespec64 cur_ts; + struct timespec64 req_ts; + struct cam_lrme_core *lrme_core; + struct cam_lrme_frame_request *req = NULL; + struct cam_lrme_hw_dump_header *hdr; + + mutex_lock(&lrme_hw->hw_mutex); + if (lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_DBG(CAM_LRME, "LRME HW is in off state"); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + if (lrme_core->req_submit && + lrme_core->req_submit->req_id == dump_args->request_id) + req = lrme_core->req_submit; + else if (lrme_core->req_proc && + lrme_core->req_proc->req_id == dump_args->request_id) + req = lrme_core->req_proc; + + if (!req) { + CAM_DBG(CAM_LRME, "LRME req %lld not with hw", + dump_args->request_id); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + cur_time = ktime_get(); + diff = ktime_us_delta(req->submit_timestamp, cur_time); + cur_ts = ktime_to_timespec64(cur_time); + req_ts = ktime_to_timespec64(req->submit_timestamp); + + if (diff < CAM_LRME_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_LRME, "No error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + CAM_INFO(CAM_LRME, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req_ts.tv_sec, + req_ts.tv_nsec/NSEC_PER_USEC, + cur_ts.tv_sec, + cur_ts.tv_nsec/NSEC_PER_USEC); + + if (dump_args->buf_len <= dump_args->offset) { + CAM_WARN(CAM_LRME, "dump buffer overshoot len %zu offset %zu", + dump_args->buf_len, dump_args->offset); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + remain_len = dump_args->buf_len - dump_args->offset; + min_len = sizeof(struct cam_lrme_hw_dump_header) + + (CAM_LRME_HW_DUMP_NUM_WORDS * sizeof(uint64_t)); + + if (remain_len < min_len) { + CAM_WARN(CAM_LRME, "dump buffer exhaust remain %zu min %u", + remain_len, min_len); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + + dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_lrme_hw_dump_header *)dst; + scnprintf(hdr->tag, CAM_LRME_HW_DUMP_TAG_MAX_LEN, + "LRME_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_lrme_hw_dump_header)); + start = addr; + *addr++ = req->req_id; + *addr++ = req_ts.tv_sec; + *addr++ = req_ts.tv_nsec/NSEC_PER_USEC; + *addr++ = cur_ts.tv_sec; + *addr++ = cur_ts.tv_nsec/NSEC_PER_USEC; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_lrme_hw_dump_header); + cam_lrme_dump_regs_to_buf(req, lrme_hw, dump_args); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; +} + static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer, uint32_t *index, uint32_t reg_offset, uint32_t reg_value) { @@ -957,6 +1111,8 @@ int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, goto error; } + frame_req->submit_timestamp = ktime_get(); + switch (lrme_core->state) { case CAM_LRME_CORE_STATE_PROCESSING: lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND; @@ -1266,6 +1422,12 @@ int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, break; } + case CAM_LRME_HW_CMD_DUMP: { + struct cam_lrme_hw_dump_args *dump_args = + (struct cam_lrme_hw_dump_args *)cmd_args; + rc = cam_lrme_hw_dump(lrme_hw, dump_args); + break; + } default: break; } diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h index accb5a8b5827..4c9386c9f046 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_LRME_HW_CORE_H_ @@ -35,6 +35,10 @@ #define CAM_LRME_MAX_REG_PAIR_NUM 60 +#define CAM_LRME_RESPONSE_TIME_THRESHOLD 100000 +#define CAM_LRME_HW_DUMP_TAG_MAX_LEN 32 +#define CAM_LRME_HW_DUMP_NUM_WORDS 5 + /** * enum cam_lrme_irq_set * @@ -432,6 +436,20 @@ struct cam_lrme_hw_info { struct cam_lrme_titan_reg titan_reg; }; +/** + * struct cam_lrme_hw_dump_header : LRME hw dump header + * + * @tag : LRME hw dump header tag + * @size : Size of data + * @word_size : size of each word + */ + +struct cam_lrme_hw_dump_header { + uint8_t tag[CAM_LRME_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + int cam_lrme_hw_process_irq(void *priv, void *data); int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, uint32_t arg_size); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h index b74d53700419..cd4d64b18f67 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_LRME_HW_INTF_H_ @@ -59,12 +59,14 @@ enum cam_lrme_cb_type { * @CAM_LRME_HW_CMD_REGISTER_CB : register HW manager callback * @CAM_LRME_HW_CMD_SUBMIT : Submit frame to HW * @CAM_LRME_HW_CMD_DUMP_REGISTER : dump register values + * @CAM_LRME_HW_CMD_DUMP : dump register values to buffer */ enum cam_lrme_hw_cmd_type { CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, CAM_LRME_HW_CMD_REGISTER_CB, CAM_LRME_HW_CMD_SUBMIT, CAM_LRME_HW_CMD_DUMP_REGISTER, + CAM_LRME_HW_CMD_DUMP, }; /** @@ -87,6 +89,7 @@ enum cam_lrme_hw_reset_type { * @hw_device : Pointer to HW device * @hw_update_entries : List of hw_update_entries * @num_hw_update_entries : number of hw_update_entries + * @submit_timestamp : timestamp of submitting request with hw */ struct cam_lrme_frame_request { struct list_head frame_list; @@ -95,6 +98,7 @@ struct cam_lrme_frame_request { struct cam_lrme_device *hw_device; struct cam_hw_update_entry hw_update_entries[CAM_LRME_MAX_HW_ENTRIES]; uint32_t num_hw_update_entries; + ktime_t submit_timestamp; }; /** @@ -192,4 +196,19 @@ struct cam_lrme_hw_submit_args { struct cam_lrme_frame_request *frame_req; }; +/** + * struct cam_lrme_hw_dump_args : Args for dump request + * + * @request_id : Issue request id + * @cpu_addr : start address of the target buffer + * @offset : offset of the buffer + * @buf_len : Length of target buffer + */ +struct cam_lrme_hw_dump_args { + uint64_t request_id; + uintptr_t cpu_addr; + size_t offset; + size_t buf_len; +}; + #endif /* _CAM_LRME_HW_INTF_H_ */ -- GitLab From 49bdc6fbcbbe949ff6d8bdd63d90bff30cdd7ecd Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 13 Jan 2020 17:14:33 +0530 Subject: [PATCH 208/410] msm: camera: core: Fix cpas axi clk rate overflow Change the clk variable type from int32_t to int64_t to avoid integer overflow. CRs-Fixed: 2609090 Change-Id: I9f785ce2c1e45b1e9a238c42e86da1161bf70f75 Signed-off-by: Ravikishore Pampana --- drivers/cam_cpas/cam_cpas_hw.c | 8 ++++---- drivers/cam_utils/cam_soc_util.c | 20 ++++++++++---------- drivers/cam_utils/cam_soc_util.h | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 5ae03680ad2f..3caa2c634927 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -425,7 +425,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( if (soc_private->control_camnoc_axi_clk) { struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; uint64_t required_camnoc_bw = 0, intermediate_result = 0; - int32_t clk_rate = 0; + int64_t clk_rate = 0; for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { tree_node = soc_private->tree_node[i]; @@ -454,7 +454,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( do_div(intermediate_result, soc_private->camnoc_bus_width); clk_rate = intermediate_result; - CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %lld", required_camnoc_bw, clk_rate); /* @@ -467,7 +467,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); if (rc) CAM_ERR(CAM_CPAS, - "Failed in setting camnoc axi clk %llu %d %d", + "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); } } diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 4e3dacaa822c..6c564fd8337f 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include @@ -17,7 +17,7 @@ static char supported_clk_info[256]; static char debugfs_dir_name[64]; int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t clk_rate, int clk_idx, int32_t *clk_lvl) + int64_t clk_rate, int clk_idx, int32_t *clk_lvl) { int i; long clk_rate_round; @@ -41,9 +41,9 @@ int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, (soc_info->clk_rate[i][clk_idx] >= clk_rate_round)) { CAM_DBG(CAM_UTIL, - "soc = %d round rate = %ld actual = %d", + "soc = %d round rate = %ld actual = %lld", soc_info->clk_rate[i][clk_idx], - clk_rate_round, clk_rate); + clk_rate_round, clk_rate); *clk_lvl = i; return 0; } @@ -380,7 +380,7 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, * @return: Success or failure */ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, - int32_t clk_rate) + int64_t clk_rate) { int rc = 0; long clk_rate_round; @@ -388,7 +388,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, if (!clk || !clk_name) return -EINVAL; - CAM_DBG(CAM_UTIL, "set %s, rate %d", clk_name, clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate); if (clk_rate > 0) { clk_rate_round = clk_round_rate(clk, clk_rate); CAM_DBG(CAM_UTIL, "new_rate %ld", clk_rate_round); @@ -424,7 +424,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, } int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate) + int64_t clk_rate) { int rc = 0; int i = 0; @@ -452,13 +452,13 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, &apply_level); if (rc || (apply_level < 0) || (apply_level >= CAM_MAX_VOTE)) { CAM_ERR(CAM_UTIL, - "set %s, rate %d dev_name = %s apply level = %d", + "set %s, rate %lld dev_name = %s apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); return -EINVAL; } - CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s apply level = %d", + CAM_DBG(CAM_UTIL, "set %s, rate %lld dev_name = %s apply level = %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, apply_level); @@ -471,7 +471,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, soc_info->clk_name[src_clk_idx], clk_rate); if (rc) { CAM_ERR(CAM_UTIL, - "SET_RATE Failed: src clk: %s, rate %d, dev_name = %s rc: %d", + "SET_RATE Failed: src clk: %s, rate %lld, dev_name = %s rc: %d", soc_info->clk_name[src_clk_idx], clk_rate, soc_info->dev_name, rc); return rc; diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 64320ca7b91d..0c6069322319 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SOC_UTIL_H_ @@ -382,7 +382,7 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, * @return: success or failure */ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int32_t clk_rate); + int64_t clk_rate); /** * cam_soc_util_get_option_clk_by_name() @@ -624,7 +624,7 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level); int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, - int32_t clk_rate, int clk_idx, int32_t *clk_lvl); + int64_t clk_rate, int clk_idx, int32_t *clk_lvl); /* Callback to get reg space data for specific HW */ typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type, -- GitLab From e8010f6cd3824392b1732526e327828d0bb2f9b4 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 9 Jan 2020 12:18:17 -0800 Subject: [PATCH 209/410] msm: camera: isp: Change data type for error handling Use unsigned long to capture the return value of wait_for_completion APIs as part of CSID path reset. CRs-Fixed: 2600604 Change-Id: Ic21ddf283180a177b2c2d9e9a33fec4ec68bdd98 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index dd9c6dd4c057..d311e41f1c1b 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -285,7 +285,7 @@ static int cam_ife_hw_mgr_reset_csid_res( rc = hw_intf->hw_ops.reset(hw_intf->hw_priv, &csid_reset_args, sizeof(struct cam_csid_reset_cfg_args)); - if (rc <= 0) + if (rc) goto err; } } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 8051a601fd9d..985cd134a465 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -527,6 +527,7 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, struct cam_csid_reset_cfg_args *reset) { int rc = 0; + unsigned long rem_jiffies; struct cam_hw_soc_info *soc_info; struct cam_isp_resource_node *res; const struct cam_ife_csid_reg_offset *csid_reg; @@ -646,14 +647,13 @@ static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, cam_io_w_mb(reset_strb_val, soc_info->reg_map[0].mem_base + reset_strb_addr); - rc = wait_for_completion_timeout(complete, + rem_jiffies = wait_for_completion_timeout(complete, msecs_to_jiffies(IFE_CSID_TIMEOUT)); - if (rc <= 0) { + if (!rem_jiffies) { + rc = -ETIMEDOUT; CAM_ERR(CAM_ISP, "CSID:%d Res id %d fail rc = %d", csid_hw->hw_intf->hw_idx, res->res_id, rc); - if (rc == 0) - rc = -ETIMEDOUT; } end: -- GitLab From 377c35c527d12fcfa37c139b35c1851e59548c39 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 18 Dec 2019 15:53:50 -0800 Subject: [PATCH 210/410] msm: camera: sensor: Add Init setting retry in case cci is resetting If any subdev is reporting Nack, cci hardware gets into resetting. During resetting if sensor tries to apply Init setting, it fails. This change adds retry for INIT setting to reapply after sometime. CRs-Fixed: 2598605 Change-Id: Iff13014d74abe6aebaec6cd428811de9d865f090 Signed-off-by: Jigarkumar Zala --- .../cam_actuator/cam_actuator_core.c | 15 ++++++++++--- .../cam_flash/cam_flash_core.c | 12 +++++++++- .../cam_sensor_module/cam_ois/cam_ois_core.c | 14 ++++++++++-- .../cam_sensor/cam_sensor_core.c | 22 +++++++++++++++---- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index d886d8ebaecb..0b6e25572e90 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -957,10 +957,19 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, ACT_APPLY_SETTINGS_NOW) { rc = cam_actuator_apply_settings(a_ctrl, &a_ctrl->i2c_data.init_settings); + if ((rc == -EAGAIN) && + (a_ctrl->io_master_info.master_type == CCI_MASTER)) { + CAM_WARN(CAM_ACTUATOR, + "CCI HW is in resetting mode:: Reapplying Init settings"); + usleep_range(1000, 1010); + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + } + if (rc < 0) CAM_ERR(CAM_ACTUATOR, - "Cannot apply Update settings"); - + "Failed to apply Init settings: rc = %d", + rc); /* Delete the request even if the apply is failed */ rc = delete_request(&a_ctrl->i2c_data.init_settings); if (rc < 0) { diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index 063848104f63..2d8df8a0ac41 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -662,6 +662,16 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, list) { rc = cam_sensor_util_i2c_apply_setting (&(fctrl->io_master_info), i2c_list); + if ((rc == -EAGAIN) && + (fctrl->io_master_info.master_type == + CCI_MASTER)) { + CAM_WARN(CAM_FLASH, + "CCI HW is in reset mode: Reapplying Init settings"); + usleep_range(1000, 1010); + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + } + if (rc) { CAM_ERR(CAM_FLASH, "Failed to apply init settings: %d", diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 8ced8a28c309..6a1ccbd4aa11 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -586,8 +586,18 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) } rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data); + if ((rc == -EAGAIN) && + (o_ctrl->io_master_info.master_type == CCI_MASTER)) { + CAM_WARN(CAM_OIS, + "CCI HW is restting: Reapplying INIT settings"); + usleep_range(1000, 1010); + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_init_data); + } if (rc < 0) { - CAM_ERR(CAM_OIS, "Cannot apply Init settings"); + CAM_ERR(CAM_OIS, + "Cannot apply Init settings: rc = %d", + rc); goto pwr_dwn; } diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 37f62fe95246..696bbd3b90cb 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -644,7 +644,7 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, void *arg) { - int rc = 0; + int rc = 0, pkt_opcode = 0; struct cam_control *cmd = (struct cam_control *)arg; struct cam_sensor_power_ctrl_t *power_info = &s_ctrl->sensordata->power_info; @@ -932,14 +932,28 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, if (s_ctrl->i2c_data.init_settings.is_settings_valid && (s_ctrl->i2c_data.init_settings.request_id == 0)) { + pkt_opcode = + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG; rc = cam_sensor_apply_settings(s_ctrl, 0, - CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG); - + pkt_opcode); + + if ((rc == -EAGAIN) && + (s_ctrl->io_master_info.master_type == CCI_MASTER)) { + /* If CCI hardware is resetting we need to wait + * for sometime before reapply + */ + CAM_WARN(CAM_SENSOR, + "Reapplying the Init settings due to cci hw reset"); + usleep_range(1000, 1010); + rc = cam_sensor_apply_settings(s_ctrl, 0, + pkt_opcode); + } s_ctrl->i2c_data.init_settings.request_id = -1; if (rc < 0) { CAM_ERR(CAM_SENSOR, - "cannot apply init settings"); + "cannot apply init settings rc= %d", + rc); delete_request(&s_ctrl->i2c_data.init_settings); goto release_mutex; } -- GitLab From 64c6e1ecd79dcc0f7c822a53359e76727381dc56 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Fri, 3 Jan 2020 18:37:51 +0530 Subject: [PATCH 211/410] msm: camera: cpas: Add support for camnoc based voting For some targets, it is needed to vote for camnoc clock as there is no CAMNOC AXI clock source in camera domain. Voting is done with the bus drivers and it calcultates the clock rate. This change adds support for camnoc based voting. CRs-Fixed: 2571273 Change-Id: I38a4fa8d40892b6dfe7e925b6368eb259132615d Signed-off-by: Gaurav Jindal --- drivers/cam_cpas/cam_cpas_hw.c | 166 +++++++++++++++++++++++++++----- drivers/cam_cpas/cam_cpas_hw.h | 8 +- drivers/cam_cpas/cam_cpas_soc.c | 56 ++++++++++- drivers/cam_cpas/cam_cpas_soc.h | 4 +- 4 files changed, 206 insertions(+), 28 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 5ae03680ad2f..829d00870d80 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -242,6 +242,12 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, return -EINVAL; } + if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", + cpas_core->num_camnoc_axi_ports); + return -EINVAL; + } + for (i = 0; i < cpas_core->num_axi_ports; i++) { cam_cpas_util_unregister_bus_client( &cpas_core->axi_port[i].bus_client); @@ -249,6 +255,13 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, cpas_core->axi_port[i].axi_port_node = NULL; } + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + cam_cpas_util_unregister_bus_client( + &cpas_core->camnoc_axi_port[i].bus_client); + of_node_put(cpas_core->camnoc_axi_port[i].axi_port_node); + cpas_core->camnoc_axi_port[i].axi_port_node = NULL; + } + return 0; } @@ -257,6 +270,7 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, { int i = 0, rc = 0; struct device_node *axi_port_mnoc_node = NULL; + struct device_node *axi_port_camnoc_node = NULL; if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", @@ -271,6 +285,15 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, if (rc) goto bus_register_fail; } + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + axi_port_camnoc_node = + cpas_core->camnoc_axi_port[i].axi_port_node; + rc = cam_cpas_util_register_bus_client(soc_info, + axi_port_camnoc_node, + &cpas_core->camnoc_axi_port[i].bus_client); + if (rc) + goto bus_register_fail; + } return 0; bus_register_fail: @@ -608,6 +631,99 @@ static int cam_cpas_axi_consolidate_path_votes( return rc; } +static int cam_cpas_update_axi_vote_bw( + struct cam_hw_info *cpas_hw, + struct cam_cpas_tree_node *cpas_tree_node, + bool *mnoc_axi_port_updated, + bool *camnoc_axi_port_updated) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + if (cpas_tree_node->axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d", + cpas_tree_node->axi_port_idx); + return -EINVAL; + } + + cpas_core->axi_port[cpas_tree_node->axi_port_idx].ab_bw = + cpas_tree_node->mnoc_ab_bw; + cpas_core->axi_port[cpas_tree_node->axi_port_idx].ib_bw = + cpas_tree_node->mnoc_ib_bw; + mnoc_axi_port_updated[cpas_tree_node->axi_port_idx] = true; + + if (soc_private->control_camnoc_axi_clk) + return 0; + + cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx].camnoc_bw = + cpas_tree_node->camnoc_bw; + camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true; + return 0; +} + +static int cam_cpas_camnoc_set_vote_axi_clk_rate( + struct cam_hw_info *cpas_hw, + bool *camnoc_axi_port_updated) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + int i; + int rc = 0; + struct cam_cpas_axi_port *camnoc_axi_port = NULL; + uint64_t camnoc_bw; + + if (soc_private->control_camnoc_axi_clk) { + rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); + if (rc) + CAM_ERR(CAM_CPAS, + "Failed in setting axi clk rate rc=%d", rc); + return rc; + } + + /* Below code is executed if we just vote and do not set the clk rate + * for camnoc + */ + + if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", + cpas_core->num_camnoc_axi_ports); + return -EINVAL; + } + + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + if (camnoc_axi_port_updated[i]) + camnoc_axi_port = &cpas_core->camnoc_axi_port[i]; + else + continue; + + CAM_DBG(CAM_PERF, "Port[%s] : camnoc_bw=%lld", + camnoc_axi_port->axi_port_name, + camnoc_axi_port->camnoc_bw); + + if (camnoc_axi_port->camnoc_bw) + camnoc_bw = camnoc_axi_port->camnoc_bw; + else + camnoc_bw = camnoc_axi_port->additional_bw; + + rc = cam_cpas_util_vote_bus_client_bw( + &camnoc_axi_port->bus_client, + 0, camnoc_bw, true); + + CAM_DBG(CAM_CPAS, + "camnoc vote camnoc_bw[%llu] rc=%d %s", + camnoc_bw, rc, camnoc_axi_port->axi_port_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in camnoc vote camnoc_bw[%llu] rc=%d", + camnoc_bw, rc); + break; + } + } + return rc; +} + static int cam_cpas_util_apply_client_axi_vote( struct cam_hw_info *cpas_hw, struct cam_cpas_client *cpas_client, @@ -615,12 +731,13 @@ static int cam_cpas_util_apply_client_axi_vote( { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_axi_vote *con_axi_vote = NULL; - struct cam_cpas_axi_port *axi_port = NULL; + struct cam_cpas_axi_port *mnoc_axi_port = NULL; struct cam_cpas_tree_node *curr_tree_node = NULL; struct cam_cpas_tree_node *par_tree_node = NULL; uint32_t transac_type; uint32_t path_data_type; - bool axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; + bool mnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; + bool camnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0, curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; @@ -643,7 +760,7 @@ static int cam_cpas_util_apply_client_axi_vote( cpas_core->axi_port[i].additional_bw -= CAM_CPAS_DEFAULT_AXI_BW; } - axi_port_updated[i] = true; + mnoc_axi_port_updated[i] = true; } goto vote_start_clients; } @@ -733,15 +850,15 @@ static int cam_cpas_util_apply_client_axi_vote( rc = -EINVAL; goto unlock_tree; } - - cpas_core->axi_port - [par_tree_node->axi_port_idx].ab_bw = - par_tree_node->mnoc_ab_bw; - cpas_core->axi_port - [par_tree_node->axi_port_idx].ib_bw = - par_tree_node->mnoc_ib_bw; - axi_port_updated[par_tree_node->axi_port_idx] = - true; + rc = cam_cpas_update_axi_vote_bw(cpas_hw, + par_tree_node, + mnoc_axi_port_updated, + camnoc_axi_port_updated); + if (rc) { + CAM_ERR(CAM_CPAS, + "Update Vote failed"); + goto unlock_tree; + } } curr_tree_node = par_tree_node; @@ -759,26 +876,27 @@ static int cam_cpas_util_apply_client_axi_vote( vote_start_clients: for (i = 0; i < cpas_core->num_axi_ports; i++) { - if (axi_port_updated[i]) - axi_port = &cpas_core->axi_port[i]; + if (mnoc_axi_port_updated[i]) + mnoc_axi_port = &cpas_core->axi_port[i]; else continue; CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld", - axi_port->axi_port_name, axi_port->ab_bw, - axi_port->ib_bw, axi_port->additional_bw); + mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw, + mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw); - if (axi_port->ab_bw) - mnoc_ab_bw = axi_port->ab_bw; + if (mnoc_axi_port->ab_bw) + mnoc_ab_bw = mnoc_axi_port->ab_bw; else - mnoc_ab_bw = axi_port->additional_bw; + mnoc_ab_bw = mnoc_axi_port->additional_bw; if (cpas_core->axi_port[i].ib_bw_voting_needed) - mnoc_ib_bw = axi_port->ib_bw; + mnoc_ib_bw = mnoc_axi_port->ib_bw; else mnoc_ib_bw = 0; - rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, + rc = cam_cpas_util_vote_bus_client_bw( + &mnoc_axi_port->bus_client, mnoc_ab_bw, mnoc_ib_bw, false); if (rc) { CAM_ERR(CAM_CPAS, @@ -787,8 +905,8 @@ static int cam_cpas_util_apply_client_axi_vote( goto unlock_tree; } } - - rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); + rc = cam_cpas_camnoc_set_vote_axi_clk_rate( + cpas_hw, camnoc_axi_port_updated); if (rc) CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index b3c01b3ee737..cfa7dfbb69b2 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_HW_H_ @@ -153,6 +153,7 @@ struct cam_cpas_bus_client { * @axi_port_node: Node representing AXI Port info in device tree * @ab_bw: AB bw value for this port * @ib_bw: IB bw value for this port + * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients */ struct cam_cpas_axi_port { @@ -162,6 +163,7 @@ struct cam_cpas_axi_port { struct device_node *axi_port_node; uint64_t ab_bw; uint64_t ib_bw; + uint64_t camnoc_bw; uint64_t additional_bw; }; @@ -174,11 +176,13 @@ struct cam_cpas_axi_port { * @tree_lock: Mutex lock for accessing CPAS node tree * @num_clients: Total number of clients that CPAS supports * @num_axi_ports: Total number of axi ports found in device tree + * @num_camnoc_axi_ports: Total number of camnoc axi ports found in device tree * @registered_clients: Number of Clients registered currently * @streamon_clients: Number of Clients that are in start state currently * @regbase_index: Register base indices for CPAS register base IDs * @ahb_bus_client: AHB Bus client info * @axi_port: AXI port info for a specific axi index + * @camnoc_axi_port: CAMNOC AXI port info for a specific camnoc axi index * @internal_ops: CPAS HW internal ops * @work_queue: Work queue handle * @irq_count: atomic irq count @@ -193,11 +197,13 @@ struct cam_cpas { struct mutex tree_lock; uint32_t num_clients; uint32_t num_axi_ports; + uint32_t num_camnoc_axi_ports; uint32_t registered_clients; uint32_t streamon_clients; int32_t regbase_index[CAM_CPAS_REG_MAX]; struct cam_cpas_bus_client ahb_bus_client; struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS]; + struct cam_cpas_axi_port camnoc_axi_port[CAM_CPAS_MAX_AXI_PORTS]; struct cam_cpas_internal_ops internal_ops; struct workqueue_struct *work_queue; atomic_t irq_count; diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index c86753dd24d9..3b4e4fb25275 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -134,6 +134,47 @@ static int cam_cpas_util_path_type_to_idx(uint32_t *path_data_type) return 0; } +static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core, + struct device_node *curr_node, + struct cam_cpas_tree_node *cpas_node_ptr, + int *camnoc_idx) + +{ + struct device_node *camnoc_node; + int rc; + + camnoc_node = of_find_node_by_name(curr_node, + "qcom,axi-port-camnoc"); + if (camnoc_node) { + + if (*camnoc_idx >= + CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "CAMNOC axi index overshoot %d", + *camnoc_idx); + return -EINVAL; + } + + cpas_core->camnoc_axi_port[*camnoc_idx] + .axi_port_node = camnoc_node; + rc = of_property_read_string( + curr_node, + "qcom,axi-port-name", + &cpas_core->camnoc_axi_port[*camnoc_idx] + .axi_port_name); + + if (rc) { + CAM_ERR(CAM_CPAS, + "fail to read camnoc-port-name rc=%d", + rc); + return rc; + } + cpas_node_ptr->camnoc_axi_port_idx = *camnoc_idx; + cpas_core->num_camnoc_axi_ports++; + (*camnoc_idx)++; + } + return 0; +} + static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *of_node, struct cam_cpas_private_soc *soc_private) { @@ -142,7 +183,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *curr_node; struct device_node *parent_node; struct device_node *mnoc_node; - int mnoc_idx = 0; + int mnoc_idx = 0, camnoc_idx = 0; uint32_t path_idx; bool camnoc_max_needed = false; struct cam_cpas_tree_node *curr_node_ptr = NULL; @@ -248,6 +289,17 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, cpas_core->num_axi_ports++; } + if (!soc_private->control_camnoc_axi_clk) { + rc = cam_cpas_update_camnoc_node( + cpas_core, curr_node, curr_node_ptr, + &camnoc_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "Parse Camnoc port fail"); + return rc; + } + } + rc = of_property_read_string(curr_node, "client-name", &client_name); if (!rc) { diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index fea9c3c97593..503efc20e8b8 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_SOC_H_ @@ -30,6 +30,7 @@ struct cam_cpas_vdd_ahb_mapping { * @cell_idx: Index to identify node from device tree and its parent * @level_idx: Index to identify at what level the node is present * @axi_port_idx: Index to identify which axi port to vote the consolidated bw + * @camnoc_axi_port_idx: Index to find which axi port to vote consolidated bw * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc) * @path_trans_type: Transaction type info from device tree (rd, wr) * @merge_type: Traffic merge type (calculation info) from device tree @@ -53,6 +54,7 @@ struct cam_cpas_tree_node { uint32_t cell_idx; uint32_t level_idx; int axi_port_idx; + int camnoc_axi_port_idx; const char *node_name; uint32_t path_data_type; uint32_t path_trans_type; -- GitLab From 2dad6bd09d2dbb8cdd87e1991b54f67b5c24b5a9 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 5 Dec 2019 16:30:26 -0800 Subject: [PATCH 212/410] msm: camera: sensor: Notify completion in error case There is no need to wait till timeout in case of NACK or underflow error irq is raised, so notify thread for rd_done completion. Also, correct the error mask to catch the NACK error for Master 1. CRs-Fixed: 2598605 Change-Id: Ib8a16ee119dd81f1384283ac7e9f82d3ac2588bb Signed-off-by: Jigarkumar Zala Signed-off-by: Depeng Shao Signed-off-by: Karthik Jayakumar --- .../cam_sensor_module/cam_cci/cam_cci_core.c | 75 +++++++++++++++++-- .../cam_sensor_module/cam_cci/cam_cci_dev.c | 48 +++++++++--- .../cam_sensor_module/cam_cci/cam_cci_hwreg.h | 8 +- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 3 + 4 files changed, 113 insertions(+), 21 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index a0d1cbe058d9..4a2a643a7408 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -42,6 +42,9 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, void __iomem *base = soc_info->reg_map[0].mem_base; cam_io_w_mb(1 << master, base + CCI_HALT_REQ_ADDR); + if (!cci_dev->cci_master_info[master].status) + reinit_completion(&cci_dev->cci_master_info[master] + .reset_complete); rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc < 0) { @@ -51,6 +54,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, /* Set reset pending flag to true */ cci_dev->cci_master_info[master].reset_pending = true; + cci_dev->cci_master_info[master].status = 0; /* Set proper mask to RESET CMD address based on MASTER */ if (master == MASTER_0) @@ -66,6 +70,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, CCI_TIMEOUT); if (rc <= 0) CAM_ERR(CAM_CCI, "wait failed %d", rc); + cci_dev->cci_master_info[master].status = 0; } } @@ -127,8 +132,10 @@ static int32_t cam_cci_validate_queue(struct cci_device *cci_dev, return rc; } rc = cci_dev->cci_master_info[master].status; - if (rc < 0) + if (rc < 0) { CAM_ERR(CAM_CCI, "Failed rc %d", rc); + cci_dev->cci_master_info[master].status = 0; + } } return rc; @@ -246,14 +253,16 @@ static uint32_t cam_cci_wait(struct cci_device *cci_dev, cam_cci_dump_registers(cci_dev, master, queue); #endif CAM_ERR(CAM_CCI, "wait for queue: %d", queue); - if (rc == 0) + if (rc == 0) { rc = -ETIMEDOUT; - cam_cci_flush_queue(cci_dev, master); - return rc; + cam_cci_flush_queue(cci_dev, master); + return rc; + } } rc = cci_dev->cci_master_info[master].status; if (rc < 0) { CAM_ERR(CAM_CCI, "failed rc %d", rc); + cci_dev->cci_master_info[master].status = 0; return rc; } @@ -851,7 +860,8 @@ static int32_t cam_cci_data_queue(struct cci_device *cci_dev, rc = cam_cci_transfer_end(cci_dev, master, queue); if (rc < 0) { - CAM_ERR(CAM_CCI, "failed rc %d", rc); + CAM_ERR(CAM_CCI, "Slave: 0x%x failed rc %d", + (c_ctrl->cci_info->sid << 1), rc); return rc; } @@ -918,6 +928,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, mutex_unlock(&cci_dev->cci_master_info[master].mutex); mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1024,6 +1035,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, goto rel_mutex_q; } + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "Error with Salve: 0x%x", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } + read_words = cam_io_r_mb(base + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); if (read_words <= 0) { @@ -1104,6 +1123,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, cam_cci_flush_queue(cci_dev, master); goto rel_mutex_q; } + + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "Error with Slave 0x%x", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } break; } } @@ -1183,6 +1210,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, mutex_unlock(&cci_dev->cci_master_info[master].mutex); mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1290,6 +1318,14 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, rc = 0; } + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "ERROR with Slave 0x%x:", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } + read_words = cam_io_r_mb(base + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); exp_words = ((read_cfg->num_byte / 4) + 1); @@ -1384,6 +1420,8 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, goto ERROR; } mutex_unlock(&cci_dev->cci_master_info[master].mutex); + + reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_write call. This is to @@ -1546,6 +1584,7 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, * THRESHOLD irq's, we reinit the threshold wait before * we load the burst read cmd. */ + reinit_completion(&cci_dev->cci_master_info[master].rd_done); reinit_completion(&cci_dev->cci_master_info[master].th_complete); CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes); @@ -1687,7 +1726,29 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, { int32_t rc = 0; struct cci_device *cci_dev = v4l2_get_subdevdata(sd); - CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + enum cci_i2c_master_t master = MASTER_MAX; + + if (!cci_dev) { + CAM_ERR(CAM_CCI, "CCI_DEV IS NULL"); + return -EINVAL; + } + + if (!cci_ctrl) { + CAM_ERR(CAM_CCI, "CCI_CTRL IS NULL"); + return -EINVAL; + } + + master = cci_ctrl->cci_info->cci_i2c_master; + if (master >= MASTER_MAX) { + CAM_ERR(CAM_CCI, "INVALID MASTER: %d", master); + return -EINVAL; + } + + if (cci_dev->cci_master_info[master].status < 0) { + CAM_WARN(CAM_CCI, "CCI hardware is resetting"); + return -EAGAIN; + } + CAM_DBG(CAM_CCI, "master = %d, cmd = %d", master, cci_ctrl->cmd); switch (cci_ctrl->cmd) { case MSM_CCI_INIT: diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index e52e16cb5f96..855fe5e68573 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_cci_dev.h" @@ -82,7 +82,9 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); - cci_master_info->status = 0; + + complete_all(&cci_master_info->rd_done); + complete_all(&cci_master_info->th_complete); } if (cci_dev->cci_master_info[MASTER_1].reset_pending == true) { cci_master_info = &cci_dev->cci_master_info[MASTER_1]; @@ -90,7 +92,9 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); - cci_master_info->status = 0; + + complete_all(&cci_master_info->rd_done); + complete_all(&cci_master_info->th_complete); } } @@ -223,9 +227,18 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) - CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x", + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q0 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q1 NACK ERROR: 0x%x", base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_1]); + } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", @@ -234,22 +247,35 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) CAM_ERR(CAM_CCI, "Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x", base, irq_status0); - cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + + cci_dev->cci_master_info[MASTER_0].reset_pending = true; + cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) - CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x", + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q0 NACK ERROR: 0x%x", base, irq_status0); - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q1 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_1]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", base, irq_status0); - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x", base, irq_status0); - cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + + cci_dev->cci_master_info[MASTER_1].reset_pending = true; + cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h index f00b854e9533..73756a301f7a 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2015, 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_HWREG_ @@ -54,8 +54,10 @@ #define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 #define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 #define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 -#define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK 0x18000000 -#define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK 0x60000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK 0x8000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK 0x10000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK 0x20000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK 0x40000000 #define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 #define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 #define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index 82f1c61cf8fe..ff74be5eb9f9 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -54,6 +54,7 @@ int cam_cci_init(struct v4l2_subdev *sd, &cci_dev->cci_master_info[master].report_q[i]); /* Set reset pending flag to true */ cci_dev->cci_master_info[master].reset_pending = true; + cci_dev->cci_master_info[master].status = 0; /* Set proper mask to RESET CMD address */ if (master == MASTER_0) cam_io_w_mb(CCI_M0_RESET_RMSK, @@ -67,6 +68,7 @@ int cam_cci_init(struct v4l2_subdev *sd, CCI_TIMEOUT); if (rc <= 0) CAM_ERR(CAM_CCI, "wait failed %d", rc); + cci_dev->cci_master_info[master].status = 0; mutex_unlock(&cci_dev->cci_master_info[master].mutex); } return 0; @@ -132,6 +134,7 @@ int cam_cci_init(struct v4l2_subdev *sd, } cci_dev->cci_master_info[master].reset_pending = true; + cci_dev->cci_master_info[master].status = 0; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); -- GitLab From ef4e88e5004d80f0c1083db9f43ad00cd95d7036 Mon Sep 17 00:00:00 2001 From: Sravan Muppidi Date: Tue, 24 Dec 2019 15:54:42 +0530 Subject: [PATCH 213/410] msm: camera: jpeg: Check the HW state before accessing register Check the hardware state before accessing registers to prevent unclocked access. CRs-Fixed: 2598203 Change-Id: I136b00d157d846c6582d80b8bf2be6b1238af50f Signed-off-by: Sravan Muppidi --- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 4830bf58e89e..c38d873b35a9 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -42,6 +42,7 @@ int cam_jpeg_enc_init_hw(void *device_priv, struct cam_jpeg_enc_device_core_info *core_info = NULL; struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote = {0}; + unsigned long flags; int rc; if (!device_priv) { @@ -92,6 +93,9 @@ int cam_jpeg_enc_init_hw(void *device_priv, CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc); goto soc_failed; } + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_UP; + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); mutex_unlock(&core_info->core_mutex); @@ -112,6 +116,7 @@ int cam_jpeg_enc_deinit_hw(void *device_priv, struct cam_hw_info *jpeg_enc_dev = device_priv; struct cam_hw_soc_info *soc_info = NULL; struct cam_jpeg_enc_device_core_info *core_info = NULL; + unsigned long flags; int rc; if (!device_priv) { @@ -141,6 +146,9 @@ int cam_jpeg_enc_deinit_hw(void *device_priv, return -EFAULT; } + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); rc = cam_jpeg_enc_disable_soc_resources(soc_info); if (rc) CAM_ERR(CAM_JPEG, "soc disable failed %d", rc); @@ -174,12 +182,19 @@ irqreturn_t cam_jpeg_enc_irq(int irq_num, void *data) hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; + spin_lock(&jpeg_enc_dev->hw_lock); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + return IRQ_HANDLED; + } irq_status = cam_io_r_mb(mem_base + core_info->jpeg_enc_hw_info->reg_offset.int_status); cam_io_w_mb(irq_status, soc_info->reg_map[0].mem_base + core_info->jpeg_enc_hw_info->reg_offset.int_clr); + spin_unlock(&jpeg_enc_dev->hw_lock); CAM_DBG(CAM_JPEG, "irq_num %d irq_status = %x , core_state %d", irq_num, irq_status, core_info->core_state); @@ -255,6 +270,7 @@ int cam_jpeg_enc_reset_hw(void *data, struct cam_jpeg_enc_device_hw_info *hw_info = NULL; void __iomem *mem_base; unsigned long rem_jiffies; + unsigned long flags; if (!jpeg_enc_dev) { CAM_ERR(CAM_JPEG, "Invalid args"); @@ -268,17 +284,23 @@ int cam_jpeg_enc_reset_hw(void *data, mem_base = soc_info->reg_map[0].mem_base; mutex_lock(&core_info->core_mutex); - spin_lock(&jpeg_enc_dev->hw_lock); + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) { CAM_ERR(CAM_JPEG, "alrady resetting"); - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); mutex_unlock(&core_info->core_mutex); return 0; } reinit_completion(&jpeg_enc_dev->hw_complete); core_info->core_state = CAM_JPEG_ENC_CORE_RESETTING; - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); cam_io_w_mb(hw_info->reg_val.int_mask_disable_all, mem_base + hw_info->reg_offset.int_mask); @@ -308,6 +330,7 @@ int cam_jpeg_enc_start_hw(void *data, struct cam_hw_soc_info *soc_info = NULL; struct cam_jpeg_enc_device_hw_info *hw_info = NULL; void __iomem *mem_base; + unsigned long flags; if (!jpeg_enc_dev) { CAM_ERR(CAM_JPEG, "Invalid args"); @@ -320,10 +343,18 @@ int cam_jpeg_enc_start_hw(void *data, hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); + return -EINVAL; + } if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) { - CAM_ERR(CAM_JPEG, "Error not ready"); + CAM_ERR(CAM_JPEG, "Error not ready: %d", core_info->core_state); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); return -EINVAL; } + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); cam_io_w_mb(hw_info->reg_val.hw_cmd_start, mem_base + hw_info->reg_offset.hw_cmd); @@ -340,6 +371,7 @@ int cam_jpeg_enc_stop_hw(void *data, struct cam_jpeg_enc_device_hw_info *hw_info = NULL; void __iomem *mem_base; unsigned long rem_jiffies; + unsigned long flags; if (!jpeg_enc_dev) { CAM_ERR(CAM_JPEG, "Invalid args"); @@ -352,17 +384,23 @@ int cam_jpeg_enc_stop_hw(void *data, mem_base = soc_info->reg_map[0].mem_base; mutex_lock(&core_info->core_mutex); - spin_lock(&jpeg_enc_dev->hw_lock); + spin_lock_irqsave(&jpeg_enc_dev->hw_lock, flags); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); + mutex_unlock(&core_info->core_mutex); + return -EINVAL; + } if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { CAM_ERR(CAM_JPEG, "alrady stopping"); - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); mutex_unlock(&core_info->core_mutex); return 0; } reinit_completion(&jpeg_enc_dev->hw_complete); core_info->core_state = CAM_JPEG_ENC_CORE_ABORTING; - spin_unlock(&jpeg_enc_dev->hw_lock); + spin_unlock_irqrestore(&jpeg_enc_dev->hw_lock, flags); cam_io_w_mb(hw_info->reg_val.hw_cmd_stop, mem_base + hw_info->reg_offset.hw_cmd); -- GitLab From 47c185f9bf84a62761bf93e8249f3e9943283c7b Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 21 Aug 2019 16:47:23 -0700 Subject: [PATCH 214/410] msm: camera: isp: Add support for offline IFE This change adds new IRQ state machine and updates the acquire logic to enable offline IFE. This change also adds the fixes necessary to enable bus read for various buffer formats and append go command at the end of each packet for offline context. CRs-Fixed: 2513939 Change-Id: Ie068670ed11aa6713e8f0cb817e4b5d4c209e696 Signed-off-by: Venkat Chinta Signed-off-by: Vishalsingh Hajeri --- drivers/cam_isp/cam_isp_context.c | 207 ++++- drivers/cam_isp/cam_isp_context.h | 5 + drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 710 ++++++++++-------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 6 +- .../hw_utils/cam_isp_packet_parser.c | 99 ++- .../hw_utils/include/cam_isp_packet_parser.h | 19 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 1 + .../isp_hw/include/cam_ife_csid_hw_intf.h | 1 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 3 +- .../isp_hw/include/cam_vfe_hw_intf.h | 33 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 1 + .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 1 + .../vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c | 662 +++++++++------- .../vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h | 3 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 57 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 4 +- 16 files changed, 1219 insertions(+), 593 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 372af656cd71..af2ccee2a164 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -965,6 +965,96 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( return rc; } +static int __cam_isp_ctx_apply_req_offline( + struct cam_context *ctx, uint32_t next_state, + struct cam_isp_context *ctx_isp) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_hw_config_args cfg; + + if (list_empty(&ctx->pending_req_list)) { + CAM_DBG(CAM_ISP, "No pending requests to apply"); + rc = -EFAULT; + goto end; + } + + if (ctx->state != CAM_CTX_ACTIVATED) + goto end; + + if (ctx_isp->active_req_cnt >= 2) + goto end; + + req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + list); + + CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u", + req->request_id, ctx_isp->substate_activated, ctx->ctx_id); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + memset(&cfg, 0, sizeof(cfg)); + + cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; + cfg.request_id = req->request_id; + cfg.hw_update_entries = req_isp->cfg; + cfg.num_hw_update_entries = req_isp->num_cfg; + cfg.priv = &req_isp->hw_update_data; + cfg.init_packet = 0; + + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration"); + } else { + atomic_set(&ctx_isp->rxd_epoch, 0); + ctx_isp->substate_activated = next_state; + ctx_isp->last_applied_req_id = req->request_id; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->wait_req_list); + CAM_DBG(CAM_ISP, "New substate state %d, applied req %lld", + next_state, ctx_isp->last_applied_req_id); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_offline_epoch_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_context *ctx = ctx_isp->base; + struct cam_ctx_request *req, *req_temp; + uint64_t request_id = 0; + + atomic_set(&ctx_isp->rxd_epoch, 1); + + CAM_DBG(CAM_ISP, "SOF frame %lld ctx %u", ctx_isp->frame_id, + ctx->ctx_id); + + list_for_each_entry_safe(req, req_temp, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_apply_req_offline(ctx, CAM_ISP_CTX_ACTIVATED_APPLIED, + ctx_isp); + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, + request_id); + + return 0; +} + static int __cam_isp_ctx_reg_upd_in_epoch_bubble_state( struct cam_isp_context *ctx_isp, void *evt_data) { @@ -1738,6 +1828,9 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, } while (req->request_id < ctx_isp->last_applied_req_id); + if (ctx_isp->offline_context) + goto exit; + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { notify.link_hdl = ctx->link_hdl; notify.dev_hdl = ctx->dev_hdl; @@ -1788,6 +1881,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, CAM_DBG(CAM_ISP, "Exit"); +exit: return rc; } @@ -2171,6 +2265,63 @@ static struct cam_isp_ctx_irq_ops }, }; +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_offline_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_applied_state, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + NULL, + NULL, + __cam_isp_ctx_offline_epoch_in_activated_state, + NULL, + __cam_isp_ctx_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + }, + /* Bubble Applied */ + { + }, + /* HW ERROR */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_hw_error, + NULL, + NULL, + NULL, + }, + }, + /* HALT */ + { + }, +}; + static int __cam_isp_ctx_apply_req_in_activated_state( struct cam_context *ctx, struct cam_req_mgr_apply_request *apply, enum cam_isp_ctx_activated_substate next_state) @@ -2722,6 +2873,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( end: ctx_isp->bubble_frame_cnt = 0; atomic_set(&ctx_isp->process_bubble, 0); + atomic_set(&ctx_isp->rxd_epoch, 0); return rc; } @@ -3606,8 +3758,11 @@ static int __cam_isp_ctx_config_dev_in_top_state( ctx->state); } } else { - if (ctx->state != CAM_CTX_FLUSHED && ctx->state >= CAM_CTX_READY - && ctx->ctx_crm_intf->add_req) { + if (ctx_isp->offline_context) { + __cam_isp_ctx_enqueue_request_in_order(ctx, req); + } else if ((ctx->state != CAM_CTX_FLUSHED) && + (ctx->state >= CAM_CTX_READY) && + ctx->ctx_crm_intf->add_req) { add_req.link_hdl = ctx->link_hdl; add_req.dev_hdl = ctx->dev_hdl; add_req.req_id = req->request_id; @@ -3634,6 +3789,13 @@ static int __cam_isp_ctx_config_dev_in_top_state( "Preprocessing Config req_id %lld successful on ctx %u", req->request_id, ctx->ctx_id); + if (ctx_isp->offline_context && atomic_read(&ctx_isp->rxd_epoch)) { + spin_lock_bh(&ctx->lock); + __cam_isp_ctx_apply_req_offline(ctx, + CAM_ISP_CTX_ACTIVATED_APPLIED, ctx_isp); + spin_unlock_bh(&ctx->lock); + } + return rc; put_ref: @@ -3748,11 +3910,15 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, cam_isp_ctx_rdi_only_activated_state_machine; ctx_isp->rdi_only_context = true; } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { - CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + CAM_DBG(CAM_ISP, "FS2 Session has PIX, RD and RDI"); ctx_isp->substate_machine_irq = cam_isp_ctx_fs2_state_machine_irq; ctx_isp->substate_machine = cam_isp_ctx_fs2_state_machine; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_OFFLINE) { + CAM_DBG(CAM_ISP, "offline Session has PIX and RD resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_offline_state_machine_irq; } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -3906,11 +4072,16 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, cam_isp_ctx_rdi_only_activated_state_machine; ctx_isp->rdi_only_context = true; } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { - CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + CAM_DBG(CAM_ISP, "FS2 Session has PIX, RD and RDI"); ctx_isp->substate_machine_irq = cam_isp_ctx_fs2_state_machine_irq; ctx_isp->substate_machine = cam_isp_ctx_fs2_state_machine; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_OFFLINE) { + CAM_DBG(CAM_ISP, "Offline session has PIX and RD resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_offline_state_machine_irq; + ctx_isp->substate_machine = NULL; } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -4057,11 +4228,17 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, cam_isp_ctx_rdi_only_activated_state_machine; ctx_isp->rdi_only_context = true; } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { - CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + CAM_DBG(CAM_ISP, "FS2 Session has PIX, RD and RDI"); ctx_isp->substate_machine_irq = cam_isp_ctx_fs2_state_machine_irq; ctx_isp->substate_machine = cam_isp_ctx_fs2_state_machine; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_OFFLINE) { + CAM_DBG(CAM_ISP, "Offline Session has PIX and RD resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_offline_state_machine_irq; + ctx_isp->substate_machine = NULL; + ctx_isp->offline_context = true; } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -4128,11 +4305,10 @@ static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx, rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd); - if (!rc && (ctx->link_hdl >= 0)) { + if (!rc && ((ctx->link_hdl >= 0) || ctx_isp->offline_context)) { ctx->state = CAM_CTX_READY; trace_cam_context_state("ISP", ctx); } - CAM_DBG(CAM_ISP, "next state %d", ctx->state); return rc; } @@ -4289,6 +4465,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, start_isp.start_only = false; atomic_set(&ctx_isp->process_bubble, 0); + atomic_set(&ctx_isp->rxd_epoch, 0); ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -4311,11 +4488,24 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, */ list_del_init(&req->list); - if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) { + if (ctx_isp->offline_context && !req_isp->num_fence_map_out) { + list_add_tail(&req->list, &ctx->free_req_list); + atomic_set(&ctx_isp->rxd_epoch, 1); + CAM_DBG(CAM_REQ, + "Move pending req: %lld to free list(cnt: %d) offline ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } else if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) { list_add_tail(&req->list, &ctx->wait_req_list); + CAM_DBG(CAM_REQ, + "Move pending req: %lld to wait list(cnt: %d) ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; + CAM_DBG(CAM_REQ, + "Move pending req: %lld to active list(cnt: %d) ctx %u offline %d", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id, + ctx_isp->offline_context); } /* @@ -4460,6 +4650,7 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( ctx_isp->last_applied_req_id = 0; ctx_isp->req_info.last_bufdone_req_id = 0; atomic_set(&ctx_isp->process_bubble, 0); + atomic_set(&ctx_isp->rxd_epoch, 0); atomic64_set(&ctx_isp->state_monitor_head, -1); for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index d91f5eea02e9..d5e2f1bac0e3 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -245,12 +245,15 @@ struct cam_isp_context_event_record { * @event_record: Event record array * @rdi_only_context: Get context type information. * true, if context is rdi only context + * @offline_context: Indicate whether context is for offline IFE * @hw_acquired: Indicate whether HW resources are acquired * @init_received: Indicate whether init config packet is received * @split_acquire: Indicate whether a separate acquire is expected * @custom_enabled: Custom HW enabled for this ctx * @use_frame_header_ts: Use frame header for qtimer ts * @init_timestamp: Timestamp at which this context is initialized + * @rxd_epoch: Indicate whether epoch has been received. Used to + * decide whether to apply request in offline ctx * */ struct cam_isp_context { @@ -283,12 +286,14 @@ struct cam_isp_context { struct cam_isp_context_event_record event_record[ CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES]; bool rdi_only_context; + bool offline_context; bool hw_acquired; bool init_received; bool split_acquire; bool custom_enabled; bool use_frame_header_ts; unsigned int init_timestamp; + atomic_t rxd_epoch; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index d311e41f1c1b..f1fc8fb44c8d 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -996,91 +996,6 @@ static int cam_ife_mgr_process_base_info( return 0; } -static int cam_ife_hw_mgr_acquire_res_bus_rd( - struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_in_port_generic_info *in_port) -{ - int rc = -EINVAL; - struct cam_vfe_acquire_args vfe_acquire; - struct cam_ife_hw_mgr_res *ife_in_rd_res; - struct cam_hw_intf *hw_intf; - struct cam_ife_hw_mgr_res *ife_src_res; - int i; - - CAM_DBG(CAM_ISP, "Enter"); - - list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { - if (ife_src_res->res_id != CAM_ISP_HW_VFE_IN_RD) - continue; - - rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, - &ife_in_rd_res); - if (rc) { - CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; - } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd, - &ife_in_rd_res); - - vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD; - vfe_acquire.tasklet = ife_ctx->common.tasklet_info; - vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; - vfe_acquire.priv = ife_ctx; - vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; - vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!ife_src_res->hw_res[i]) - continue; - - hw_intf = ife_src_res->hw_res[i]->hw_intf; - if (i == CAM_ISP_HW_SPLIT_LEFT) { - vfe_acquire.vfe_out.split_id = - CAM_ISP_HW_SPLIT_LEFT; - if (ife_src_res->is_dual_vfe) { - /*TBD */ - vfe_acquire.vfe_out.is_master = 1; - vfe_acquire.vfe_out.dual_slave_core = - ife_ctx->slave_hw_idx; - } else { - vfe_acquire.vfe_out.is_master = 0; - vfe_acquire.vfe_out.dual_slave_core = - 0; - } - } else { - vfe_acquire.vfe_out.split_id = - CAM_ISP_HW_SPLIT_RIGHT; - vfe_acquire.vfe_out.is_master = 0; - vfe_acquire.vfe_out.dual_slave_core = - ife_ctx->master_hw_idx; - } - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &vfe_acquire, - sizeof(struct cam_vfe_acquire_args)); - if (rc) { - CAM_ERR(CAM_ISP, - "Can not acquire out resource 0x%x", - vfe_acquire.rsrc_type); - goto err; - } - - ife_in_rd_res->hw_res[i] = - vfe_acquire.vfe_out.rsrc_node; - CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", - ife_in_rd_res->hw_res[i]->res_type, - ife_in_rd_res->hw_res[i]->res_id); - - } - ife_in_rd_res->is_dual_vfe = in_port->usage_type; - ife_in_rd_res->res_type = (enum cam_ife_hw_mgr_res_type) - CAM_ISP_RESOURCE_VFE_BUS_RD; - } - - return 0; -err: - CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc); - return rc; -} - static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_ife_hw_mgr_res *ife_src_res, @@ -1322,132 +1237,6 @@ static int cam_ife_hw_mgr_acquire_res_ife_out( return rc; } -static int cam_ife_hw_mgr_acquire_res_ife_rd_src( - struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_in_port_generic_info *in_port) -{ - int rc = -1; - struct cam_ife_hw_mgr_res *csid_res; - struct cam_ife_hw_mgr_res *ife_src_res; - struct cam_vfe_acquire_args vfe_acquire; - struct cam_hw_intf *hw_intf; - struct cam_ife_hw_mgr *ife_hw_mgr; - int vfe_idx = -1, i = 0; - - ife_hw_mgr = ife_ctx->hw_mgr; - - CAM_DBG(CAM_ISP, "Enter"); - list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) { - if (csid_res->res_id != CAM_IFE_PIX_PATH_RES_RDI_0) { - CAM_DBG(CAM_ISP, "not RDI0: %d", csid_res->res_id); - continue; - } - - rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, - &ife_src_res); - if (rc) { - CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; - } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, - &ife_src_res); - - CAM_DBG(CAM_ISP, "csid_res_id %d", csid_res->res_id); - vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; - vfe_acquire.tasklet = ife_ctx->common.tasklet_info; - vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; - vfe_acquire.vfe_in.in_port = in_port; - vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RD; - vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; - - ife_src_res->res_type = - (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; - ife_src_res->res_id = vfe_acquire.vfe_in.res_id; - ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; - - hw_intf = - ife_hw_mgr->ife_devices[csid_res->hw_res[ - CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx]; - - vfe_idx = csid_res->hw_res[ - CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx; - - /* - * fill in more acquire information as needed - */ - if (ife_src_res->is_dual_vfe) - vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; - - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &vfe_acquire, - sizeof(struct cam_vfe_acquire_args)); - if (rc) { - CAM_ERR(CAM_ISP, - "Can not acquire IFE HW res %d", - csid_res->res_id); - goto err; - } - ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT] = - vfe_acquire.vfe_in.rsrc_node; - CAM_DBG(CAM_ISP, - "acquire success IFE:%d res type :0x%x res id:0x%x", - hw_intf->hw_idx, - ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_type, - ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_id); - - if (!ife_src_res->is_dual_vfe) - goto acq; - - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (i == CAM_ISP_HW_SPLIT_LEFT) { - CAM_DBG(CAM_ISP, "vfe_idx %d is acquired", - vfe_idx); - continue; - } - - hw_intf = ife_hw_mgr->ife_devices[i]; - - /* fill in more acquire information as needed */ - if (i == CAM_ISP_HW_SPLIT_RIGHT) - vfe_acquire.vfe_in.sync_mode = - CAM_ISP_HW_SYNC_SLAVE; - - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &vfe_acquire, - sizeof(struct cam_vfe_acquire_args)); - if (rc) { - CAM_ERR(CAM_ISP, - "Can not acquire IFE HW res %d", - csid_res->res_id); - goto err; - } - ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; - CAM_DBG(CAM_ISP, - "acquire success IFE:%d res type :0x%x res id:0x%x", - hw_intf->hw_idx, - ife_src_res->hw_res[i]->res_type, - ife_src_res->hw_res[i]->res_id); - } -acq: - /* - * It should be one to one mapping between - * csid resource and ife source resource - */ - csid_res->child[0] = ife_src_res; - ife_src_res->parent = csid_res; - csid_res->child[csid_res->num_children++] = ife_src_res; - CAM_DBG(CAM_ISP, - "csid_res=%d CSID num_children=%d ife_src_res=%d", - csid_res->res_id, csid_res->num_children, - ife_src_res->res_id); - } - -err: - /* release resource at the entry function */ - CAM_DBG(CAM_ISP, "Exit rc %d", rc); - return rc; -} - static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx) { uint32_t hw_version, rc = 0; @@ -1563,6 +1352,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( vfe_acquire.tasklet = ife_ctx->common.tasklet_info; vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.vfe_in.is_fe_enabled = ife_ctx->is_fe_enabled; + vfe_acquire.vfe_in.is_offline = ife_ctx->is_offline; vfe_acquire.priv = ife_ctx; vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; @@ -1822,7 +1613,7 @@ static int cam_ife_mgr_acquire_cid_res( /* Acquire Left if not already acquired */ /* For dual IFE cases, start acquiring the lower idx first */ - if (ife_ctx->is_fe_enable || in_port->usage_type) + if (ife_ctx->is_fe_enabled || in_port->usage_type) rc = cam_ife_hw_mgr_acquire_csid_hw(ife_hw_mgr, &csid_acquire, true); else @@ -2159,7 +1950,7 @@ static int cam_ife_hw_mgr_acquire_res_root( ife_ctx->res_list_ife_in.res_id = in_port->res_type; ife_ctx->res_list_ife_in.is_dual_vfe = in_port->usage_type; } else if ((ife_ctx->res_list_ife_in.res_id != - in_port->res_type) && (!ife_ctx->is_fe_enable)) { + in_port->res_type) && (!ife_ctx->is_fe_enabled)) { CAM_ERR(CAM_ISP, "No Free resource for this context"); goto err; } else { @@ -2204,14 +1995,14 @@ static int cam_ife_mgr_check_and_update_fe_v0( CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, in_port->res_type); if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { - ife_ctx->is_fe_enable = true; + ife_ctx->is_fe_enabled = true; break; } in_port = (struct cam_isp_in_port_info *)((uint8_t *)in_port + in_port_length); } - CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + CAM_DBG(CAM_ISP, "is_fe_enabled %d", ife_ctx->is_fe_enabled); return 0; } @@ -2249,14 +2040,17 @@ static int cam_ife_mgr_check_and_update_fe_v2( CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, in_port->res_type); if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { - ife_ctx->is_fe_enable = true; + ife_ctx->is_fe_enabled = true; + if (in_port->offline_mode) + ife_ctx->is_offline = true; break; } in_port = (struct cam_isp_in_port_info_v2 *) ((uint8_t *)in_port + in_port_length); } - CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + CAM_DBG(CAM_ISP, "is_fe_enabled %d is_offline %d", + ife_ctx->is_fe_enabled, ife_ctx->is_offline); return 0; } @@ -2309,22 +2103,21 @@ static int cam_ife_hw_mgr_preprocess_port( ife_hw_mgr = ife_ctx->hw_mgr; - if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) ife_rd_num++; - } else { - for (i = 0; i < in_port->num_out_res; i++) { - out_port = &in_port->data[i]; - if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) - rdi_num++; - else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) - ppp_num++; - else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR) - lcr_num++; - else { - CAM_DBG(CAM_ISP, "out_res_type %d", - out_port->res_type); - ipp_num++; - } + + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + rdi_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) + ppp_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR) + lcr_num++; + else { + CAM_DBG(CAM_ISP, "out_res_type %d", + out_port->res_type); + ipp_num++; } } @@ -2340,6 +2133,293 @@ static int cam_ife_hw_mgr_preprocess_port( return 0; } +static int cam_ife_hw_mgr_acquire_offline_res_ife_bus_rd( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL, j; + int i = CAM_ISP_HW_SPLIT_LEFT; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_ife_hw_mgr_res *ife_bus_rd_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + + ife_hw_mgr = ife_ctx->hw_mgr; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &ife_bus_rd_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.priv = ife_ctx; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + + vfe_acquire.vfe_bus_rd.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_bus_rd.is_dual = (uint32_t)ife_ctx->is_dual; + vfe_acquire.vfe_bus_rd.is_offline = ife_ctx->is_offline; + vfe_acquire.vfe_bus_rd.res_id = CAM_ISP_HW_VFE_IN_RD; + vfe_acquire.vfe_bus_rd.unpacker_fmt = in_port->fe_unpacker_fmt; + + for (j = 0; j < CAM_IFE_HW_NUM_MAX; j++) { + if (!ife_hw_mgr->ife_devices[j]) + continue; + + hw_intf = ife_hw_mgr->ife_devices[j]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, sizeof(struct cam_vfe_acquire_args)); + + if (!rc) { + ife_bus_rd_res->hw_res[i] = + vfe_acquire.vfe_bus_rd.rsrc_node; + + CAM_DBG(CAM_ISP, "Acquired VFE:%d BUS RD for LEFT", j); + break; + } + } + + if (j == CAM_IFE_HW_NUM_MAX || !vfe_acquire.vfe_bus_rd.rsrc_node) { + CAM_ERR(CAM_ISP, "Failed to acquire BUS RD for LEFT", i); + goto put_res; + } + + ife_bus_rd_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_bus_rd_res->res_id = vfe_acquire.vfe_in.res_id; + ife_bus_rd_res->is_dual_vfe = (uint32_t)ife_ctx->is_dual; + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd, &ife_bus_rd_res); + + if (ife_ctx->is_dual) { + for (j = 0; j < CAM_IFE_HW_NUM_MAX; j++) { + if (!ife_hw_mgr->ife_devices[j]) + continue; + + if (j == ife_bus_rd_res->hw_res[i]->hw_intf->hw_idx) + continue; + + hw_intf = ife_hw_mgr->ife_devices[j]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + + if (!rc) { + ife_bus_rd_res->hw_res[++i] = + vfe_acquire.vfe_bus_rd.rsrc_node; + + CAM_DBG(CAM_ISP, + "Acquired VFE:%d BUS RD for RIGHT", j); + break; + } + } + + if (j == CAM_IFE_HW_NUM_MAX || + !vfe_acquire.vfe_bus_rd.rsrc_node) { + CAM_ERR(CAM_ISP, "Failed to acquire BUS RD for RIGHT"); + goto end; + } + } + + return 0; + +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &ife_bus_rd_res); + +end: + return rc; +} + +static int cam_ife_hw_mgr_acquire_offline_res_ife_camif( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + bool acquire_lcr, + uint32_t *acquired_hw_id, + uint32_t *acquired_hw_path) +{ + int rc = -1; + int i = CAM_ISP_HW_SPLIT_LEFT; + struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_ife_hw_mgr_res *ife_bus_rd_res; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + + ife_hw_mgr = ife_ctx->hw_mgr; + + ife_bus_rd_res = list_first_entry(&ife_ctx->res_list_ife_in_rd, + struct cam_ife_hw_mgr_res, list); + + if (!ife_bus_rd_res) { + CAM_ERR(CAM_ISP, "BUS RD resource has not been acquired"); + rc = -EINVAL; + goto end; + } + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &ife_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No free resource"); + goto end; + } + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.priv = ife_ctx; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + + vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.vfe_in.is_fe_enabled = ife_ctx->is_fe_enabled; + vfe_acquire.vfe_in.is_offline = ife_ctx->is_offline; + + if (!acquire_lcr) + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_CAMIF; + else + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_LCR; + + if (ife_ctx->is_dual) + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; + else + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + + hw_intf = ife_hw_mgr->ife_devices[ + ife_bus_rd_res->hw_res[i]->hw_intf->hw_idx]; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire CAMIF for LEFT"); + goto put_res; + } + + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + + *acquired_hw_id |= cam_convert_hw_idx_to_ife_hw_num( + hw_intf->hw_idx); + + acquired_hw_path[i] |= cam_convert_res_id_to_hw_path( + ife_src_res->hw_res[i]->res_id); + + CAM_DBG(CAM_ISP, "Acquired VFE:%d CAMIF for LEFT", + ife_src_res->hw_res[i]->hw_intf->hw_idx); + + ife_src_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_id = vfe_acquire.vfe_in.res_id; + ife_src_res->is_dual_vfe = (uint32_t)ife_ctx->is_dual; + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, &ife_src_res); + + if (ife_ctx->is_dual) { + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_SLAVE; + + hw_intf = ife_hw_mgr->ife_devices[ + ife_bus_rd_res->hw_res[++i]->hw_intf->hw_idx]; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire CAMIF for RIGHT"); + goto end; + } + + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + + *acquired_hw_id |= cam_convert_hw_idx_to_ife_hw_num( + hw_intf->hw_idx); + + acquired_hw_path[i] |= cam_convert_res_id_to_hw_path( + ife_src_res->hw_res[i]->res_id); + + CAM_DBG(CAM_ISP, "Acquired VFE:%d CAMIF for RIGHT", + ife_src_res->hw_res[i]->hw_intf->hw_idx); + } + + ife_src_res->parent = ife_bus_rd_res; + ife_bus_rd_res->child[ife_bus_rd_res->num_children++] = ife_src_res; + + return rc; + +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &ife_src_res); + +end: + return rc; +} + +static int cam_ife_mgr_acquire_hw_for_fe_ctx( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + uint32_t *num_pix_port, + uint32_t *acquired_hw_id, + uint32_t *acquired_hw_path) +{ + int rc = -1; + int ipp_count = 0; + int rdi_count = 0; + int ppp_count = 0; + int ife_rd_count = 0; + int lcr_count = 0; + + ife_ctx->is_dual = (bool)in_port->usage_type; + + cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count, + &rdi_count, &ppp_count, &ife_rd_count, &lcr_count); + + if ((!ipp_count && !lcr_count) || !ife_rd_count) { + CAM_ERR(CAM_ISP, + "Invalid %d BUS RD %d PIX %d LCR ports for FE ctx"); + return -EINVAL; + } + + if (rdi_count || ppp_count) { + CAM_ERR(CAM_ISP, + "%d RDI %d PPP ports invalid for FE ctx", + rdi_count, ppp_count); + return -EINVAL; + } + + rc = cam_ife_hw_mgr_acquire_offline_res_ife_bus_rd(ife_ctx, in_port); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE BUS RD resource Failed"); + goto err; + } + + if (ipp_count) + rc = cam_ife_hw_mgr_acquire_offline_res_ife_camif(ife_ctx, + in_port, false, acquired_hw_id, acquired_hw_path); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE IPP SRC resource Failed"); + goto err; + } + + if (lcr_count) + rc = cam_ife_hw_mgr_acquire_offline_res_ife_camif(ife_ctx, + in_port, true, acquired_hw_id, acquired_hw_path); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE LCR SRC resource Failed"); + goto err; + } + + rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed"); + goto err; + } + + *num_pix_port += ipp_count + lcr_count; + + return 0; + +err: + return rc; +} + + static int cam_ife_mgr_acquire_hw_for_ctx( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_generic_info *in_port, @@ -2367,10 +2447,14 @@ static int cam_ife_mgr_acquire_hw_for_ctx( cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count, &rdi_count, &ppp_count, &ife_rd_count, &lcr_count); - if (!ipp_count && !rdi_count && !ppp_count && !ife_rd_count - && !lcr_count) { + if (ife_rd_count) { + CAM_ERR(CAM_ISP, "Invalid BUS RD port for non-FE ctx"); + return -EINVAL; + } + + if (!ipp_count && !rdi_count && !ppp_count && !lcr_count) { CAM_ERR(CAM_ISP, - "No PIX or RDI or PPP or IFE RD or LCR resource"); + "No PIX or RDI or PPP or LCR resource"); return -EINVAL; } @@ -2415,15 +2499,7 @@ static int cam_ife_mgr_acquire_hw_for_ctx( } /* get ife src resource */ - if (ife_rd_count) { - rc = cam_ife_hw_mgr_acquire_res_ife_rd_src(ife_ctx, in_port); - rc = cam_ife_hw_mgr_acquire_res_bus_rd(ife_ctx, in_port); - - if (rc) { - CAM_ERR(CAM_ISP, "Acquire IFE RD SRC resource Failed"); - goto err; - } - } else if (ipp_count || ppp_count || rdi_count) { + if (ipp_count || ppp_count || rdi_count) { rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port, false, acquired_hw_id, acquired_hw_path); @@ -2627,10 +2703,12 @@ static int cam_ife_mgr_acquire_get_unified_structure_v2( if (port_info->num_valid_vc_dt == 0 || port_info->num_valid_vc_dt >= CAM_ISP_VC_DT_CFG) { - CAM_ERR(CAM_ISP, "Invalid i/p arg invalid vc-dt: %d", - in->num_valid_vc_dt); - rc = -EINVAL; - goto release_mem; + if (in->res_type != CAM_ISP_IFE_IN_RES_RD) { + CAM_ERR(CAM_ISP, "Invalid i/p arg invalid vc-dt: %d", + in->num_valid_vc_dt); + rc = -EINVAL; + goto release_mem; + } } for (i = 0; i < port_info->num_valid_vc_dt; i++) { @@ -2638,26 +2716,27 @@ static int cam_ife_mgr_acquire_get_unified_structure_v2( port_info->dt[i] = in->dt[i]; } - port_info->format = in->format; - port_info->test_pattern = in->test_pattern; - port_info->usage_type = in->usage_type; - port_info->left_start = in->left_start; - port_info->left_stop = in->left_stop; - port_info->left_width = in->left_width; - port_info->right_start = in->right_start; - port_info->right_stop = in->right_stop; - port_info->right_width = in->right_width; - port_info->line_start = in->line_start; - port_info->line_stop = in->line_stop; - port_info->height = in->height; - port_info->pixel_clk = in->pixel_clk; - port_info->batch_size = in->batch_size; - port_info->dsp_mode = in->dsp_mode; - port_info->hbi_cnt = in->hbi_cnt; - port_info->cust_node = in->cust_node; - port_info->horizontal_bin = in->horizontal_bin; - port_info->qcfa_bin = in->qcfa_bin; - port_info->num_out_res = in->num_out_res; + port_info->format = in->format; + port_info->test_pattern = in->test_pattern; + port_info->usage_type = in->usage_type; + port_info->left_start = in->left_start; + port_info->left_stop = in->left_stop; + port_info->left_width = in->left_width; + port_info->right_start = in->right_start; + port_info->right_stop = in->right_stop; + port_info->right_width = in->right_width; + port_info->line_start = in->line_start; + port_info->line_stop = in->line_stop; + port_info->height = in->height; + port_info->pixel_clk = in->pixel_clk; + port_info->batch_size = in->batch_size; + port_info->dsp_mode = in->dsp_mode; + port_info->fe_unpacker_fmt = in->format; + port_info->hbi_cnt = in->hbi_cnt; + port_info->cust_node = in->cust_node; + port_info->horizontal_bin = in->horizontal_bin; + port_info->qcfa_bin = in->qcfa_bin; + port_info->num_out_res = in->num_out_res; port_info->data = kcalloc(in->num_out_res, sizeof(struct cam_isp_out_port_generic_info), @@ -2805,10 +2884,17 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) ife_ctx->use_frame_header_ts = true; } - rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, - &num_pix_port_per_in, &num_rdi_port_per_in, - &acquire_args->acquired_hw_id[i], - acquire_args->acquired_hw_path[i]); + if (ife_ctx->is_fe_enabled) + rc = cam_ife_mgr_acquire_hw_for_fe_ctx( + ife_ctx, in_port, + &num_pix_port_per_in, + &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + else + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, + &num_pix_port_per_in, &num_rdi_port_per_in, + &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); total_pix_port += num_pix_port_per_in; total_rdi_port += num_rdi_port_per_in; @@ -2897,6 +2983,7 @@ void cam_ife_mgr_acquire_get_unified_dev_str(struct cam_isp_in_port_info *in, gen_port_info->batch_size = in->batch_size; gen_port_info->dsp_mode = in->dsp_mode; gen_port_info->hbi_cnt = in->hbi_cnt; + gen_port_info->fe_unpacker_fmt = in->format; gen_port_info->cust_node = 0; gen_port_info->num_out_res = in->num_out_res; @@ -3767,11 +3854,6 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); - /* IFE bus rd resources */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { - cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); - } - CAM_DBG(CAM_ISP, "Going to stop IFE Mux"); /* IFE mux in resources */ @@ -3779,6 +3861,11 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); } + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + cam_tasklet_stop(ctx->common.tasklet_info); cam_ife_mgr_pause_hw(ctx); @@ -4072,18 +4159,6 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } } - CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d", - ctx->ctx_index); - /* Start the IFE mux in devices */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { - rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); - if (rc) { - CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", - hw_mgr_res->res_id); - goto err; - } - } - if (primary_rdi_out_res < CAM_ISP_IFE_OUT_RES_MAX) primary_rdi_src_res = cam_convert_rdi_out_res_id_to_src(primary_rdi_out_res); @@ -4096,15 +4171,25 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) hw_mgr_res->hw_res[0]->rdi_only_ctx = ctx->is_rdi_only_context; } - rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); if (rc) { - CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)", + CAM_ERR(CAM_ISP, "Can not start IFE Mux (%d)", hw_mgr_res->res_id); goto err; } } + CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d", ctx->ctx_index); + /* Start IFE Bus RD devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", ctx->ctx_index); /* Start the IFE CSID HW devices */ @@ -5753,6 +5838,17 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, } } + /* add go_cmd for offline context */ + if (prepare->num_out_map_entries && prepare->num_in_map_entries && + ctx->is_offline) { + rc = cam_isp_add_go_cmd(prepare, &ctx->res_list_ife_in_rd, + ctx->base[i].idx, &kmd_buf); + if (rc) + CAM_ERR(CAM_ISP, + "Add GO_CMD faled i: %d, idx: %d, rc: %d", + i, ctx->base[i].idx, rc); + } + /* * reg update will be done later for the initial configure. * need to plus one to the op_code and only take the lower @@ -5979,7 +6075,10 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) isp_hw_cmd_args->u.sof_irq_enable); break; case CAM_ISP_HW_MGR_CMD_CTX_TYPE: - if (ctx->is_fe_enable) + if (ctx->is_fe_enabled && ctx->is_offline) + isp_hw_cmd_args->u.ctx_type = + CAM_ISP_CTX_OFFLINE; + else if (ctx->is_fe_enabled && !ctx->is_offline) isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2; else if (ctx->is_rdi_only_context) isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI; @@ -6213,6 +6312,17 @@ static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args) return rc; } +static inline void cam_ife_hw_mgr_get_offline_sof_timestamp( + uint64_t *timestamp, + uint64_t *boot_time) +{ + struct timespec64 ts; + + get_monotonic_boottime64(&ts); + *timestamp = (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec); + *boot_time = *timestamp; +} + static int cam_ife_mgr_cmd_get_sof_timestamp( struct cam_ife_hw_mgr_ctx *ife_ctx, uint64_t *time_stamp, @@ -6595,6 +6705,7 @@ static int cam_ife_hw_mgr_handle_hw_rup( case CAM_ISP_HW_VFE_IN_PDLIB: case CAM_ISP_HW_VFE_IN_LCR: + case CAM_ISP_HW_VFE_IN_RD: break; default: CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", @@ -6724,6 +6835,8 @@ static int cam_ife_hw_mgr_handle_hw_sof( struct cam_isp_hw_sof_event_data sof_done_event_data; int rc = 0; + memset(&sof_done_event_data, 0, sizeof(sof_done_event_data)); + ife_hw_irq_sof_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF]; @@ -6734,10 +6847,15 @@ static int cam_ife_hw_mgr_handle_hw_sof( rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, CAM_ISP_HW_EVENT_SOF); if (!rc) { - cam_ife_mgr_cmd_get_sof_timestamp( - ife_hw_mgr_ctx, - &sof_done_event_data.timestamp, - &sof_done_event_data.boot_time); + if (ife_hw_mgr_ctx->is_offline) + cam_ife_hw_mgr_get_offline_sof_timestamp( + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); + else + cam_ife_mgr_cmd_get_sof_timestamp( + ife_hw_mgr_ctx, + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); /* if frame header is enabled reset qtimer ts */ if (ife_hw_mgr_ctx->use_frame_header_ts) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 438d3549eaef..9c6dc72190a8 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -137,11 +137,12 @@ struct cam_ife_hw_mgr_debug { * @last_dump_flush_req_id Last req id for which reg dump on flush was called * @last_dump_err_req_id Last req id for which reg dump on error was called * @init_done indicate whether init hw is done - * @is_fe_enable indicate whether fetch engine\read path is enabled + * @is_fe_enabled Indicate whether fetch engine\read path is enabled * @is_dual indicate whether context is in dual VFE mode * @custom_enabled update the flag if context is connected to custom HW * @use_frame_header_ts obtain qtimer ts using frame header * @ts captured timestamp when the ctx is acquired + * @is_offline Indicate whether context is for offline IFE */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -186,11 +187,12 @@ struct cam_ife_hw_mgr_ctx { uint64_t last_dump_flush_req_id; uint64_t last_dump_err_req_id; bool init_done; - bool is_fe_enable; + bool is_fe_enabled; bool is_dual; bool custom_enabled; bool use_frame_header_ts; struct timespec64 ts; + bool is_offline; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 679ec02f9fbf..6d633f3e23bc 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -926,7 +926,7 @@ int cam_isp_add_reg_update( return rc; CAM_DBG(CAM_ISP, "Reg update added for res %d hw_id %d", - res->res_id, res->hw_intf->hw_idx); + res->res_type, res->hw_intf->hw_idx); reg_update_size += get_regup.cmd.used_bytes; } } @@ -960,3 +960,100 @@ int cam_isp_add_reg_update( return rc; } + +int cam_isp_add_go_cmd( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_rd, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int rc = -EINVAL; + struct cam_isp_resource_node *res; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_update_entry *hw_entry; + struct cam_isp_hw_get_cmd_update get_regup; + uint32_t kmd_buf_remain_size, num_ent, i, reg_update_size; + + hw_entry = prepare->hw_update_entries; + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries current: %d max: %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + reg_update_size = 0; + list_for_each_entry(hw_mgr_res, res_list_isp_rd, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + if (res->hw_intf->hw_idx != base_idx) + continue; + + if (kmd_buf_info->size > (kmd_buf_info->used_bytes + + reg_update_size)) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + reg_update_size); + } else { + CAM_ERR(CAM_ISP, "no free mem %d %d %d", + base_idx, kmd_buf_info->size, + kmd_buf_info->used_bytes + + reg_update_size); + rc = -EINVAL; + return rc; + } + + get_regup.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + reg_update_size/4; + get_regup.cmd.size = kmd_buf_remain_size; + get_regup.cmd_type = CAM_ISP_HW_CMD_FE_TRIGGER_CMD; + get_regup.res = res; + + rc = res->process_cmd(res->res_priv, + CAM_ISP_HW_CMD_FE_TRIGGER_CMD, &get_regup, + sizeof(struct cam_isp_hw_get_cmd_update)); + if (rc) + return rc; + + CAM_DBG(CAM_ISP, "GO_CMD added for RD res %d hw_id %d", + res->res_type, res->hw_intf->hw_idx); + reg_update_size += get_regup.cmd.used_bytes; + } + } + + if (reg_update_size) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = reg_update_size; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + + prepare->hw_update_entries[num_ent].flags = + CAM_ISP_IOCFG_BL; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); + num_ent++; + + kmd_buf_info->used_bytes += reg_update_size; + kmd_buf_info->offset += reg_update_size; + prepare->num_hw_update_entries = num_ent; + rc = 0; + } + + return rc; +} + diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h index 0c0f1e4ea6ce..5813208a6421 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -176,4 +176,23 @@ int cam_isp_add_reg_update( uint32_t base_idx, struct cam_kmd_buf_info *kmd_buf_info); +/* + * cam_isp_add_go_cmd() + * + * @brief Add go_cmd in the hw entries list for each rd source + * + * @prepare: Contain the packet and HW update variables + * @res_list_isp_rd: Resource list for BUS RD ports + * @base_idx: Base or dev index of the IFE/VFE HW instance + * @kmd_buf_info: Kmd buffer to store the change base command + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_isp_add_go_cmd( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_rd, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info); + + #endif /*_CAM_ISP_HW_PARSER_H */ diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 9502fe44b436..c67b50fedfad 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -237,6 +237,7 @@ enum cam_isp_ctx_type { CAM_ISP_CTX_FS2 = 1, CAM_ISP_CTX_RDI, CAM_ISP_CTX_PIX, + CAM_ISP_CTX_OFFLINE, CAM_ISP_CTX_MAX, }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 0474a2840460..3092b81352c3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -97,6 +97,7 @@ struct cam_isp_in_port_generic_info { uint32_t batch_size; uint32_t dsp_mode; uint32_t hbi_cnt; + uint32_t fe_unpacker_fmt; uint32_t cust_node; uint32_t num_out_res; uint32_t horizontal_bin; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 13a1612dce7c..fc6951b2fa1e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -74,8 +74,8 @@ enum cam_isp_resource_type { CAM_ISP_RESOURCE_CID, CAM_ISP_RESOURCE_PIX_PATH, CAM_ISP_RESOURCE_VFE_IN, - CAM_ISP_RESOURCE_VFE_OUT, CAM_ISP_RESOURCE_VFE_BUS_RD, + CAM_ISP_RESOURCE_VFE_OUT, CAM_ISP_RESOURCE_MAX, }; @@ -105,6 +105,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, CAM_ISP_HW_CMD_DUMP_HW, + CAM_ISP_HW_CMD_FE_TRIGGER_CMD, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index 21efc83b551e..531e695583a0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -102,6 +102,27 @@ struct cam_vfe_hw_get_hw_cap { uint32_t max_rdi_num; }; +/* + * struct cam_vfe_hw_vfe_bus_rd_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @res_id: Unique Identity of port to associate with this + * resource. + * @is_dual: Flag to indicate dual VFE usecase + * @cdm_ops: CDM operations + * @unpacket_fmt: Unpacker format for read engine + * @is_offline: Flag to indicate offline usecase + */ +struct cam_vfe_hw_vfe_bus_rd_acquire_args { + struct cam_isp_resource_node *rsrc_node; + uint32_t res_id; + uint32_t is_dual; + struct cam_cdm_utils_ops *cdm_ops; + uint32_t unpacker_fmt; + bool is_offline; +}; + /* * struct cam_vfe_hw_vfe_out_acquire_args: * @@ -138,11 +159,13 @@ struct cam_vfe_hw_vfe_out_acquire_args { * @res_id: Resource ID of resource to acquire if specific, * else CAM_ISP_HW_VFE_IN_MAX * @dual_hw_idx: Slave core for this master core if dual vfe case + * @is_dual: flag to indicate if dual vfe case * @cdm_ops: CDM operations * @sync_mode: In case of Dual VFE, this is Master or Slave. * (Default is Master in case of Single VFE) * @in_port: Input port details to acquire - * @is_dual: flag to indicate if dual vfe case + * @is_fe_enabled: Flag to indicate if FE is enabled + * @is_offline: Flag to indicate Offline IFE */ struct cam_vfe_hw_vfe_in_acquire_args { struct cam_isp_resource_node *rsrc_node; @@ -152,6 +175,8 @@ struct cam_vfe_hw_vfe_in_acquire_args { void *cdm_ops; enum cam_isp_hw_sync_mode sync_mode; struct cam_isp_in_port_generic_info *in_port; + bool is_fe_enabled; + bool is_offline; }; /* @@ -173,9 +198,9 @@ struct cam_vfe_acquire_args { void *priv; cam_hw_mgr_event_cb_func event_cb; union { - struct cam_vfe_hw_vfe_out_acquire_args vfe_out; - struct cam_vfe_hw_vfe_out_acquire_args vfe_bus_rd; - struct cam_vfe_hw_vfe_in_acquire_args vfe_in; + struct cam_vfe_hw_vfe_out_acquire_args vfe_out; + struct cam_vfe_hw_vfe_bus_rd_acquire_args vfe_bus_rd; + struct cam_vfe_hw_vfe_in_acquire_args vfe_in; }; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 1a80dc7f8f2e..946ac2267d95 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -407,6 +407,7 @@ static struct cam_vfe_bus_rd_ver1_hw_info vfe175_130_bus_rd_hw_info = { .max_height = -1, }, }, + .top_irq_shift = 23, }; static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index 0cd59de02f46..18a0071bf0b0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -1360,6 +1360,7 @@ static struct cam_vfe_bus_rd_ver1_hw_info vfe480_bus_rd_hw_info = { .max_height = -1, }, }, + .top_irq_shift = 8, }; struct cam_vfe_hw_info cam_vfe480_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c index 314ebff70fc0..ca1ef5977a53 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -37,24 +37,29 @@ static const char drv_name[] = "vfe_bus_rd"; buf_array[(index)++] = val; \ } while (0) +#define BUS_RD_VER1_DEFAULT_LATENCY_BUF_ALLOC 512 + enum cam_vfe_bus_rd_ver1_unpacker_format { - BUS_RD_VER1_PACKER_FMT_PLAIN_128 = 0x0, - BUS_RD_VER1_PACKER_FMT_PLAIN_8 = 0x1, - BUS_RD_VER1_PACKER_FMT_PLAIN_16_10BPP = 0x2, - BUS_RD_VER1_PACKER_FMT_PLAIN_16_12BPP = 0x3, - BUS_RD_VER1_PACKER_FMT_PLAIN_16_14BPP = 0x4, - BUS_RD_VER1_PACKER_FMT_PLAIN_16_16BPP = 0x5, - BUS_RD_VER1_PACKER_FMT_ARGB_10 = 0x6, - BUS_RD_VER1_PACKER_FMT_ARGB_12 = 0x7, - BUS_RD_VER1_PACKER_FMT_ARGB_14 = 0x8, - BUS_RD_VER1_PACKER_FMT_PLAIN_32_20BPP = 0x9, - BUS_RD_VER1_PACKER_FMT_PLAIN_64 = 0xA, - BUS_RD_VER1_PACKER_FMT_TP_10 = 0xB, - BUS_RD_VER1_PACKER_FMT_PLAIN_32_32BPP = 0xC, - BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN = 0xD, - BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0xE, - BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF, - BUS_RD_VER1_PACKER_FMT_MAX = 0xF, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_128 = 0x0, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_8 = 0x1, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_10BPP = 0x2, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_12BPP = 0x3, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_14BPP = 0x4, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_32_20BPP = 0x5, + BUS_RD_VER1_UNPACKER_FMT_ARGB_10 = 0x6, + BUS_RD_VER1_UNPACKER_FMT_ARGB_12 = 0x7, + BUS_RD_VER1_UNPACKER_FMT_ARGB_14 = 0x8, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_32 = 0x9, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_64 = 0xA, + BUS_RD_VER1_UNPACKER_FMT_TP_10 = 0xB, + BUS_RD_VER1_UNPACKER_FMT_MIPI8 = 0xC, + BUS_RD_VER1_UNPACKER_FMT_MIPI10 = 0xD, + BUS_RD_VER1_UNPACKER_FMT_MIPI12 = 0xE, + BUS_RD_VER1_UNPACKER_FMT_MIPI14 = 0xF, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_16BPP = 0x10, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_128_ODD_EVEN = 0x11, + BUS_RD_VER1_UNPACKER_FMT_PLAIN_8_ODD_EVEN = 0x12, + BUS_RD_VER1_UNPACKER_FMT_MAX = 0x13, }; struct cam_vfe_bus_rd_ver1_common_data { @@ -74,6 +79,7 @@ struct cam_vfe_bus_rd_ver1_common_data { uint32_t num_sec_out; uint32_t fs_sync_enable; uint32_t go_cmd_sel; + cam_hw_mgr_event_cb_func event_cb; }; struct cam_vfe_bus_rd_ver1_rm_resource_data { @@ -83,7 +89,6 @@ struct cam_vfe_bus_rd_ver1_rm_resource_data { void *ctx; bool init_cfg_done; - bool hfr_cfg_done; uint32_t offset; @@ -125,12 +130,16 @@ struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data { uint32_t max_height; struct cam_cdm_utils_ops *cdm_util_ops; uint32_t secure_mode; + int irq_handle; + void *priv; + uint32_t status; + bool is_offline; }; struct cam_vfe_bus_rd_ver1_priv { struct cam_vfe_bus_rd_ver1_common_data common_data; - uint32_t num_client; - uint32_t num_bus_rd_resc; + uint32_t num_client; + uint32_t num_bus_rd_resc; struct cam_isp_resource_node bus_client[ CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; @@ -138,32 +147,105 @@ struct cam_vfe_bus_rd_ver1_priv { CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; int irq_handle; - int error_irq_handle; + void *tasklet_info; + uint32_t top_irq_shift; }; -static int cam_vfe_bus_process_cmd( +static int cam_vfe_bus_rd_process_cmd( struct cam_isp_resource_node *priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size); -static enum cam_vfe_bus_rd_ver1_unpacker_format - cam_vfe_bus_get_unpacker_fmt(uint32_t unpack_fmt) +static void cam_vfe_bus_rd_pxls_to_bytes(uint32_t pxls, uint32_t fmt, + uint32_t *bytes) { - switch (unpack_fmt) { - case CAM_FORMAT_MIPI_RAW_10: - return BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN; + switch (fmt) { + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_128: + *bytes = pxls * 16; + break; + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_8: + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_8_ODD_EVEN: + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_10BPP: + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_12BPP: + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_14BPP: + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_16BPP: + case BUS_RD_VER1_UNPACKER_FMT_ARGB_10: + case BUS_RD_VER1_UNPACKER_FMT_ARGB_12: + case BUS_RD_VER1_UNPACKER_FMT_ARGB_14: + *bytes = pxls * 2; + break; + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_32_20BPP: + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_32: + *bytes = pxls * 4; + break; + case BUS_RD_VER1_UNPACKER_FMT_PLAIN_64: + *bytes = pxls * 8; + break; + case BUS_RD_VER1_UNPACKER_FMT_TP_10: + *bytes = ALIGNUP(pxls, 3) * 4 / 3; + break; + case BUS_RD_VER1_UNPACKER_FMT_MIPI8: + *bytes = pxls; + break; + case BUS_RD_VER1_UNPACKER_FMT_MIPI10: + *bytes = ALIGNUP(pxls * 5, 4) / 4; + break; + case BUS_RD_VER1_UNPACKER_FMT_MIPI12: + *bytes = ALIGNUP(pxls * 3, 2) / 2; + break; + case BUS_RD_VER1_UNPACKER_FMT_MIPI14: + *bytes = ALIGNUP(pxls * 7, 4) / 4; + break; default: - return BUS_RD_VER1_PACKER_FMT_MAX; + CAM_ERR(CAM_ISP, "Invalid unpacker_fmt:%d", fmt); + break; } } -static bool cam_vfe_bus_can_be_secure(uint32_t out_type) +static enum cam_vfe_bus_rd_ver1_unpacker_format + cam_vfe_bus_get_unpacker_fmt(uint32_t unpack_fmt) { - switch (out_type) { - case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: - return false; - + switch (unpack_fmt) { + case CAM_FORMAT_PLAIN128: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_128; + case CAM_FORMAT_PLAIN8: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_8; + case CAM_FORMAT_PLAIN16_10: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_10BPP; + case CAM_FORMAT_PLAIN16_12: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_12BPP; + case CAM_FORMAT_PLAIN16_14: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_14BPP; + case CAM_FORMAT_PLAIN32_20: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_32_20BPP; + case CAM_FORMAT_ARGB_10: + return BUS_RD_VER1_UNPACKER_FMT_ARGB_10; + case CAM_FORMAT_ARGB_12: + return BUS_RD_VER1_UNPACKER_FMT_ARGB_12; + case CAM_FORMAT_ARGB_14: + return BUS_RD_VER1_UNPACKER_FMT_ARGB_14; + case CAM_FORMAT_PLAIN32: + case CAM_FORMAT_ARGB: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_32; + case CAM_FORMAT_PLAIN64: + case CAM_FORMAT_ARGB_16: + case CAM_FORMAT_PD10: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_64; + case CAM_FORMAT_TP10: + return BUS_RD_VER1_UNPACKER_FMT_TP_10; + case CAM_FORMAT_MIPI_RAW_8: + return BUS_RD_VER1_UNPACKER_FMT_MIPI8; + case CAM_FORMAT_MIPI_RAW_10: + return BUS_RD_VER1_UNPACKER_FMT_MIPI10; + case CAM_FORMAT_MIPI_RAW_12: + return BUS_RD_VER1_UNPACKER_FMT_MIPI12; + case CAM_FORMAT_MIPI_RAW_14: + return BUS_RD_VER1_UNPACKER_FMT_MIPI14; + case CAM_FORMAT_PLAIN16_16: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_16_16BPP; + case CAM_FORMAT_PLAIN8_SWAP: + return BUS_RD_VER1_UNPACKER_FMT_PLAIN_8_ODD_EVEN; default: - return false; + return BUS_RD_VER1_UNPACKER_FMT_MAX; } } @@ -185,12 +267,58 @@ static int cam_vfe_bus_get_num_rm( case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: return 1; default: - break; + CAM_ERR(CAM_ISP, "Unsupported resource_type %u", res_type); + return -EINVAL; + } +} + +static int cam_vfe_bus_rd_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_isp_resource_node *bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + + bus_rd = th_payload->handler_priv; + if (!bus_rd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + rsrc_data = bus_rd->res_priv; + rsrc_data->status = th_payload->evt_status_arr[0]; + + CAM_DBG(CAM_ISP, "VFE:%d Bus RD IRQ status_0: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0]); + + return 0; +} + +static int cam_vfe_bus_rd_handle_irq_bottom_half( + void *handler_priv, void *evt_payload_priv) +{ + struct cam_isp_resource_node *bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + + bus_rd = (struct cam_isp_resource_node *)handler_priv; + if (!bus_rd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + rsrc_data = bus_rd->res_priv; + + if (rsrc_data->status & 0x2) + CAM_DBG(CAM_ISP, "Received VFE:%d BUS RD RUP", + rsrc_data->common_data->core_index); + else if (rsrc_data->status & 0x4) + CAM_DBG(CAM_ISP, "Received VFE:%d BUS RD BUF DONE", + rsrc_data->common_data->core_index); + else if (rsrc_data->status & 0x10000) { + CAM_ERR(CAM_ISP, "Received VFE:%d BUS RD CCIF Violation", + rsrc_data->common_data->core_index); + return CAM_VFE_IRQ_STATUS_VIOLATION; } - CAM_ERR(CAM_ISP, "Unsupported resource_type %u", - res_type); - return -EINVAL; + return CAM_VFE_IRQ_STATUS_SUCCESS; } static int cam_vfe_bus_get_rm_idx( @@ -217,19 +345,18 @@ static int cam_vfe_bus_get_rm_idx( } static int cam_vfe_bus_acquire_rm( - struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, - struct cam_isp_out_port_generic_info *out_port_info, - void *tasklet, - void *ctx, - enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, - enum cam_vfe_bus_plane_type plane, - uint32_t subscribe_irq, - struct cam_isp_resource_node **rm_res, - uint32_t *client_done_mask, - uint32_t is_dual) + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + void *tasklet, + void *ctx, + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane, + struct cam_isp_resource_node **rm_res, + uint32_t *client_done_mask, + uint32_t is_dual, + uint32_t unpacker_fmt) { - uint32_t rm_idx = 0; - struct cam_isp_resource_node *rm_res_local = NULL; + uint32_t rm_idx = 0; + struct cam_isp_resource_node *rm_res_local = NULL; struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = NULL; *rm_res = NULL; @@ -238,14 +365,15 @@ static int cam_vfe_bus_acquire_rm( /* No need to allocate for BUS VER2. VFE OUT to RM is fixed. */ rm_idx = cam_vfe_bus_get_rm_idx(vfe_bus_rd_res_id, plane); if (rm_idx < 0 || rm_idx >= ver1_bus_rd_priv->num_client) { - CAM_ERR(CAM_ISP, "Unsupported VFE out %d plane %d", + CAM_ERR(CAM_ISP, "Unsupported VFE RM:%d plane:%d", vfe_bus_rd_res_id, plane); return -EINVAL; } rm_res_local = &ver1_bus_rd_priv->bus_client[rm_idx]; if (rm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { - CAM_ERR(CAM_ISP, "RM res not available state:%d", + CAM_ERR(CAM_ISP, "VFE:%d RM:%d res not available state:%d", + ver1_bus_rd_priv->common_data.core_index, rm_idx, rm_res_local->res_state); return -EALREADY; } @@ -255,18 +383,22 @@ static int cam_vfe_bus_acquire_rm( rsrc_data = rm_res_local->res_priv; rsrc_data->ctx = ctx; rsrc_data->is_dual = is_dual; + rsrc_data->unpacker_cfg = cam_vfe_bus_get_unpacker_fmt(unpacker_fmt); + rsrc_data->latency_buf_allocation = + BUS_RD_VER1_DEFAULT_LATENCY_BUF_ALLOC; /* Set RM offset value to default */ rsrc_data->offset = 0; - *client_done_mask = (1 << rm_idx); + *client_done_mask = (1 << (rm_idx + 2)); *rm_res = rm_res_local; - CAM_DBG(CAM_ISP, "RM %d: Acquired"); + CAM_DBG(CAM_ISP, "VFE:%d RM:%d Acquired", + rsrc_data->common_data->core_index, rsrc_data->index); return 0; } -static int cam_vfe_bus_release_rm(void *bus_priv, - struct cam_isp_resource_node *rm_res) +static int cam_vfe_bus_release_rm(void *bus_priv, + struct cam_isp_resource_node *rm_res) { struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = rm_res->res_priv; @@ -279,68 +411,49 @@ static int cam_vfe_bus_release_rm(void *bus_priv, rsrc_data->unpacker_cfg = 0; rsrc_data->burst_len = 0; rsrc_data->init_cfg_done = false; - rsrc_data->hfr_cfg_done = false; rsrc_data->en_cfg = 0; rsrc_data->is_dual = 0; rm_res->tasklet_info = NULL; rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + CAM_DBG(CAM_ISP, "VFE:%d RM:%d released", + rsrc_data->common_data->core_index, rsrc_data->index); return 0; } static int cam_vfe_bus_start_rm(struct cam_isp_resource_node *rm_res) { - int rc = 0; - struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = - rm_res->res_priv; - struct cam_vfe_bus_rd_ver1_common_data *common_data = - rm_data->common_data; - uint32_t buf_size; - uint32_t val; - uint32_t offset; - - CAM_DBG(CAM_ISP, "w: 0x%x", rm_data->width); - CAM_DBG(CAM_ISP, "h: 0x%x", rm_data->height); - CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); - CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); - CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", - rm_data->latency_buf_allocation); - CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); - CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); - CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", rm_data->fs_sync_enable); - CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); - CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", rm_data->fs_line_sync_en); - CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); - CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); - - /* Write All the values*/ - offset = rm_data->hw_regs->buf_size; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + uint32_t buf_size; + + rm_data = rm_res->res_priv; + common_data = rm_data->common_data; + buf_size = ((rm_data->width)&(0x0000FFFF)) | ((rm_data->height<<16)&(0xFFFF0000)); - cam_io_w_mb(buf_size, common_data->mem_base + offset); - CAM_DBG(CAM_ISP, "buf_size: 0x%x", buf_size); - - val = rm_data->width; - offset = rm_data->hw_regs->stride; - CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); - cam_io_w_mb(val, common_data->mem_base + offset); - - CAM_DBG(CAM_ISP, "rm_data->unpacker_cfg:0x%x", rm_data->unpacker_cfg); - val = cam_vfe_bus_get_unpacker_fmt(rm_data->unpacker_cfg); - CAM_DBG(CAM_ISP, " value:0x%x", val); - offset = rm_data->hw_regs->unpacker_cfg; - CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); - cam_io_w_mb(val, common_data->mem_base + offset); - - val = rm_data->latency_buf_allocation; - offset = rm_data->hw_regs->latency_buf_allocation; - CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); - cam_io_w_mb(val, common_data->mem_base + offset); - - cam_io_w_mb(0x1, common_data->mem_base + - rm_data->hw_regs->cfg); - return rc; + cam_io_w_mb(buf_size, common_data->mem_base + + rm_data->hw_regs->buf_size); + cam_io_w_mb(rm_data->width, common_data->mem_base + + rm_data->hw_regs->stride); + cam_io_w_mb(rm_data->unpacker_cfg, common_data->mem_base + + rm_data->hw_regs->unpacker_cfg); + cam_io_w_mb(rm_data->latency_buf_allocation, common_data->mem_base + + rm_data->hw_regs->latency_buf_allocation); + cam_io_w_mb(0x1, common_data->mem_base + rm_data->hw_regs->cfg); + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + CAM_DBG(CAM_ISP, + "Start VFE:%d RM:%d offset:0x%X en_cfg:0x%X width:%d height:%d", + rm_data->common_data->core_index, rm_data->index, + (uint32_t) rm_data->hw_regs->cfg, rm_data->en_cfg, + rm_data->width, rm_data->height); + CAM_DBG(CAM_ISP, "RM:%d pk_fmt:%d stride:%d", rm_data->index, + rm_data->unpacker_cfg, rm_data->stride); + + return 0; } static int cam_vfe_bus_stop_rm(struct cam_isp_resource_node *rm_res) @@ -352,12 +465,13 @@ static int cam_vfe_bus_stop_rm(struct cam_isp_resource_node *rm_res) rsrc_data->common_data; /* Disable RM */ - cam_io_w_mb(0x0, - common_data->mem_base + rsrc_data->hw_regs->cfg); + cam_io_w_mb(0x0, common_data->mem_base + rsrc_data->hw_regs->cfg); rm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; rsrc_data->init_cfg_done = false; - rsrc_data->hfr_cfg_done = false; + + CAM_DBG(CAM_ISP, "VFE:%d RM:%d stopped", + rsrc_data->common_data->core_index, rsrc_data->index); return rc; } @@ -372,7 +486,8 @@ static int cam_vfe_bus_init_rm_resource(uint32_t index, rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_rm_resource_data), GFP_KERNEL); if (!rsrc_data) { - CAM_DBG(CAM_ISP, "Failed to alloc for RM res priv"); + CAM_DBG(CAM_ISP, "Failed to alloc VFE:%d RM res priv", + ver1_bus_rd_priv->common_data.core_index); return -ENOMEM; } rm_res->res_priv = rsrc_data; @@ -388,7 +503,6 @@ static int cam_vfe_bus_init_rm_resource(uint32_t index, rm_res->stop = cam_vfe_bus_stop_rm; rm_res->hw_intf = ver1_bus_rd_priv->common_data.hw_intf; - return 0; } @@ -428,15 +542,13 @@ static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, int i; enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type bus_rd_res_id; int num_rm; - uint32_t subscribe_irq; uint32_t client_done_mask; struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv = bus_priv; struct cam_vfe_acquire_args *acq_args = acquire_args; - struct cam_vfe_hw_vfe_out_acquire_args *bus_rd_acquire_args; + struct cam_vfe_hw_vfe_bus_rd_acquire_args *bus_rd_acquire_args; struct cam_isp_resource_node *rsrc_node = NULL; struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; - uint32_t secure_caps = 0, mode; if (!bus_priv || !acquire_args) { CAM_ERR(CAM_ISP, "Invalid Param"); @@ -445,9 +557,6 @@ static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, bus_rd_acquire_args = &acq_args->vfe_bus_rd; - CAM_DBG(CAM_ISP, "Acquiring resource type 0x%x", - acq_args->rsrc_type); - bus_rd_res_id = cam_vfe_bus_get_bus_rd_res_id( acq_args->rsrc_type); if (bus_rd_res_id == CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX) @@ -459,61 +568,40 @@ static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, rsrc_node = &ver1_bus_rd_priv->vfe_bus_rd[bus_rd_res_id]; if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { - CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", - bus_rd_res_id, rsrc_node->res_state); + CAM_ERR(CAM_ISP, "VFE:%d RM:0x%x not available state:%d", + ver1_bus_rd_priv->common_data.core_index, + acq_args->rsrc_type, rsrc_node->res_state); return -EBUSY; } + rsrc_node->res_id = acq_args->rsrc_type; rsrc_data = rsrc_node->res_priv; - secure_caps = cam_vfe_bus_can_be_secure( - rsrc_data->bus_rd_type); - - mode = bus_rd_acquire_args->out_port_info->secure_mode; - mutex_lock(&rsrc_data->common_data->bus_mutex); - if (secure_caps) { - if (!rsrc_data->common_data->num_sec_out) { - rsrc_data->secure_mode = mode; - rsrc_data->common_data->secure_mode = mode; - } else { - if (mode == rsrc_data->common_data->secure_mode) { - rsrc_data->secure_mode = - rsrc_data->common_data->secure_mode; - } else { - rc = -EINVAL; - CAM_ERR_RATE_LIMIT(CAM_ISP, - "Mismatch: Acquire mode[%d], drvr mode[%d]", - rsrc_data->common_data->secure_mode, - mode); - mutex_unlock( - &rsrc_data->common_data->bus_mutex); - return -EINVAL; - } - } - rsrc_data->common_data->num_sec_out++; - } - mutex_unlock(&rsrc_data->common_data->bus_mutex); + + CAM_DBG(CAM_ISP, "VFE:%d acquire RD type:0x%x", + rsrc_data->common_data->core_index, acq_args->rsrc_type); rsrc_data->num_rm = num_rm; rsrc_node->tasklet_info = acq_args->tasklet; + ver1_bus_rd_priv->tasklet_info = acq_args->tasklet; rsrc_node->cdm_ops = bus_rd_acquire_args->cdm_ops; rsrc_data->cdm_util_ops = bus_rd_acquire_args->cdm_ops; - - subscribe_irq = 1; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + rsrc_data->is_offline = bus_rd_acquire_args->is_offline; for (i = 0; i < num_rm; i++) { rc = cam_vfe_bus_acquire_rm(ver1_bus_rd_priv, - bus_rd_acquire_args->out_port_info, acq_args->tasklet, acq_args->priv, bus_rd_res_id, i, - subscribe_irq, &rsrc_data->rm_res[i], &client_done_mask, - bus_rd_acquire_args->is_dual); + bus_rd_acquire_args->is_dual, + bus_rd_acquire_args->unpacker_fmt); if (rc) { CAM_ERR(CAM_ISP, - "VFE%d RM acquire failed for Out %d rc=%d", + "VFE:%d RM:%d acquire failed rc:%d", rsrc_data->common_data->core_index, bus_rd_res_id, rc); goto release_rm; @@ -523,7 +611,8 @@ static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; bus_rd_acquire_args->rsrc_node = rsrc_node; - CAM_DBG(CAM_ISP, "Acquire successful"); + CAM_DBG(CAM_ISP, "VFE:%d acquire RD 0x%x successful", + rsrc_data->common_data->core_index, acq_args->rsrc_type); return rc; release_rm: @@ -538,7 +627,6 @@ static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, uint32_t i; struct cam_isp_resource_node *vfe_bus_rd = NULL; struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; - uint32_t secure_caps = 0; if (!bus_priv || !release_args) { CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", @@ -550,8 +638,10 @@ static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, rsrc_data = vfe_bus_rd->res_priv; if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { - CAM_ERR(CAM_ISP, "Invalid resource state:%d", - vfe_bus_rd->res_state); + CAM_ERR(CAM_ISP, + "VFE:%d RD type:0x%x invalid resource state:%d", + rsrc_data->common_data->core_index, + vfe_bus_rd->res_id, vfe_bus_rd->res_state); } for (i = 0; i < rsrc_data->num_rm; i++) @@ -562,32 +652,6 @@ static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, vfe_bus_rd->cdm_ops = NULL; rsrc_data->cdm_util_ops = NULL; - secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->bus_rd_type); - mutex_lock(&rsrc_data->common_data->bus_mutex); - if (secure_caps) { - if (rsrc_data->secure_mode == - rsrc_data->common_data->secure_mode) { - rsrc_data->common_data->num_sec_out--; - rsrc_data->secure_mode = - CAM_SECURE_MODE_NON_SECURE; - } else { - /* - * The validity of the mode is properly - * checked while acquiring the output port. - * not expected to reach here, unless there is - * some corruption. - */ - CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", - rsrc_data->common_data->secure_mode, - rsrc_data->secure_mode); - } - - if (!rsrc_data->common_data->num_sec_out) - rsrc_data->common_data->secure_mode = - CAM_SECURE_MODE_NON_SECURE; - } - mutex_unlock(&rsrc_data->common_data->bus_mutex); - if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; @@ -595,31 +659,56 @@ static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, } static int cam_vfe_bus_start_vfe_bus_rd( - struct cam_isp_resource_node *vfe_out) + struct cam_isp_resource_node *vfe_bus_rd) { int rc = 0, i; - struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; - struct cam_vfe_bus_rd_ver1_common_data *common_data = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + struct cam_vfe_bus_rd_ver1_common_data *common_data = NULL; + uint32_t irq_reg_mask[1] = {0x6}, val = 0; - if (!vfe_out) { + if (!vfe_bus_rd) { CAM_ERR(CAM_ISP, "Invalid input"); return -EINVAL; } - rsrc_data = vfe_out->res_priv; + rsrc_data = vfe_bus_rd->res_priv; common_data = rsrc_data->common_data; - CAM_DBG(CAM_ISP, "Start resource type: %x", rsrc_data->bus_rd_type); + CAM_DBG(CAM_ISP, "VFE:%d start RD type:0x%x", vfe_bus_rd->res_id); - if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { CAM_ERR(CAM_ISP, "Invalid resource state:%d", - vfe_out->res_state); + vfe_bus_rd->res_state); return -EACCES; } + if (!rsrc_data->is_offline) { + val = (common_data->fs_sync_enable << 5) | + (common_data->go_cmd_sel << 4); + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->input_if_cmd); + } + for (i = 0; i < rsrc_data->num_rm; i++) rc = cam_vfe_bus_start_rm(rsrc_data->rm_res[i]); - vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, + CAM_IRQ_PRIORITY_1, + irq_reg_mask, + vfe_bus_rd, + cam_vfe_bus_rd_handle_irq_top_half, + cam_vfe_bus_rd_handle_irq_bottom_half, + vfe_bus_rd->tasklet_info, + &tasklet_bh_api); + + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS RD IRQ"); + rsrc_data->irq_handle = 0; + return -EFAULT; + } + + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; return rc; } @@ -629,7 +718,6 @@ static int cam_vfe_bus_stop_vfe_bus_rd( int rc = 0, i; struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; - CAM_DBG(CAM_ISP, "E:Stop rd Res"); if (!vfe_bus_rd) { CAM_ERR(CAM_ISP, "Invalid input"); return -EINVAL; @@ -639,14 +727,26 @@ static int cam_vfe_bus_stop_vfe_bus_rd( if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { - CAM_DBG(CAM_ISP, "vfe_out res_state is %d", + CAM_DBG(CAM_ISP, "VFE:%d Bus RD 0x%x state: %d", + rsrc_data->common_data->core_index, vfe_bus_rd->res_id, vfe_bus_rd->res_state); return rc; } for (i = 0; i < rsrc_data->num_rm; i++) rc = cam_vfe_bus_stop_rm(rsrc_data->rm_res[i]); + if (rsrc_data->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + rsrc_data->common_data->bus_irq_controller, + rsrc_data->irq_handle); + rsrc_data->irq_handle = 0; + } + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + CAM_DBG(CAM_ISP, "VFE:%d stopped Bus RD:0x%x", + rsrc_data->common_data->core_index, + vfe_bus_rd->res_id); return rc; } @@ -661,7 +761,7 @@ static int cam_vfe_bus_init_vfe_bus_read_resource(uint32_t index, bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; if (vfe_bus_rd_resc_type < 0 || - vfe_bus_rd_resc_type > CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0) { + vfe_bus_rd_resc_type >= CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX) { CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", vfe_bus_rd_resc_type); return -EINVAL; @@ -699,7 +799,7 @@ static int cam_vfe_bus_init_vfe_bus_read_resource(uint32_t index, vfe_bus_rd->start = cam_vfe_bus_start_vfe_bus_rd; vfe_bus_rd->stop = cam_vfe_bus_stop_vfe_bus_rd; - vfe_bus_rd->process_cmd = cam_vfe_bus_process_cmd; + vfe_bus_rd->process_cmd = cam_vfe_bus_rd_process_cmd; vfe_bus_rd->hw_intf = bus_rd_priv->common_data.hw_intf; return 0; @@ -738,13 +838,18 @@ static int cam_vfe_bus_deinit_vfe_bus_rd_resource( } static int cam_vfe_bus_rd_ver1_handle_irq(uint32_t evt_id, - struct cam_irq_th_payload *th_payload) + struct cam_irq_th_payload *th_payload) { - struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + int rc = 0; - bus_priv = th_payload->handler_priv; - CAM_DBG(CAM_ISP, "BUS READ IRQ Received"); - return 0; + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "Top Bus RD IRQ Received"); + + rc = cam_irq_controller_handle_irq(evt_id, + bus_priv->common_data.bus_irq_controller); + + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; } static int cam_vfe_bus_rd_update_rm(void *priv, void *cmd_args, @@ -757,7 +862,6 @@ static int cam_vfe_bus_rd_update_rm(void *priv, void *cmd_args, struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; uint32_t *reg_val_pair; uint32_t i, j, size = 0; - uint32_t val; uint32_t buf_size = 0; bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; @@ -794,39 +898,32 @@ static int cam_vfe_bus_rd_update_rm(void *priv, void *cmd_args, rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; /* update size register */ - rm_data->width = io_cfg->planes[i].width; + cam_vfe_bus_rd_pxls_to_bytes(io_cfg->planes[i].width, + rm_data->unpacker_cfg, &rm_data->width); rm_data->height = io_cfg->planes[i].height; - CAM_DBG(CAM_ISP, "RM %d image w 0x%x h 0x%x image size 0x%x", - rm_data->index, rm_data->width, rm_data->height, - buf_size); buf_size = ((rm_data->width)&(0x0000FFFF)) | ((rm_data->height<<16)&(0xFFFF0000)); - CAM_DBG(CAM_ISP, "size offset 0x%x buf_size 0x%x", - rm_data->hw_regs->buf_size, buf_size); CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, rm_data->hw_regs->buf_size, buf_size); - CAM_DBG(CAM_ISP, "RM %d image size 0x%x", + CAM_DBG(CAM_ISP, "VFE:%d RM:%d image_size:0x%X", + rm_data->common_data->core_index, rm_data->index, reg_val_pair[j-1]); - val = rm_data->width; - CAM_DBG(CAM_ISP, "io_cfg stride 0x%x", val); + rm_data->stride = io_cfg->planes[i].plane_stride; CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - rm_data->hw_regs->stride, - val); - rm_data->stride = val; - CAM_DBG(CAM_ISP, "RM %d image stride 0x%x", + rm_data->hw_regs->stride, rm_data->stride); + CAM_DBG(CAM_ISP, "VFE:%d RM:%d image_stride:0x%X", + rm_data->common_data->core_index, rm_data->index, reg_val_pair[j-1]); - /* RM Image address */ - CAM_DBG(CAM_ISP, "image_addr offset %x", - rm_data->hw_regs->image_addr); CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, rm_data->hw_regs->image_addr, update_buf->rm_update->image_buf[i] + rm_data->offset); - CAM_DBG(CAM_ISP, "RM %d image address 0x%x", + CAM_DBG(CAM_ISP, "VFE:%d RM:%d image_address:0x%X", + rm_data->common_data->core_index, rm_data->index, reg_val_pair[j-1]); rm_data->img_addr = reg_val_pair[j-1]; @@ -887,43 +984,93 @@ static int cam_vfe_bus_rd_update_fs_cfg(void *priv, void *cmd_args, common_data = rm_data->common_data; rm_data->format = fe_cfg->format; - CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); - rm_data->unpacker_cfg = fe_cfg->unpacker_cfg; - CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); - rm_data->latency_buf_allocation = fe_cfg->latency_buf_size; - CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", - rm_data->latency_buf_allocation); - rm_data->stride = fe_cfg->stride; - CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); - rm_data->go_cmd_sel = fe_cfg->go_cmd_sel; - CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); - rm_data->fs_sync_enable = fe_cfg->fs_sync_enable; - CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", - rm_data->fs_sync_enable); - rm_data->hbi_count = fe_cfg->hbi_count; - CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); - rm_data->fs_line_sync_en = fe_cfg->fs_line_sync_en; - CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", - rm_data->fs_line_sync_en); - rm_data->fs_mode = fe_cfg->fs_mode; - CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); - rm_data->min_vbi = fe_cfg->min_vbi; - CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + + CAM_DBG(CAM_ISP, + "VFE:%d RM:%d format:0x%x unpacker_cfg:0x%x", + rm_data->format, rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, + "latency_buf_alloc:0x%x stride:0x%x go_cmd_sel:0x%x", + rm_data->latency_buf_allocation, rm_data->stride, + rm_data->go_cmd_sel); + CAM_DBG(CAM_ISP, + "fs_sync_en:%d hbi_cnt:0x%x fs_mode:0x%x min_vbi:0x%x", + rm_data->fs_sync_enable, rm_data->hbi_count, + rm_data->fs_mode, rm_data->min_vbi); } bus_priv->common_data.fs_sync_enable = fe_cfg->fs_sync_enable; bus_priv->common_data.go_cmd_sel = fe_cfg->go_cmd_sel; return 0; } +static int cam_vfe_bus_rd_add_go_cmd(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rd_data; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + uint32_t reg_val_pair[2 * CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + int i = 0; + uint32_t val = 0, size = 0, offset = 0; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "invalid ars size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) priv; + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + for (i = 0; i < rd_data->num_rm; i++) { + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, + "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = rd_data->rm_res[i]->res_priv; + offset = rsrc_data->common_data->common_reg->input_if_cmd; + val = cam_io_r_mb(rsrc_data->common_data->mem_base + offset); + val |= 0x1; + reg_val_pair[i * 2] = offset; + reg_val_pair[i * 2 + 1] = val; + CAM_DBG(CAM_ISP, "VFE:%d Bus RD go_cmd: 0x%x offset 0x%x", + rd_data->common_data->core_index, + reg_val_pair[i * 2 + 1], reg_val_pair[i * 2]); + } + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; + +} + static int cam_vfe_bus_start_hw(void *hw_priv, void *start_hw_args, uint32_t arg_size) { @@ -941,7 +1088,7 @@ static int cam_vfe_bus_init_hw(void *hw_priv, { struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; uint32_t top_irq_reg_mask[3] = {0}; - uint32_t offset = 0, val = 0; + uint32_t offset = 0; struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; if (!bus_priv) { @@ -949,7 +1096,7 @@ static int cam_vfe_bus_init_hw(void *hw_priv, return -EINVAL; } common_reg = bus_priv->common_data.common_reg; - top_irq_reg_mask[0] = (1 << 23); + top_irq_reg_mask[0] = (1 << bus_priv->top_irq_shift); bus_priv->irq_handle = cam_irq_controller_subscribe_irq( bus_priv->common_data.vfe_irq_controller, @@ -966,23 +1113,15 @@ static int cam_vfe_bus_init_hw(void *hw_priv, bus_priv->irq_handle = 0; return -EFAULT; } + /* no clock gating at bus input */ offset = common_reg->cgc_ovd; - cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + cam_io_w_mb(0x1, bus_priv->common_data.mem_base + offset); /* BUS_RD_TEST_BUS_CTRL */ offset = common_reg->test_bus_ctrl; cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); - /* Read irq mask */ - offset = common_reg->irq_reg_info.irq_reg_set->mask_reg_offset; - cam_io_w_mb(0x5, bus_priv->common_data.mem_base + offset); - - /* INPUT_IF_CMD */ - val = (bus_priv->common_data.fs_sync_enable << 5) | - (bus_priv->common_data.go_cmd_sel << 4); - offset = common_reg->input_if_cmd; - cam_io_w_mb(val, bus_priv->common_data.mem_base + offset); return 0; } @@ -997,13 +1136,6 @@ static int cam_vfe_bus_deinit_hw(void *hw_priv, return -EINVAL; } - if (bus_priv->error_irq_handle) { - rc = cam_irq_controller_unsubscribe_irq( - bus_priv->common_data.bus_irq_controller, - bus_priv->error_irq_handle); - bus_priv->error_irq_handle = 0; - } - if (bus_priv->irq_handle) { rc = cam_irq_controller_unsubscribe_irq( bus_priv->common_data.vfe_irq_controller, @@ -1014,13 +1146,13 @@ static int cam_vfe_bus_deinit_hw(void *hw_priv, return rc; } -static int __cam_vfe_bus_process_cmd(void *priv, +static int __cam_vfe_bus_rd_process_cmd(void *priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { - return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); + return cam_vfe_bus_rd_process_cmd(priv, cmd_type, cmd_args, arg_size); } -static int cam_vfe_bus_process_cmd( +static int cam_vfe_bus_rd_process_cmd( struct cam_isp_resource_node *priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -1044,6 +1176,9 @@ static int cam_vfe_bus_process_cmd( case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: rc = cam_vfe_bus_rd_update_fs_cfg(priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_FE_TRIGGER_CMD: + rc = cam_vfe_bus_rd_add_go_cmd(priv, cmd_args, arg_size); + break; default: CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", cmd_type); @@ -1102,6 +1237,7 @@ int cam_vfe_bus_rd_ver1_init( bus_priv->common_data.hw_intf = hw_intf; bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; bus_priv->common_data.common_reg = &bus_rd_hw_info->common_reg; + bus_priv->top_irq_shift = bus_rd_hw_info->top_irq_shift; mutex_init(&bus_priv->common_data.bus_mutex); @@ -1141,7 +1277,7 @@ int cam_vfe_bus_rd_ver1_init( vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw; vfe_bus_local->top_half_handler = cam_vfe_bus_rd_ver1_handle_irq; vfe_bus_local->bottom_half_handler = NULL; - vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_rd_process_cmd; *vfe_bus = vfe_bus_local; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h index 19cc86496371..90229b179c0d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_BUS_R_VER1_H_ @@ -88,6 +88,7 @@ struct cam_vfe_bus_rd_ver1_hw_info { uint32_t num_bus_rd_resc; struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info vfe_bus_rd_hw_info[CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; + uint32_t top_irq_shift; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index ac03b3a132dc..f2e85daa5752 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -52,6 +52,8 @@ struct cam_vfe_mux_camif_ver3_data { uint32_t camif_debug; uint32_t horizontal_bin; uint32_t qcfa_bin; + bool is_fe_enabled; + bool is_offline; }; static int cam_vfe_camif_ver3_get_evt_payload( @@ -246,18 +248,20 @@ int cam_vfe_camif_ver3_acquire_resource( return rc; } - camif_data->sync_mode = acquire_data->vfe_in.sync_mode; - camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; - camif_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; - camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start; - camif_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; - camif_data->first_line = acquire_data->vfe_in.in_port->line_start; - camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + camif_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + camif_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + camif_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + camif_data->first_line = acquire_data->vfe_in.in_port->line_start; + camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + camif_data->is_fe_enabled = acquire_data->vfe_in.is_fe_enabled; + camif_data->is_offline = acquire_data->vfe_in.is_offline; + camif_data->event_cb = acquire_data->event_cb; + camif_data->priv = acquire_data->priv; + camif_data->qcfa_bin = acquire_data->vfe_in.in_port->qcfa_bin; camif_data->horizontal_bin = acquire_data->vfe_in.in_port->horizontal_bin; - camif_data->qcfa_bin = acquire_data->vfe_in.in_port->qcfa_bin; - camif_data->event_cb = acquire_data->event_cb; - camif_data->priv = acquire_data->priv; CAM_DBG(CAM_ISP, "VFE:%d CAMIF pix_pattern:%d dsp_mode=%d", camif_res->hw_intf->hw_idx, @@ -419,6 +423,14 @@ static int cam_vfe_camif_ver3_resource_start( val |= (rsrc_data->cam_common_cfg.input_mux_sel_pp & 0x3) << CAM_SHIFT_TOP_CORE_CFG_INPUTMUX_PP; + if (rsrc_data->is_fe_enabled && !rsrc_data->is_offline) + val |= 0x2 << rsrc_data->reg_data->operating_mode_shift; + else + val |= 0x1 << rsrc_data->reg_data->operating_mode_shift; + + CAM_DBG(CAM_ISP, "VFE:%d TOP core_cfg: 0x%X", + camif_res->hw_intf->hw_idx, val); + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg_0); @@ -454,11 +466,14 @@ static int cam_vfe_camif_ver3_resource_start( camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; /* Reg Update */ - cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, - rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd); - CAM_DBG(CAM_ISP, "VFE:%d CAMIF RUP val:0x%X", - camif_res->hw_intf->hw_idx, - rsrc_data->reg_data->reg_update_cmd_data); + if (!rsrc_data->is_offline) { + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + + rsrc_data->camif_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "VFE:%d CAMIF RUP val:0x%X", + camif_res->hw_intf->hw_idx, + rsrc_data->reg_data->reg_update_cmd_data); + } /* disable sof irq debug flag */ rsrc_data->enable_sof_irq_debug = false; @@ -601,6 +616,18 @@ static int cam_vfe_camif_ver3_reg_dump( CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); } + CAM_INFO(CAM_ISP, "IFE:%d BUS RD", camif_res->hw_intf->hw_idx); + for (offset = 0xA800; offset <= 0xA89C; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + if (offset == 0xA838) + offset = 0xA844; + if (offset == 0xA864) + offset = 0xA874; + if (offset == 0xA878) + offset = 0xA87C; + } + CAM_INFO(CAM_ISP, "IFE:%d BUS WR", camif_res->hw_intf->hw_idx); for (offset = 0xAA00; offset <= 0xAADC; offset += 0x4) { val = cam_soc_util_r(camif_priv->soc_info, 0, offset); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index 743950bd01bc..3b242256082b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include @@ -12,7 +12,7 @@ #include "cam_debug_util.h" #include "cam_vfe_soc.h" -#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00000003 +#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00000007 #define CAM_VFE_HW_RESET_HW_VAL 0x007F0000 #define CAM_VFE_LITE_HW_RESET_AND_REG_VAL 0x00000002 #define CAM_VFE_LITE_HW_RESET_HW_VAL 0x0000003D -- GitLab From 04325984b8ca81c0c2b7af5a8051785e2d120a9b Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Tue, 3 Dec 2019 20:18:07 +0800 Subject: [PATCH 215/410] msm: camera: sensor: Turn off the flash while flushing Turn off the flash while flushing if the flushed request turns off the flash. CRs-Fixed: 2576732 Change-Id: I546fc6b6ee79f492af905d163515eb19eed78f41 Signed-off-by: Depeng Shao --- .../cam_flash/cam_flash_core.c | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index 2d8df8a0ac41..8216e5a83b79 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -287,6 +287,8 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, int rc = 0; int i = 0, j = 0; int frame_offset = 0; + bool is_off_needed = false; + struct cam_flash_frame_setting *flash_data = NULL; if (!fctrl) { CAM_ERR(CAM_FLASH, "Device data is NULL"); @@ -296,23 +298,47 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, if (type == FLUSH_ALL) { /* flush all requests*/ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { - fctrl->per_frame[i].cmn_attr.request_id = 0; - fctrl->per_frame[i].cmn_attr.is_settings_valid = false; - fctrl->per_frame[i].cmn_attr.count = 0; + flash_data = + &fctrl->per_frame[i]; + if ((flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) && + (flash_data->cmn_attr.request_id > 0) && + (flash_data->cmn_attr.request_id <= req_id) && + flash_data->cmn_attr.is_settings_valid) { + is_off_needed = true; + CAM_DBG(CAM_FLASH, + "FLASH_ALL: Turn off the flash for req %llu", + flash_data->cmn_attr.request_id); + } + + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; + flash_data->cmn_attr.count = 0; for (j = 0; j < CAM_FLASH_MAX_LED_TRIGGERS; j++) - fctrl->per_frame[i].led_current_ma[j] = 0; + flash_data->led_current_ma[j] = 0; } cam_flash_pmic_flush_nrt(fctrl); } else if ((type == FLUSH_REQ) && (req_id != 0)) { /* flush request with req_id*/ frame_offset = req_id % MAX_PER_FRAME_ARRAY; - fctrl->per_frame[frame_offset].cmn_attr.request_id = 0; - fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid = + flash_data = + &fctrl->per_frame[frame_offset]; + + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) { + is_off_needed = true; + CAM_DBG(CAM_FLASH, + "FLASH_REQ: Turn off the flash for req %llu", + flash_data->cmn_attr.request_id); + } + + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; - fctrl->per_frame[frame_offset].cmn_attr.count = 0; + flash_data->cmn_attr.count = 0; for (i = 0; i < CAM_FLASH_MAX_LED_TRIGGERS; i++) - fctrl->per_frame[frame_offset].led_current_ma[i] = 0; + flash_data->led_current_ma[i] = 0; } else if ((type == FLUSH_REQ) && (req_id == 0)) { /* Handels NonRealTime usecase */ cam_flash_pmic_flush_nrt(fctrl); @@ -321,6 +347,9 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, return -EINVAL; } + if (is_off_needed) + cam_flash_off(fctrl); + return rc; } @@ -567,7 +596,9 @@ static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", top, del_req_id); } - fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + + cam_flash_i2c_flush_nrt(fctrl); + return 0; } @@ -577,6 +608,7 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, int i = 0; struct cam_flash_frame_setting *flash_data = NULL; uint64_t top = 0, del_req_id = 0; + int frame_offset = 0; if (req_id != 0) { for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { @@ -612,7 +644,16 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, top, del_req_id); } - fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + /* delete the request */ + frame_offset = del_req_id % MAX_PER_FRAME_ARRAY; + flash_data = &fctrl->per_frame[frame_offset]; + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; + flash_data->cmn_attr.count = 0; + + for (i = 0; i < CAM_FLASH_MAX_LED_TRIGGERS; i++) + flash_data->led_current_ma[i] = 0; + return 0; } -- GitLab From ecc1637fd7abd4a8aac3afbba2dde993f10b196f Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 16 Jan 2020 12:14:03 -0800 Subject: [PATCH 216/410] msm: camera: ife: Reduce config done timeout during stop This change reduces the duration of wait for config done during stop and flush. We perform wait for completion once for reg dump during flush so there is no need for a long wait during stop. CRs-Fixed: 2606911 Change-Id: Ib1c2d7655d8a213495618a140acea2391b262082 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index f1fc8fb44c8d..97646dd46729 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -3870,19 +3870,13 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) cam_ife_mgr_pause_hw(ctx); - rc = wait_for_completion_timeout( - &ctx->config_done_complete, - msecs_to_jiffies(300)); - if (rc <= 0) { + rc = wait_for_completion_timeout(&ctx->config_done_complete, + msecs_to_jiffies(10)); + if (rc == 0) { CAM_WARN(CAM_ISP, "config done completion timeout for last applied req_id=%llu rc=%d ctx_index %d", ctx->applied_req_id, rc, ctx->ctx_index); rc = -ETIMEDOUT; - } else { - CAM_DBG(CAM_ISP, - "config done Success for req_id=%llu ctx_index %d", - ctx->applied_req_id, ctx->ctx_index); - rc = 0; } if (stop_isp->stop_only) -- GitLab From 2763caffc8975df9e3fc0433014af7718c217e65 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 11 Dec 2019 13:20:01 -0800 Subject: [PATCH 217/410] msm: camera: req_mgr: Increase watchdog timeout This change increases the watchdog timeout value from one second to five. CRs-Fixed: 2606911 Change-Id: I353f78369c31a513dfd94dd1988bc42c2f75b167 Signed-off-by: Venkat Chinta --- drivers/cam_req_mgr/cam_req_mgr_core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index df4a890079a8..a78309bcb1e3 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_CORE_H_ #define _CAM_REQ_MGR_CORE_H_ @@ -13,7 +13,7 @@ #define CAM_REQ_MGR_MAX_LINKED_DEV 16 #define MAX_REQ_SLOTS 48 -#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 1000 +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 5000 #define CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX 50000 #define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 #define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 -- GitLab From 6606f1a75446ef9889a72dfaafc5894491abf33b Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 14 Jan 2020 15:53:54 -0800 Subject: [PATCH 218/410] msm: camera: req_mgr: Reduce maximum attempts to apply request This change reduces the maximum attempts to apply a particular request from three to two. After two failed attempts to apply to ISP device, IRQs for ISP device will be overlapped from two requests. Thereafter apply request at every alternate frame will fail without a chance of recovery. Therefore we must notify userspace to trigger recover on the link. CRs-Fixed: 2606911 Change-Id: I526bb837a496fe1e67786b854c5afb062dddb918 Signed-off-by: Venkat Chinta --- drivers/cam_req_mgr/cam_req_mgr_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index a78309bcb1e3..b037c4364790 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -33,7 +33,7 @@ #define MAXIMUM_LINKS_PER_SESSION 4 -#define MAXIMUM_RETRY_ATTEMPTS 3 +#define MAXIMUM_RETRY_ATTEMPTS 2 #define VERSION_1 1 #define VERSION_2 2 -- GitLab From 1189e7ac86b657c87c0c4de6883d5de8dd9697bd Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 19 Dec 2019 16:00:05 -0800 Subject: [PATCH 219/410] msm: camera: ife: Disable clock gating at top Clock gating must be disabled at top level initialize hardware routine as VFE is reset after resource level initialize hardware routine. CRs-Fixed: 2590331 Change-Id: I5c51c402a3a6076f056368493b774daa199228aa Signed-off-by: Venkat Chinta --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 14 -------------- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index f2e85daa5752..6f1e28110b5f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -296,20 +296,6 @@ static int cam_vfe_camif_ver3_resource_init( "failed to enable dsp clk, rc = %d", rc); } - /* All auto clock gating disabled by default */ - CAM_INFO(CAM_ISP, "overriding clock gating"); - cam_io_w_mb(0xFFFFFFFF, camif_data->mem_base + - camif_data->common_reg->core_cgc_ovd_0); - - cam_io_w_mb(0xFF, camif_data->mem_base + - camif_data->common_reg->core_cgc_ovd_1); - - cam_io_w_mb(0x1, camif_data->mem_base + - camif_data->common_reg->ahb_cgc_ovd); - - cam_io_w_mb(0x1, camif_data->mem_base + - camif_data->common_reg->noc_cgc_ovd); - return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index 3b242256082b..15d9b0e1a8cd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -222,9 +222,24 @@ int cam_vfe_top_ver3_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { struct cam_vfe_top_ver3_priv *top_priv = device_priv; + struct cam_vfe_top_ver3_common_data common_data = top_priv->common_data; top_priv->hw_clk_rate = 0; + /* Disable clock gating at IFE top */ + CAM_INFO(CAM_ISP, "Disable clock gating at IFE top"); + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->core_cgc_ovd_0, 0xFFFFFFFF); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->core_cgc_ovd_1, 0xFF); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->ahb_cgc_ovd, 0x1); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->noc_cgc_ovd, 0x1); + return 0; } -- GitLab From 0079fd9f37f1c120913f52dcf04dc5c7e1e606c4 Mon Sep 17 00:00:00 2001 From: Sravan Muppidi Date: Mon, 6 Jan 2020 09:51:18 +0530 Subject: [PATCH 220/410] msm: camera: core: Avoid concurrency between stop and pfdump Camera context layer checks the state of the driver context and allow the events to proceed. Two events should not execute concurrently on context. Currently Dumping platform data executing concurrently with flush or stop. This changes avoid the concurrent execute of dump pf data and other events. Added validation check in cam_context_config_dev_to_hw. CRs-Fixed: 2602229 Change-Id: Ib5aaff0edbd39dd63e7eb1c38207f765da294817 Signed-off-by: Sravan Muppidi --- drivers/cam_core/cam_context.c | 4 +++- drivers/cam_core/cam_context_utils.c | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 267b23dafa72..9e24505fe213 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -268,6 +268,7 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, return -EINVAL; } + mutex_lock(&ctx->ctx_mutex); if ((ctx->state > CAM_CTX_AVAILABLE) && (ctx->state < CAM_CTX_STATE_MAX)) { if (ctx->state_machine[ctx->state].pagefault_ops) { @@ -278,6 +279,7 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, ctx->dev_hdl, ctx->state); } } + mutex_unlock(&ctx->ctx_mutex); return rc; } diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 87abebabaf00..b9d438db0f8f 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -296,6 +296,13 @@ int32_t cam_context_config_dev_to_hw( return rc; } + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, "Not enough buf, len : %zu offset = %llu", + len, cmd->offset); + return -EINVAL; + + } packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); -- GitLab From 5cbff44a78eae5e79d101edd36cb0510b9ba1e28 Mon Sep 17 00:00:00 2001 From: Prakasha Nayak Date: Wed, 6 Nov 2019 17:02:50 +0530 Subject: [PATCH 221/410] msm: camera: isp: Add epd Blob support This change adds blob support to disable CSID EOT IRQ in case of high data rate sensors which sends EPD instead of EOT. CRs-Fixed: 2566158 Change-Id: I8ac6d2281a6510d3702f3b651e2c7ca2391afe6c Signed-off-by: Prakasha Nayak --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 67 +++++++++++++++++-- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 29 +++++++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 3 +- .../isp_hw/include/cam_ife_csid_hw_intf.h | 9 +++ include/uapi/media/cam_isp.h | 12 +++- 5 files changed, 111 insertions(+), 9 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 97646dd46729..89e8a556a357 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -5163,6 +5163,51 @@ static int cam_isp_blob_vfe_out_update( return rc; } +static int cam_isp_blob_csid_config_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_csid_epd_config *epd_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_csid_epd_update_args epd_update_args; + int rc = -EINVAL; + uint32_t i = 0; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + epd_update_args.epd_supported = + epd_config->is_epd_supported; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_SET_CONFIG, + &epd_update_args, + sizeof( + struct cam_ife_csid_epd_update_args) + ); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to epd config:%d", + epd_config->is_epd_supported); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + + } + } + + return rc; +} static int cam_isp_packet_generic_blob_handler(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) { @@ -5177,12 +5222,6 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, return -EINVAL; } - if (blob_type >= CAM_ISP_GENERIC_BLOB_TYPE_MAX) { - CAM_ERR(CAM_ISP, "Invalid Blob Type %d Max %d", blob_type, - CAM_ISP_GENERIC_BLOB_TYPE_MAX); - return -EINVAL; - } - prepare = blob_info->prepare; if (!prepare || !prepare->ctxt_to_hw_map) { CAM_ERR(CAM_ISP, "Failed. prepare is NULL, blob_type %d", @@ -5632,7 +5671,23 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "VFE out update failed rc: %d", rc); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_CSID_CONFIG: { + struct cam_isp_csid_epd_config *epd_config; + if (blob_size < sizeof(struct cam_isp_csid_epd_config)) { + CAM_ERR(CAM_ISP, + "Invalid epd config blob size %u expected %u", + blob_size, + sizeof(struct cam_isp_csid_epd_config)); + return -EINVAL; + } + epd_config = (struct cam_isp_csid_epd_config *)blob_data; + rc = cam_isp_blob_csid_config_update(blob_type, blob_info, + epd_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "CSID Config failed rc: %d", rc); + } + break; default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 985cd134a465..81fdd87b8679 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -518,6 +518,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; csid_hw->prev_boot_timestamp = 0; + csid_hw->epd_supported = 0; end: return rc; @@ -1356,6 +1357,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; csid_hw->prev_boot_timestamp = 0; + csid_hw->epd_supported = 0; return rc; } @@ -1591,7 +1593,6 @@ static int cam_ife_csid_enable_csi2( CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW | CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW | CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW | - CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION | CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION | CSID_CSI2_RX_ERROR_CRC | CSID_CSI2_RX_ERROR_ECC | @@ -1600,6 +1601,12 @@ static int cam_ife_csid_enable_csi2( CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME | CSID_CSI2_RX_ERROR_CPHY_PH_CRC; + if (csid_hw->epd_supported == 1) + CAM_INFO(CAM_ISP, + "Disable CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION for EPD"); + else + val = val | CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION; + /* Enable the interrupt based on csid debug info set */ if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) val |= CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED | @@ -3862,6 +3869,23 @@ static int cam_ife_csid_dump_hw( return 0; } +static int cam_ife_csid_set_epd_config( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_ife_csid_epd_update_args *epd_update = NULL; + + if ((!csid_hw) || (!cmd_args)) + return -EINVAL; + + epd_update = + (struct cam_ife_csid_epd_update_args *)cmd_args; + + csid_hw->epd_supported = epd_update->epd_supported; + CAM_DBG(CAM_ISP, "CSID EPD supported %d", csid_hw->epd_supported); + + return 0; +} + static int cam_ife_csid_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -3902,6 +3926,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_DUMP_HW: rc = cam_ife_csid_dump_hw(csid_hw, cmd_args); break; + case CAM_IFE_CSID_SET_CONFIG: + rc = cam_ife_csid_set_epd_config(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index c7a648daff86..71a451b89198 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -552,9 +552,9 @@ struct cam_ife_csid_path_cfg { * need to stop the CSID and mask interrupts. * @binning_enable Flag is set if hardware supports QCFA binning * @binning_supported Flag is set if sensor supports QCFA binning - * * @first_sof_ts first bootime stamp at the start * @prev_qtimer_ts stores csid timestamp + * @epd_supported Flag is set if sensor supports EPD */ struct cam_ife_csid_hw { struct cam_hw_intf *hw_intf; @@ -588,6 +588,7 @@ struct cam_ife_csid_hw { uint32_t binning_supported; uint64_t prev_boot_timestamp; uint64_t prev_qtimer_ts; + uint32_t epd_supported; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 3092b81352c3..78c457b6a7cb 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -205,6 +205,7 @@ enum cam_ife_csid_cmd_type { CAM_IFE_CSID_CMD_GET_TIME_STAMP, CAM_IFE_CSID_SET_CSID_DEBUG, CAM_IFE_CSID_SOF_IRQ_DEBUG, + CAM_IFE_CSID_SET_CONFIG, CAM_IFE_CSID_CMD_MAX, }; @@ -237,5 +238,13 @@ struct cam_ife_csid_qcfa_update_args { uint32_t qcfa_binning; }; +/* + * struct cam_ife_csid_epd_update_args: + * + * @epd_supported: flag to check epd supported or not + */ +struct cam_ife_csid_epd_update_args { + uint32_t epd_supported; +}; #endif /* _CAM_CSID_HW_INTF_H_ */ diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 6d6a16c5ffad..ef10e615cdf7 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_CAM_ISP_H__ @@ -102,6 +102,7 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG 7 #define CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG 8 #define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 9 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CONFIG 10 #define CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG 12 #define CAM_ISP_VC_DT_CFG 4 @@ -697,6 +698,15 @@ struct cam_isp_vfe_out_config { struct cam_isp_vfe_wm_config wm_config[1]; }; +/** + * struct cam_isp_csid_epd_config - Support for EPD Packet config + * + * @is_epd_sensor : flag to check if epd supported + */ +struct cam_isp_csid_epd_config { + uint32_t is_epd_supported; +}; + #define CAM_ISP_ACQUIRE_COMMON_VER0 0x1000 #define CAM_ISP_ACQUIRE_COMMON_SIZE_VER0 0x0 -- GitLab From 85ef6928a3c4272a4ea2061428facb313409f1cd Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Tue, 14 Jan 2020 14:44:43 +0530 Subject: [PATCH 222/410] msm: camera: req_mgr: Update link activate/deactivate to avoid race When cam request manager gets a request to deactivate a link, we do pause for each of the device for that link. There is a race here in current scenario that workqueues can be scheduled even after the link has been deactivated. This can lead to unexpected behavior. This change has updated the activate and deactivate handling to take care of the race. CRs-Fixed: 2601863 Change-Id: I7ff03c74c240fc3250618db518d586531d87369f Signed-off-by: Vikram Sharma --- drivers/cam_req_mgr/cam_req_mgr_core.c | 96 +++++++++++++++----------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 91e3ee1cdc4d..1a3d1901f05e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -535,32 +535,40 @@ static void __cam_req_mgr_validate_crm_wd_timer( CAM_DBG(CAM_CRM, "rd_idx: %d idx: %d current_frame_timeout: %d ms", in_q->rd_idx, idx, current_frame_timeout); - - if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > - link->watchdog->expires) { - CAM_DBG(CAM_CRM, - "Modifying wd timer expiry from %d ms to %d ms", - link->watchdog->expires, - (next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); - crm_timer_modify(link->watchdog, - next_frame_timeout + - CAM_REQ_MGR_WATCHDOG_TIMEOUT); - } else if (current_frame_timeout) { - CAM_DBG(CAM_CRM, - "Reset wd timer to current frame from %d ms to %d ms", - link->watchdog->expires, - (current_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); - crm_timer_modify(link->watchdog, - current_frame_timeout + - CAM_REQ_MGR_WATCHDOG_TIMEOUT); - } else if (link->watchdog->expires > - CAM_REQ_MGR_WATCHDOG_TIMEOUT) { - CAM_DBG(CAM_CRM, - "Reset wd timer to default from %d ms to %d ms", - link->watchdog->expires, CAM_REQ_MGR_WATCHDOG_TIMEOUT); - crm_timer_modify(link->watchdog, - CAM_REQ_MGR_WATCHDOG_TIMEOUT); + spin_lock_bh(&link->link_state_spin_lock); + if (link->watchdog) { + if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > + link->watchdog->expires) { + CAM_DBG(CAM_CRM, + "Modifying wd timer expiry from %d ms to %d ms", + link->watchdog->expires, + (next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (current_frame_timeout) { + CAM_DBG(CAM_CRM, + "Reset wd timer to frame from %d ms to %d ms", + link->watchdog->expires, + (current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (link->watchdog->expires > + CAM_REQ_MGR_WATCHDOG_TIMEOUT) { + CAM_DBG(CAM_CRM, + "Reset wd timer to default from %d ms to %d ms", + link->watchdog->expires, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + crm_timer_modify(link->watchdog, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } + } else { + CAM_WARN(CAM_CRM, "Watchdog timer exited already"); } + spin_unlock_bh(&link->link_state_spin_lock); } /** @@ -1720,6 +1728,14 @@ static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) link = (struct cam_req_mgr_core_link *)priv; session = (struct cam_req_mgr_core_session *)link->parent; + spin_lock_bh(&link->link_state_spin_lock); + if ((link->watchdog) && (link->watchdog->pause_timer)) { + CAM_INFO(CAM_CRM, "Watchdog Paused"); + spin_unlock_bh(&link->link_state_spin_lock); + return rc; + } + spin_unlock_bh(&link->link_state_spin_lock); + CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", session->session_hdl, link->link_hdl); @@ -1764,9 +1780,6 @@ static void __cam_req_mgr_sof_freeze(struct timer_list *timer_data) link = (struct cam_req_mgr_core_link *)timer->parent; - if (link->watchdog->pause_timer) - return; - task = cam_req_mgr_workq_get_task(link->workq); if (!task) { CAM_ERR(CAM_CRM, "No empty task"); @@ -2753,11 +2766,9 @@ static int cam_req_mgr_cb_notify_timer( rc = -EPERM; goto end; } - spin_unlock_bh(&link->link_state_spin_lock); - - - if (!timer_data->state) + if ((link->watchdog) && (!timer_data->state)) link->watchdog->pause_timer = true; + spin_unlock_bh(&link->link_state_spin_lock); end: return rc; @@ -2865,7 +2876,7 @@ static int cam_req_mgr_cb_notify_trigger( goto end; } - if (link->watchdog->pause_timer) + if ((link->watchdog) && (link->watchdog->pause_timer)) link->watchdog->pause_timer = false; crm_timer_reset(link->watchdog); @@ -3152,14 +3163,15 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) /* Destroy workq of link */ cam_req_mgr_workq_destroy(&link->workq); - + spin_lock_bh(&link->link_state_spin_lock); /* Destroy timer of link */ crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); /* Cleanup request tables and unlink devices */ __cam_req_mgr_destroy_link_info(link); - /* Free memory holding data of linked devs */ + __cam_req_mgr_destroy_subdev(link->l_dev); /* Destroy the link handle */ @@ -3787,6 +3799,9 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) mutex_lock(&link->lock); if (control->ops == CAM_REQ_MGR_LINK_ACTIVATE) { + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); /* Start SOF watchdog timer */ rc = crm_timer_init(&link->watchdog, CAM_REQ_MGR_WATCHDOG_TIMEOUT, link, @@ -3808,10 +3823,6 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) dev->ops->process_evt(&evt_data); } } else if (control->ops == CAM_REQ_MGR_LINK_DEACTIVATE) { - /* Destroy SOF watchdog timer */ - spin_lock_bh(&link->link_state_spin_lock); - crm_timer_exit(&link->watchdog); - spin_unlock_bh(&link->link_state_spin_lock); /* notify nodes */ for (j = 0; j < link->num_devs; j++) { dev = &link->l_dev[j]; @@ -3822,6 +3833,11 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) if (dev->ops && dev->ops->process_evt) dev->ops->process_evt(&evt_data); } + /* Destroy SOF watchdog timer */ + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_IDLE; + crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); } else { CAM_ERR(CAM_CRM, "Invalid link control command"); rc = -EINVAL; -- GitLab From cd707bb7331ce85d8bf2b136cb94cab130339d36 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 27 Jan 2020 16:59:53 +0530 Subject: [PATCH 223/410] msm: camera: isp: Add irq mask for lagoon vfe Enable the vfe camif and rdi interrupts for lagoon vfe. Change-Id: I6447c74c83fa153ad50c72b1ce94d3f3674216a1 CRs-Fixed: 2571273 Signed-off-by: Gaurav Jindal --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h index df5cc3594b98..15f4380ba935 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -75,6 +75,8 @@ static struct cam_vfe_camif_reg_data vfe_170_150_camif_reg_data = { .eof_irq_mask = 0x00000002, .error_irq_mask0 = 0x0003FC00, .error_irq_mask1 = 0x0FFF7E80, + .subscribe_irq_mask0 = 0x00000017, + .subscribe_irq_mask1 = 0x0, .enable_diagnostic_hw = 0x1, .dual_vfe_sync_mask = 0x3, }; @@ -128,6 +130,13 @@ static struct cam_vfe_rdi_ver2_reg vfe170_150_rdi_reg = { .reg_update_cmd = 0x000004AC, }; +static struct cam_vfe_rdi_common_reg_data vfe170_150_rdi_reg_data = { + .subscribe_irq_mask0 = 0x780001E0, + .subscribe_irq_mask1 = 0x0, + .error_irq_mask0 = 0x0, + .error_irq_mask1 = 0x3C, +}; + static struct cam_vfe_rdi_reg_data vfe_170_150_rdi_0_data = { .reg_update_cmd_data = 0x2, .sof_irq_mask = 0x8000000, @@ -161,6 +170,7 @@ static struct cam_vfe_top_ver2_hw_info vfe170_150_top_hw_info = { .rdi_hw_info = { .common_reg = &vfe170_150_top_common_reg, .rdi_reg = &vfe170_150_rdi_reg, + .common_reg_data = &vfe170_150_rdi_reg_data, .reg_data = { &vfe_170_150_rdi_0_data, &vfe_170_150_rdi_1_data, -- GitLab From f3a1bc3df3b2cf2ddb6c9265022b70e938ddf89c Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 8 Jan 2020 19:04:51 -0800 Subject: [PATCH 224/410] msm: camera: custom: Add support for immediate stop Add support for immediate stop and reset during flush for custom HW. CRs-Fixed: 2585745 Change-Id: I542ac02f8d99c194efa498bc07dffae7879a6c8a Signed-off-by: Karthik Anantha Ram --- drivers/cam_cust/cam_custom_context.c | 227 +++++++++++++----- .../cam_custom_hw_mgr/cam_custom_hw_mgr.c | 99 +++++++- 2 files changed, 268 insertions(+), 58 deletions(-) diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index 3e69ebd15109..25e092841cef 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/drivers/cam_cust/cam_custom_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include @@ -24,6 +24,10 @@ static const char custom_dev_name[] = "cam-custom"; static int __cam_custom_ctx_handle_irq_in_activated( void *context, uint32_t evt_id, void *evt_data); +static int __cam_custom_ctx_start_dev_in_ready( + struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); + + static int __cam_custom_ctx_enqueue_request_in_order( struct cam_context *ctx, struct cam_ctx_request *req) { @@ -131,22 +135,104 @@ static int __cam_custom_ctx_flush_req(struct cam_context *ctx, return 0; } +static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + + return 0; +} + +static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->state = CAM_CTX_ACQUIRED; + + return 0; +} + +static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_device_info *dev_info) +{ + dev_info->dev_hdl = ctx->dev_hdl; + strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name)); + dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW; + dev_info->p_delay = 1; + dev_info->trigger = CAM_TRIGGER_POINT_SOF; + + return 0; +} + static int __cam_custom_ctx_flush_req_in_top_state( struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) { int rc = 0; + struct cam_custom_context *custom_ctx; + struct cam_hw_reset_args reset_args; + struct cam_hw_stop_args stop_args; + struct cam_custom_stop_args custom_stop; + + custom_ctx = + (struct cam_custom_context *) ctx->ctx_priv; + + CAM_DBG(CAM_CUSTOM, "Flushing pending list"); + spin_lock_bh(&ctx->lock); + __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + if (ctx->state <= CAM_CTX_READY) { + ctx->state = CAM_CTX_ACQUIRED; + goto end; + } + + spin_lock_bh(&ctx->lock); + ctx->state = CAM_CTX_FLUSHED; + spin_unlock_bh(&ctx->lock); + CAM_INFO(CAM_CUSTOM, "Last request id to flush is %lld", flush_req->req_id); ctx->last_flush_req = flush_req->req_id; - } - spin_lock_bh(&ctx->lock); - rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); - spin_unlock_bh(&ctx->lock); + /* stop hw first */ + if (ctx->hw_mgr_intf->hw_stop) { + custom_stop.stop_only = true; + stop_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + stop_args.args = (void *) &custom_stop; + rc = ctx->hw_mgr_intf->hw_stop( + ctx->hw_mgr_intf->hw_mgr_priv, &stop_args); + if (rc) + CAM_ERR(CAM_CUSTOM, + "HW stop failed in flush rc %d", rc); + } + + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->wait_req_list)) + __cam_custom_ctx_flush_req(ctx, &ctx->wait_req_list, + flush_req); + if (!list_empty(&ctx->active_req_list)) + __cam_custom_ctx_flush_req(ctx, &ctx->active_req_list, + flush_req); + + custom_ctx->active_req_cnt = 0; + spin_unlock_bh(&ctx->lock); + + reset_args.ctxt_to_hw_map = custom_ctx->hw_ctx; + rc = ctx->hw_mgr_intf->hw_reset(ctx->hw_mgr_intf->hw_mgr_priv, + &reset_args); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Reset HW failed in flush rc %d", rc); + + custom_ctx->init_received = false; + } + +end: return rc; } @@ -170,34 +256,27 @@ static int __cam_custom_ctx_flush_req_in_ready( return rc; } -static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx, - struct cam_req_mgr_core_dev_link_setup *unlink) -{ - ctx->link_hdl = -1; - ctx->ctx_crm_intf = NULL; - ctx->state = CAM_CTX_ACQUIRED; - - return 0; -} - static int __cam_custom_stop_dev_core( struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd) { int rc = 0; uint32_t i; struct cam_custom_context *ctx_custom = - (struct cam_custom_context *) ctx->ctx_priv; - struct cam_ctx_request *req; - struct cam_custom_dev_ctx_req *req_custom; - struct cam_hw_stop_args stop; - - if (ctx_custom->hw_ctx) { + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_hw_stop_args stop; + struct cam_custom_stop_args custom_stop; + + if ((ctx->state != CAM_CTX_FLUSHED) && (ctx_custom->hw_ctx) && + (ctx->hw_mgr_intf->hw_stop)) { + custom_stop.stop_only = false; stop.ctxt_to_hw_map = ctx_custom->hw_ctx; - - stop.args = NULL; - if (ctx->hw_mgr_intf->hw_stop) - ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + stop.args = (void *) &custom_stop; + rc = ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, &stop); + if (rc) + CAM_ERR(CAM_CUSTOM, "HW stop failed rc %d", rc); } while (!list_empty(&ctx->pending_req_list)) { @@ -752,7 +831,9 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx, CAM_ERR(CAM_CUSTOM, "Recevied INIT pkt in wrong state"); } } else { - if (ctx->state >= CAM_CTX_READY && ctx->ctx_crm_intf->add_req) { + if ((ctx->state != CAM_CTX_FLUSHED) && + (ctx->state >= CAM_CTX_READY) && + (ctx->ctx_crm_intf->add_req)) { add_req.link_hdl = ctx->link_hdl; add_req.dev_hdl = ctx->dev_hdl; add_req.req_id = req->request_id; @@ -796,6 +877,44 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx, } +static int __cam_custom_ctx_config_dev_in_flushed(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_start_stop_dev_cmd start_cmd; + struct cam_custom_context *custom_ctx = + (struct cam_custom_context *) ctx->ctx_priv; + + if (!custom_ctx->hw_acquired) { + CAM_ERR(CAM_CUSTOM, "HW is not acquired, reject packet"); + rc = -EINVAL; + goto end; + } + + rc = __cam_custom_ctx_config_dev(ctx, cmd); + if (rc) + goto end; + + if (!custom_ctx->init_received) { + CAM_WARN(CAM_CUSTOM, + "Received update packet in flushed state, skip start"); + goto end; + } + + start_cmd.dev_handle = cmd->dev_handle; + start_cmd.session_handle = cmd->session_handle; + rc = __cam_custom_ctx_start_dev_in_ready(ctx, &start_cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Failed to re-start HW after flush rc: %d", rc); + else + CAM_INFO(CAM_CUSTOM, + "Received init after flush. Re-start HW complete."); + +end: + return rc; +} + static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { @@ -835,32 +954,11 @@ static int __cam_custom_ctx_link_in_acquired(struct cam_context *ctx, return 0; } -static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx, - struct cam_req_mgr_core_dev_link_setup *unlink) -{ - ctx->link_hdl = -1; - ctx->ctx_crm_intf = NULL; - - return 0; -} - -static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx, - struct cam_req_mgr_device_info *dev_info) -{ - dev_info->dev_hdl = ctx->dev_hdl; - strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name)); - dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW; - dev_info->p_delay = 1; - dev_info->trigger = CAM_TRIGGER_POINT_SOF; - - return 0; -} - static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; - struct cam_hw_config_args hw_config; + struct cam_custom_start_args custom_start; struct cam_ctx_request *req; struct cam_custom_dev_ctx_req *req_custom; struct cam_custom_context *ctx_custom = @@ -889,16 +987,20 @@ static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx, goto end; } - hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx; - hw_config.request_id = req->request_id; - hw_config.hw_update_entries = req_custom->cfg; - hw_config.num_hw_update_entries = req_custom->num_cfg; - hw_config.priv = &req_custom->hw_update_data; - hw_config.init_packet = 1; + custom_start.hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx; + custom_start.hw_config.request_id = req->request_id; + custom_start.hw_config.hw_update_entries = req_custom->cfg; + custom_start.hw_config.num_hw_update_entries = req_custom->num_cfg; + custom_start.hw_config.priv = &req_custom->hw_update_data; + custom_start.hw_config.init_packet = 1; + if (ctx->state == CAM_CTX_FLUSHED) + custom_start.start_only = true; + else + custom_start.start_only = false; ctx->state = CAM_CTX_ACTIVATED; rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, - &hw_config); + &custom_start); if (rc) { /* HW failure. User need to clean up the resource */ CAM_ERR(CAM_CUSTOM, "Start HW failed"); @@ -1064,7 +1166,20 @@ static struct cam_ctx_ops .pagefault_ops = NULL, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .stop_dev = __cam_custom_stop_dev_in_activated, + .release_dev = + __cam_custom_ctx_release_dev_in_activated, + .config_dev = __cam_custom_ctx_config_dev_in_flushed, + .release_hw = + __cam_custom_ctx_release_hw_in_activated_state, + }, + .crm_ops = { + .unlink = __cam_custom_ctx_unlink_in_ready, + }, + .irq_ops = NULL, + }, /* Activated */ { .ioctl_ops = { diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c index f2e5a1ff3407..2fed429ad13a 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include @@ -220,6 +220,7 @@ static int cam_custom_hw_mgr_stop_hw_res( static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) { int rc = 0; + struct cam_custom_stop_args *custom_args; struct cam_hw_stop_args *stop_args = stop_hw_args; struct cam_custom_hw_mgr_res *hw_mgr_res; struct cam_custom_hw_mgr_ctx *ctx; @@ -229,6 +230,7 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) return -EINVAL; } + custom_args = (struct cam_custom_stop_args *)stop_args->args; ctx = (struct cam_custom_hw_mgr_ctx *) stop_args->ctxt_to_hw_map; @@ -261,6 +263,9 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) /* stop custom hw here */ + if (custom_args->stop_only) + goto end; + /* Deinit custom cid here */ list_for_each_entry(hw_mgr_res, &ctx->res_list_custom_cid, list) { @@ -282,6 +287,7 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) /* deinit custom rsrc */ +end: return rc; } @@ -357,13 +363,19 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, struct cam_hw_stop_args stop_args; struct cam_custom_hw_mgr_res *hw_mgr_res; struct cam_custom_hw_mgr_ctx *ctx; + struct cam_custom_stop_args custom_stop_args; + struct cam_custom_start_args *custom_args; if (!hw_mgr_priv || !start_hw_args) { CAM_ERR(CAM_CUSTOM, "Invalid arguments"); return -EINVAL; } - hw_config = (struct cam_hw_config_args *)start_hw_args; + custom_args = + (struct cam_custom_start_args *)start_hw_args; + + hw_config = (struct cam_hw_config_args *) + &custom_args->hw_config; ctx = (struct cam_custom_hw_mgr_ctx *) hw_config->ctxt_to_hw_map; @@ -375,6 +387,9 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, CAM_DBG(CAM_CUSTOM, "Enter... ctx id:%d", ctx->ctx_index); + if (custom_args->start_only) + goto start_only; + /* Init custom cid */ list_for_each_entry(hw_mgr_res, &ctx->res_list_custom_cid, list) { @@ -402,6 +417,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, /* Apply init config */ +start_only: + /* Start custom HW first */ if (rc < 0) goto err; @@ -432,6 +449,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv, return 0; err: + custom_stop_args.stop_only = false; + stop_args.args = (void *) &custom_stop_args; stop_args.ctxt_to_hw_map = hw_config->ctxt_to_hw_map; cam_custom_mgr_stop_hw(hw_mgr_priv, &stop_args); deinit_hw: @@ -1113,6 +1132,81 @@ static int cam_custom_mgr_prepare_hw_update(void *hw_mgr_priv, return 0; } +static int cam_custom_hw_mgr_reset_csid_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_csid_reset_cfg_args csid_reset_args; + struct cam_isp_resource_node *custom_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + custom_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!custom_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + csid_reset_args.reset_type = CAM_IFE_CSID_RESET_PATH; + csid_reset_args.node_res = custom_rsrc_node; + hw_intf = custom_rsrc_node->hw_intf; + if (hw_intf->hw_ops.reset) { + CAM_DBG(CAM_CUSTOM, "RESET HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.reset(hw_intf->hw_priv, + &csid_reset_args, + sizeof(struct cam_csid_reset_cfg_args)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_ERR(CAM_CUSTOM, + "RESET HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_hw_mgr_reset( + void *hw_mgr_priv, void *hw_reset_args) +{ + struct cam_hw_reset_args *reset_args = + hw_reset_args; + struct cam_custom_hw_mgr_ctx *ctx; + struct cam_custom_hw_mgr_res *hw_mgr_res; + int rc = 0; + + if (!hw_mgr_priv || !hw_reset_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_custom_hw_mgr_ctx *) + reset_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, "Reset SBI CSID and SBI core"); + list_for_each_entry(hw_mgr_res, &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, + "Failed to reset CSID:%d rc: %d", + hw_mgr_res->res_id, rc); + goto end; + } + } + + /* Reset SBI HW */ + +end: + return rc; +} + static int cam_custom_mgr_config_hw(void *hw_mgr_priv, void *hw_config_args) { @@ -1279,6 +1373,7 @@ int cam_custom_hw_mgr_init(struct device_node *of_node, hw_mgr_intf->hw_release = cam_custom_mgr_release_hw; hw_mgr_intf->hw_prepare_update = cam_custom_mgr_prepare_hw_update; hw_mgr_intf->hw_config = cam_custom_mgr_config_hw; + hw_mgr_intf->hw_reset = cam_custom_hw_mgr_reset; if (iommu_hdl) *iommu_hdl = g_custom_hw_mgr.img_iommu_hdl; -- GitLab From 593ff340c9f8f14621e6aed23e0901a889c57c83 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 22 Jan 2020 15:47:27 -0800 Subject: [PATCH 225/410] msm: camera: ife: Remove reset type override This change removes the VFE reset type override that was introduced to a hardware limitation that has since been rectified. CRs-Fixed: 2590331 Change-Id: I2232ab69a9c66e9e14dd849755d8b4eba63fe136 Signed-off-by: Venkat Chinta --- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index 15d9b0e1a8cd..dc15cab5e2f4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -12,10 +12,10 @@ #include "cam_debug_util.h" #include "cam_vfe_soc.h" -#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00000007 -#define CAM_VFE_HW_RESET_HW_VAL 0x007F0000 +#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00000001 +#define CAM_VFE_HW_RESET_HW_VAL 0x00010000 #define CAM_VFE_LITE_HW_RESET_AND_REG_VAL 0x00000002 -#define CAM_VFE_LITE_HW_RESET_HW_VAL 0x0000003D +#define CAM_VFE_LITE_HW_RESET_HW_VAL 0x00000001 struct cam_vfe_top_ver3_common_data { struct cam_hw_soc_info *soc_info; @@ -281,11 +281,6 @@ int cam_vfe_top_ver3_reset(void *device_priv, reset_reg_val = CAM_VFE_LITE_HW_RESET_HW_VAL; break; } - /* override due to hw limitation */ - if (!soc_private->is_ife_lite) - reset_reg_val = CAM_VFE_HW_RESET_HW_AND_REG_VAL; - else - reset_reg_val = CAM_VFE_LITE_HW_RESET_AND_REG_VAL; CAM_DBG(CAM_ISP, "reset reg value: 0x%x", reset_reg_val); -- GitLab From 205af5a189b9c16d6f4fa823d8ac7f7914ca05ca Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 11 Dec 2019 13:12:58 -0800 Subject: [PATCH 226/410] msm: camera: ife: Stop hardware in error This change adds logic to stop IFE hardware in case of hardware errors. CRs-Fixed: 2590331 Change-Id: I86773cc44ce890cea47f19f0482761e686b0cd00 Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 23 +++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 89e8a556a357..347af7ab4c0b 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6467,6 +6467,9 @@ static int cam_ife_mgr_process_recovery_cb(void *priv, void *data) } } + if (!g_ife_hw_mgr.debug_cfg.enable_recovery) + break; + CAM_DBG(CAM_ISP, "RESET: CSID PATH"); for (i = 0; i < recovery_data->no_of_context; i++) { ctx = recovery_data->affected_ctx[i]; @@ -6695,22 +6698,12 @@ static int cam_ife_hw_mgr_handle_hw_err( rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); - if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) - return rc; - - if (g_ife_hw_mgr.debug_cfg.enable_recovery) { - CAM_DBG(CAM_ISP, "IFE Mgr recovery is enabled"); + if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) + recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else + recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; - /* Trigger for recovery */ - if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) - recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; - else - recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; - cam_ife_hw_mgr_do_error_recovery(&recovery_data); - } else { - CAM_DBG(CAM_ISP, "recovery is not enabled"); - rc = 0; - } + cam_ife_hw_mgr_do_error_recovery(&recovery_data); return rc; } -- GitLab From c5247f620ea865b2dfb718b98fbca0fa82eeca5d Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Thu, 2 Jan 2020 12:30:45 +0530 Subject: [PATCH 227/410] msm: camera: isp: Register dump for first request id First request id not getting dump if early pcr is on. If early pcr is on need to store the parsed register dump descriptor for first request id which comes as init packet. CRs-Fixed: 2595702 Change-Id: Icbf94d65b5c35cdf47044d770c7db7093001d506 Signed-off-by: Ravikishore Pampana --- drivers/cam_isp/cam_isp_context.c | 13 +++++++++++++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 18 ++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index af2ccee2a164..de844a9ae7fe 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -424,6 +424,8 @@ static int __cam_isp_ctx_enqueue_init_request( struct cam_isp_ctx_req *req_isp_old; struct cam_isp_ctx_req *req_isp_new; struct cam_isp_prepare_hw_update_data *hw_update_data; + struct cam_isp_prepare_hw_update_data *req_update_old; + struct cam_isp_prepare_hw_update_data *req_update_new; spin_lock_bh(&ctx->lock); if (list_empty(&ctx->pending_req_list)) { @@ -482,6 +484,17 @@ static int __cam_isp_ctx_enqueue_init_request( req_isp_old->hw_update_data.frame_header_cpu_addr = hw_update_data->frame_header_cpu_addr; + if (req_isp_new->hw_update_data.num_reg_dump_buf) { + req_update_new = &req_isp_new->hw_update_data; + req_update_old = &req_isp_old->hw_update_data; + memcpy(&req_update_old->reg_dump_buf_desc, + &req_update_new->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + req_update_new->num_reg_dump_buf); + req_update_old->num_reg_dump_buf = + req_update_new->num_reg_dump_buf; + } + req_old->request_id = req->request_id; list_add_tail(&req->list, &ctx->free_req_list); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 347af7ab4c0b..66b224585438 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2928,6 +2928,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_args->custom_enabled = ife_ctx->custom_enabled; acquire_args->use_frame_header_ts = ife_ctx->use_frame_header_ts; ife_ctx->ctx_in_use = 1; + ife_ctx->num_reg_dump_buf = 0; acquire_args->valid_acquired_hw = acquire_hw_info->num_inputs; @@ -3172,6 +3173,7 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) acquire_args->ctxt_to_hw_map = ife_ctx; ife_ctx->ctx_in_use = 1; + ife_ctx->num_reg_dump_buf = 0; CAM_INFO(CAM_ISP, "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", @@ -4334,6 +4336,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->cdm_ops = NULL; ctx->custom_enabled = false; ctx->use_frame_header_ts = false; + ctx->num_reg_dump_buf = 0; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; @@ -5907,13 +5910,24 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, if (((prepare->packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_INIT_DEV) { prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV; - if ((prepare->num_reg_dump_buf) && (prepare->num_reg_dump_buf < - CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + + if ((!prepare->num_reg_dump_buf) || (prepare->num_reg_dump_buf > + CAM_REG_DUMP_MAX_BUF_ENTRIES)) + goto end; + + if (!ctx->num_reg_dump_buf) { ctx->num_reg_dump_buf = prepare->num_reg_dump_buf; memcpy(ctx->reg_dump_buf_desc, prepare->reg_dump_buf_desc, sizeof(struct cam_cmd_buf_desc) * prepare->num_reg_dump_buf); + } else { + prepare_hw_data->num_reg_dump_buf = + prepare->num_reg_dump_buf; + memcpy(prepare_hw_data->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare_hw_data->num_reg_dump_buf); } goto end; -- GitLab From 2ee39250479558a2f141813c82b2c76d83b1aaab Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 11 Oct 2019 15:39:42 -0700 Subject: [PATCH 228/410] msm: camera: reqmgr: Reduce delay by one frame during bubble recovery The EPOCH at which bubble is detected no setting is applied to any device. This change will trigger applying the bubbled setting to the device with highest pipeline delay. CRs-Fixed: 2564669 Change-Id: I180b4a1d2d29267f330546b8860a099baf1688e9 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/cam_isp_context.c | 15 +++++++++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 30 +++++++++++++++++++++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 6 +++++ 3 files changed, 51 insertions(+) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index de844a9ae7fe..5c99fdc61c6d 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1414,6 +1414,11 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + notify.trigger = 0; + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.frame_id = ctx_isp->frame_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; CAM_WARN(CAM_ISP, "Notify CRM about Bubble req %lld frame %lld, ctx %u", req->request_id, ctx_isp->frame_id, ctx->ctx_id); @@ -1590,6 +1595,11 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + notify.trigger = 0; + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.frame_id = ctx_isp->frame_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; CAM_WARN(CAM_REQ, "Notify CRM about Bubble req_id %llu frame %lld, ctx %u", req->request_id, ctx_isp->frame_id, ctx->ctx_id); @@ -3159,6 +3169,11 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; + notify.trigger = 0; + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.frame_id = ctx_isp->frame_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; CAM_WARN(CAM_ISP, "Notify CRM about Bubble req %lld frame %lld ctx %u", req->request_id, diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 1a3d1901f05e..b5f10a232b89 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2342,6 +2342,35 @@ int cam_req_mgr_process_add_req(void *priv, void *data) return rc; } +/** + * __cam_req_mgr_apply_on_bubble() + * + * @brief : This API tries to apply settings to the device + * with highest pd on the bubbled frame + * @link : link information. + * @err_info : contains information about frame_id, trigger etc. + * + */ +void __cam_req_mgr_apply_on_bubble( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_error_notify *err_info) +{ + int rc = 0; + struct cam_req_mgr_trigger_notify trigger_data; + + trigger_data.dev_hdl = err_info->dev_hdl; + trigger_data.frame_id = err_info->frame_id; + trigger_data.link_hdl = err_info->link_hdl; + trigger_data.sof_timestamp_val = + err_info->sof_timestamp_val; + trigger_data.trigger = err_info->trigger; + + rc = __cam_req_mgr_process_req(link, &trigger_data); + if (rc) + CAM_ERR(CAM_CRM, + "Failed to apply request on bubbled frame"); +} + /** * cam_req_mgr_process_error() * @@ -2432,6 +2461,7 @@ int cam_req_mgr_process_error(void *priv, void *data) link->state = CAM_CRM_LINK_STATE_ERR; spin_unlock_bh(&link->link_state_spin_lock); link->open_req_cnt++; + __cam_req_mgr_apply_on_bubble(link, err_info); } } mutex_unlock(&link->req.lock); diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index de3a4606be1d..7c184d675c6f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -239,12 +239,18 @@ struct cam_req_mgr_timer_notify { * @link_hdl : link identifier * @dev_hdl : device handle which has sent this req id * @req_id : req id which hit error + * @frame_id : frame id for internal tracking + * @trigger : trigger point of this notification, CRM will send apply + * @sof_timestamp_val : Captured time stamp value at sof hw event * @error : what error device hit while processing this req */ struct cam_req_mgr_error_notify { int32_t link_hdl; int32_t dev_hdl; uint64_t req_id; + int64_t frame_id; + uint32_t trigger; + uint64_t sof_timestamp_val; enum cam_req_mgr_device_error error; }; -- GitLab From 233d02302b8fa0d2d117f5c3efc065128dbcd36d Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 7 Jan 2020 16:06:46 +0530 Subject: [PATCH 229/410] msm: camera: fd: skip halt and reset for session start Halt and reset can be applied only at probe time and flush time to clean up the MSF interface. CRs-Fixed: 2593760 Change-Id: I8a19a5a5f4a3b25ef5fe9c18a1e754529418c53c Signed-off-by: Tejas Prajapati --- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 10 ++++++++++ drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 10 ++++++---- drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h | 4 +++- drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c | 3 ++- drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 2 ++ drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h | 3 ++- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index cfbb8840eb63..a293770542ec 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1244,6 +1244,8 @@ static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) struct cam_fd_hw_mgr_ctx *hw_ctx; struct cam_fd_device *hw_device; struct cam_fd_hw_init_args hw_init_args; + struct cam_hw_info *fd_hw; + struct cam_fd_core *fd_core; if (!hw_mgr_priv || !hw_mgr_start_args) { CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", @@ -1266,9 +1268,17 @@ static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) return rc; } + fd_hw = (struct cam_hw_info *)hw_device->hw_intf->hw_priv; + fd_core = (struct cam_fd_core *)fd_hw->core_info; + if (hw_device->hw_intf->hw_ops.init) { hw_init_args.hw_ctx = hw_ctx; hw_init_args.ctx_hw_private = hw_ctx->ctx_hw_private; + if (fd_core->hw_static_info->enable_errata_wa.skip_reset) + hw_init_args.reset_required = false; + else + hw_init_args.reset_required = true; + rc = hw_device->hw_intf->hw_ops.init( hw_device->hw_intf->hw_priv, &hw_init_args, sizeof(hw_init_args)); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index 28628f93ff66..38283ec67bb5 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -747,10 +747,12 @@ int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size) fd_core->core_state = CAM_FD_CORE_STATE_IDLE; spin_unlock_irqrestore(&fd_core->spin_lock, flags); - rc = cam_fd_hw_reset(hw_priv, NULL, 0); - if (rc) { - CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc); - goto disable_soc; + if (init_args->reset_required) { + rc = cam_fd_hw_reset(hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc); + goto disable_soc; + } } cam_fd_hw_util_enable_power_on_settings(fd_hw); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h index 1f8815e72f20..22bcdf6fc733 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_CORE_H_ @@ -135,11 +135,13 @@ struct cam_fd_wrapper_regs { * @ro_mode_enable_always : Whether to enable ro mode always * @ro_mode_results_invalid : Whether results written directly into output * memory by HW are valid or not + * @skip_reset : Whether to skip reset during init */ struct cam_fd_hw_errata_wa { bool single_irq_only; bool ro_mode_enable_always; bool ro_mode_results_invalid; + bool skip_reset; }; /** diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index 3498e6235279..7a42379512be 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -110,6 +110,7 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) memset(&init_args, 0x0, sizeof(init_args)); memset(&deinit_args, 0x0, sizeof(deinit_args)); + init_args.reset_required = true; rc = cam_fd_hw_init(fd_hw, &init_args, sizeof(init_args)); if (rc) { CAM_ERR(CAM_FD, "Failed to hw init, rc=%d", rc); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h index 11ef1b913f91..85ec6fa390ff 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -162,10 +162,12 @@ struct cam_fd_hw_release_args { * * @hw_ctx : HW context for which init is requested * @ctx_hw_private : HW layer's private information specific to this hw context + * @reset_required : Indicates if the reset is required during init or not */ struct cam_fd_hw_init_args { void *hw_ctx; void *ctx_hw_private; + bool reset_required; }; /** diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h index f3eedeb3b811..d8b78d6e4414 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FD_HW_V501_H_ @@ -50,6 +50,7 @@ static struct cam_fd_hw_static_info cam_fd_wrapper200_core501_info = { .single_irq_only = true, .ro_mode_enable_always = true, .ro_mode_results_invalid = true, + .skip_reset = true, }, .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | -- GitLab From f20a80874847e7377a064bff47ab15811a370931 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 15 Jan 2020 18:29:00 -0800 Subject: [PATCH 230/410] msm: camera: ife: Improve logs This change adds more information to existing acquire and hfr update logs. CRs-Fixed: 2606911 Change-Id: I1ff4e1cbdd52be6b5c434438772084c4fdb2e80e Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 93 +++++++++++++------ .../hw_utils/cam_isp_packet_parser.c | 4 +- 2 files changed, 65 insertions(+), 32 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 66b224585438..105e96bd4f32 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -657,25 +657,50 @@ static const char *cam_ife_hw_mgr_get_src_res_id( } } -static void cam_ife_hw_mgr_dump_src_acq_info( - struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx, - uint32_t num_pix_port, uint32_t num_rdi_port) +static void cam_ife_hw_mgr_print_acquire_info( + struct cam_ife_hw_mgr_ctx *hw_mgr_ctx, uint32_t num_pix_port, + uint32_t num_pd_port, uint32_t num_rdi_port, int acquire_failed) { struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; struct cam_isp_resource_node *hw_res = NULL; + int hw_idx[CAM_ISP_HW_SPLIT_MAX] = {-1, -1}; int i = 0; + hw_mgr_res = list_first_entry(&hw_mgr_ctx->res_list_ife_csid, + struct cam_ife_hw_mgr_res, list); + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + hw_idx[i] = hw_res->hw_intf->hw_idx; + } + + if (acquire_failed) + goto fail; + CAM_INFO(CAM_ISP, - "Acquired HW for ctx: %u with pix_port: %u rdi_port: %u", - hwr_mgr_ctx->ctx_index, num_pix_port, num_rdi_port); + "Acquired %s IFE[%d %d] with [%u pix] [%u pd] [%u rdi] ports for ctx:%u", + (hw_mgr_ctx->is_dual) ? "dual" : "single", + hw_idx[CAM_ISP_HW_SPLIT_LEFT], hw_idx[CAM_ISP_HW_SPLIT_RIGHT], + num_pix_port, num_pd_port, num_rdi_port, hw_mgr_ctx->ctx_index); + + return; + +fail: + CAM_ERR(CAM_ISP, "Acquire HW failed for ctx:%u", hw_mgr_ctx->ctx_index); + CAM_INFO(CAM_ISP, + "Previously acquired %s IFE[%d %d] with [%u pix] [%u pd] [%u rdi] ports for ctx:%u", + (hw_mgr_ctx->is_dual) ? "dual" : "single", + hw_idx[CAM_ISP_HW_SPLIT_LEFT], hw_idx[CAM_ISP_HW_SPLIT_RIGHT], + num_pix_port, num_pd_port, num_rdi_port, hw_mgr_ctx->ctx_index); + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, - &hwr_mgr_ctx->res_list_ife_src, list) { + &hw_mgr_ctx->res_list_ife_src, list) { for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { hw_res = hw_mgr_res->hw_res[i]; if (hw_res && hw_res->hw_intf) CAM_INFO(CAM_ISP, - "IFE src split_id: %d res_id: %s hw_idx: %u state: %s", + "IFE src split_id:%d res_id:%s hw_idx:%u state:%s", i, cam_ife_hw_mgr_get_src_res_id( hw_res->res_id), @@ -2423,8 +2448,9 @@ static int cam_ife_mgr_acquire_hw_for_fe_ctx( static int cam_ife_mgr_acquire_hw_for_ctx( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_generic_info *in_port, - uint32_t *num_pix_port, uint32_t *num_rdi_port, - uint32_t *acquired_hw_id, uint32_t *acquired_hw_path) + uint32_t *num_pix_port, uint32_t *num_rdi_port, + uint32_t *num_pd_port, uint32_t *acquired_hw_id, + uint32_t *acquired_hw_path) { int rc = -1; int is_dual_vfe = 0; @@ -2528,7 +2554,8 @@ static int cam_ife_mgr_acquire_hw_for_ctx( goto err; } - *num_pix_port = ipp_count + ppp_count + ife_rd_count + lcr_count; + *num_pix_port = ipp_count + ife_rd_count + lcr_count; + *num_pd_port = ppp_count; *num_rdi_port = rdi_count; return 0; @@ -2806,8 +2833,10 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) struct cam_cdm_acquire_data cdm_acquire; uint32_t num_pix_port_per_in = 0; uint32_t num_rdi_port_per_in = 0; + uint32_t num_pd_port_per_in = 0; uint32_t total_pix_port = 0; uint32_t total_rdi_port = 0; + uint32_t total_pd_port = 0; struct cam_isp_acquire_hw_info *acquire_hw_info = NULL; uint32_t input_size = 0; @@ -2893,16 +2922,18 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) else rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, &num_pix_port_per_in, &num_rdi_port_per_in, + &num_pd_port_per_in, &acquire_args->acquired_hw_id[i], acquire_args->acquired_hw_path[i]); total_pix_port += num_pix_port_per_in; total_rdi_port += num_rdi_port_per_in; + total_pd_port += num_pd_port_per_in; if (rc) { - CAM_ERR(CAM_ISP, "can not acquire resource"); - cam_ife_hw_mgr_dump_src_acq_info(ife_ctx, - total_pix_port, total_rdi_port); + cam_ife_hw_mgr_print_acquire_info(ife_ctx, + total_pix_port, total_pd_port, + total_rdi_port, rc); goto free_mem; } @@ -2912,7 +2943,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } /* Check whether context has only RDI resource */ - if (!total_pix_port) { + if (!total_pix_port && !total_pd_port) { ife_ctx->is_rdi_only_context = 1; CAM_DBG(CAM_ISP, "RDI only context"); } @@ -2934,10 +2965,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_hw_info->num_inputs; getnstimeofday64(&ife_ctx->ts); - CAM_INFO(CAM_ISP, - "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", - total_pix_port, total_rdi_port, - ife_ctx->is_dual, ife_ctx->ctx_index); + cam_ife_hw_mgr_print_acquire_info(ife_ctx, total_pix_port, + total_pd_port, total_rdi_port, rc); cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); @@ -3013,6 +3042,8 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) struct cam_isp_in_port_generic_info *gen_port_info = NULL; uint32_t num_pix_port_per_in = 0; uint32_t num_rdi_port_per_in = 0; + uint32_t num_pd_port_per_in = 0; + uint32_t total_pd_port = 0; uint32_t total_pix_port = 0; uint32_t total_rdi_port = 0; uint32_t in_port_length = 0; @@ -3132,12 +3163,13 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, gen_port_info, &num_pix_port_per_in, - &num_rdi_port_per_in, + &num_rdi_port_per_in, &num_pd_port_per_in, &acquire_args->acquired_hw_id[i], acquire_args->acquired_hw_path[i]); total_pix_port += num_pix_port_per_in; total_rdi_port += num_rdi_port_per_in; + total_pd_port += num_pd_port_per_in; kfree(in_port); if (gen_port_info != NULL) { @@ -3146,7 +3178,9 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) gen_port_info = NULL; } if (rc) { - CAM_ERR(CAM_ISP, "can not acquire resource"); + cam_ife_hw_mgr_print_acquire_info(ife_ctx, + total_pix_port, total_pd_port, + total_rdi_port, rc); goto free_res; } } else { @@ -3175,10 +3209,8 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) ife_ctx->ctx_in_use = 1; ife_ctx->num_reg_dump_buf = 0; - CAM_INFO(CAM_ISP, - "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", - total_pix_port, total_rdi_port, - ife_ctx->is_dual, ife_ctx->ctx_index); + cam_ife_hw_mgr_print_acquire_info(ife_ctx, total_pix_port, + total_pd_port, total_rdi_port, rc); cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); @@ -4511,10 +4543,10 @@ static int cam_isp_blob_ubwc_update( &bytes_used); if (rc < 0) { CAM_ERR(CAM_ISP, - "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", + "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%X", blob_info->base_info->idx, bytes_used, - res_id_out); + ubwc_plane_cfg->port_type); goto end; } @@ -4684,10 +4716,10 @@ static int cam_isp_blob_ubwc_update_v2( &bytes_used); if (rc < 0) { CAM_ERR(CAM_ISP, - "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", + "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%X", blob_info->base_info->idx, bytes_used, - res_id_out); + ubwc_plane_cfg->port_type); goto end; } @@ -4785,8 +4817,9 @@ static int cam_isp_blob_hfr_update( &bytes_used); if (rc < 0) { CAM_ERR(CAM_ISP, - "Failed cmd_update, base_idx=%d, rc=%d", - blob_info->base_info->idx, bytes_used); + "Failed cmd_update, base_idx=%d, rc=%d, res_id_out:0x%X", + blob_info->base_info->idx, bytes_used, + port_hfr_config->resource_type); return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 6d633f3e23bc..e1e15dbb76d1 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -196,8 +196,8 @@ int cam_isp_add_cmd_buf_update( uint32_t total_used_bytes = 0; if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) { - CAM_ERR(CAM_ISP, "io res id:%d not valid", - hw_mgr_res->res_type); + CAM_ERR(CAM_ISP, "VFE out resource:0x%X type:%d not valid", + hw_mgr_res->res_id, hw_mgr_res->res_type); return -EINVAL; } -- GitLab From eabdd6c9c47a2bd91773e07fb3385205f941bd08 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Mon, 20 Jan 2020 14:37:51 -0800 Subject: [PATCH 231/410] msm: camera: isp: Config hardware in work queue Currently requests for offline IFE are applied from tasklet context or from an ioctl thread within a critical section protected by a spinlock. In both of these cases, preemtion is disabled but CDM requires mutex locks during this operation. Therefore a work queue is added in this change to handle apply request for offline IFE. CRs-Fixed: 2606911 Change-Id: Ie893a626bc274d026fb878f1f19830e990be6dc6 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 68 +++++++++++++++++---- drivers/cam_isp/cam_isp_context.h | 4 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 29 ++++++--- 3 files changed, 77 insertions(+), 24 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 5c99fdc61c6d..3203dd86f2c4 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -979,13 +979,21 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( } static int __cam_isp_ctx_apply_req_offline( - struct cam_context *ctx, uint32_t next_state, - struct cam_isp_context *ctx_isp) + void *priv, void *data) { int rc = 0; - struct cam_ctx_request *req; - struct cam_isp_ctx_req *req_isp; - struct cam_hw_config_args cfg; + struct cam_context *ctx = NULL; + struct cam_isp_context *ctx_isp = priv; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_hw_config_args cfg; + + if (!ctx_isp) { + CAM_ERR(CAM_ISP, "Invalid ctx_isp:%pK", ctx); + rc = -EINVAL; + goto end; + } + ctx = ctx_isp->base; if (list_empty(&ctx->pending_req_list)) { CAM_DBG(CAM_ISP, "No pending requests to apply"); @@ -999,8 +1007,10 @@ static int __cam_isp_ctx_apply_req_offline( if (ctx_isp->active_req_cnt >= 2) goto end; + spin_lock_bh(&ctx->lock); req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); + spin_unlock_bh(&ctx->lock); CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u", req->request_id, ctx_isp->substate_activated, ctx->ctx_id); @@ -1019,13 +1029,21 @@ static int __cam_isp_ctx_apply_req_offline( if (rc) { CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration"); } else { + spin_lock_bh(&ctx->lock); + atomic_set(&ctx_isp->rxd_epoch, 0); - ctx_isp->substate_activated = next_state; + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_APPLIED; ctx_isp->last_applied_req_id = req->request_id; + list_del_init(&req->list); list_add_tail(&req->list, &ctx->wait_req_list); + + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "New substate state %d, applied req %lld", - next_state, ctx_isp->last_applied_req_id); + CAM_ISP_CTX_ACTIVATED_APPLIED, + ctx_isp->last_applied_req_id); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, @@ -1035,6 +1053,26 @@ static int __cam_isp_ctx_apply_req_offline( return rc; } +static int __cam_isp_ctx_schedule_apply_req_offline( + struct cam_isp_context *ctx_isp) +{ + int rc = 0; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(ctx_isp->workq); + if (!task) { + CAM_ERR(CAM_ISP, "No task for worker"); + return -ENOMEM; + } + + task->process_cb = __cam_isp_ctx_apply_req_offline; + rc = cam_req_mgr_workq_enqueue_task(task, ctx_isp, CRM_TASK_PRIORITY_0); + if (rc) + CAM_ERR(CAM_ISP, "Failed to schedule task rc:%d", rc); + + return rc; +} + static int __cam_isp_ctx_offline_epoch_in_activated_state( struct cam_isp_context *ctx_isp, void *evt_data) { @@ -1055,8 +1093,7 @@ static int __cam_isp_ctx_offline_epoch_in_activated_state( } } - __cam_isp_ctx_apply_req_offline(ctx, CAM_ISP_CTX_ACTIVATED_APPLIED, - ctx_isp); + __cam_isp_ctx_schedule_apply_req_offline(ctx_isp); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); @@ -3818,10 +3855,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( req->request_id, ctx->ctx_id); if (ctx_isp->offline_context && atomic_read(&ctx_isp->rxd_epoch)) { - spin_lock_bh(&ctx->lock); - __cam_isp_ctx_apply_req_offline(ctx, - CAM_ISP_CTX_ACTIVATED_APPLIED, ctx_isp); - spin_unlock_bh(&ctx->lock); + __cam_isp_ctx_schedule_apply_req_offline(ctx_isp); } return rc; @@ -4267,6 +4301,13 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, cam_isp_ctx_offline_state_machine_irq; ctx_isp->substate_machine = NULL; ctx_isp->offline_context = true; + + rc = cam_req_mgr_workq_create("offline_ife", 20, + &ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to create workq for offline IFE rc:%d", + rc); } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -5180,6 +5221,7 @@ int cam_isp_context_init(struct cam_isp_context *ctx, atomic64_set(&ctx->event_record_head[i], -1); cam_isp_context_debug_register(); + err: return rc; } diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index d5e2f1bac0e3..89b203d1fde9 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -13,7 +13,7 @@ #include "cam_context.h" #include "cam_isp_hw_mgr_intf.h" - +#include "cam_req_mgr_workq.h" #define CAM_IFE_QTIMER_MUL_FACTOR 10000 #define CAM_IFE_QTIMER_DIV_FACTOR 192 @@ -254,6 +254,7 @@ struct cam_isp_context_event_record { * @init_timestamp: Timestamp at which this context is initialized * @rxd_epoch: Indicate whether epoch has been received. Used to * decide whether to apply request in offline ctx + * @workq: Worker thread for offline ife * */ struct cam_isp_context { @@ -294,6 +295,7 @@ struct cam_isp_context { bool use_frame_header_ts; unsigned int init_timestamp; atomic_t rxd_epoch; + struct cam_req_mgr_core_workq *workq; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 105e96bd4f32..20b08740d2ec 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -669,6 +669,11 @@ static void cam_ife_hw_mgr_print_acquire_info( hw_mgr_res = list_first_entry(&hw_mgr_ctx->res_list_ife_csid, struct cam_ife_hw_mgr_res, list); + + if (hw_mgr_ctx->is_offline) + hw_mgr_res = list_first_entry(&hw_mgr_ctx->res_list_ife_src, + struct cam_ife_hw_mgr_res, list); + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { hw_res = hw_mgr_res->hw_res[i]; if (hw_res && hw_res->hw_intf) @@ -2158,7 +2163,7 @@ static int cam_ife_hw_mgr_preprocess_port( return 0; } -static int cam_ife_hw_mgr_acquire_offline_res_ife_bus_rd( +static int cam_ife_hw_mgr_acquire_res_ife_bus_rd( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_generic_info *in_port) { @@ -2373,7 +2378,7 @@ static int cam_ife_hw_mgr_acquire_offline_res_ife_camif( return rc; } -static int cam_ife_mgr_acquire_hw_for_fe_ctx( +static int cam_ife_mgr_acquire_hw_for_offline_ctx( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_generic_info *in_port, uint32_t *num_pix_port, @@ -2405,7 +2410,7 @@ static int cam_ife_mgr_acquire_hw_for_fe_ctx( return -EINVAL; } - rc = cam_ife_hw_mgr_acquire_offline_res_ife_bus_rd(ife_ctx, in_port); + rc = cam_ife_hw_mgr_acquire_res_ife_bus_rd(ife_ctx, in_port); if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE BUS RD resource Failed"); @@ -2473,17 +2478,21 @@ static int cam_ife_mgr_acquire_hw_for_ctx( cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count, &rdi_count, &ppp_count, &ife_rd_count, &lcr_count); - if (ife_rd_count) { - CAM_ERR(CAM_ISP, "Invalid BUS RD port for non-FE ctx"); - return -EINVAL; - } - if (!ipp_count && !rdi_count && !ppp_count && !lcr_count) { CAM_ERR(CAM_ISP, "No PIX or RDI or PPP or LCR resource"); return -EINVAL; } + if (ife_rd_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_bus_rd(ife_ctx, in_port); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE BUS RD resource Failed"); + goto err; + } + } + if (ipp_count || lcr_count) { /* get ife csid IPP resource */ rc = cam_ife_hw_mgr_acquire_res_ife_csid_pxl(ife_ctx, @@ -2913,8 +2922,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) ife_ctx->use_frame_header_ts = true; } - if (ife_ctx->is_fe_enabled) - rc = cam_ife_mgr_acquire_hw_for_fe_ctx( + if (ife_ctx->is_offline) + rc = cam_ife_mgr_acquire_hw_for_offline_ctx( ife_ctx, in_port, &num_pix_port_per_in, &acquire_args->acquired_hw_id[i], -- GitLab From accf6177e2ba9a65996f49dfb5e2a1cfc1c7780a Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 27 Jan 2020 12:48:43 +0530 Subject: [PATCH 232/410] msm: camera: csiphy: Update csiphy power-up sequence for lito v2 Update the power-up sequence for lito v2, as per HPG revision M. CRs-Fixed: 2614237 Change-Id: I72caafdff0cfa7eb3be1d95c708c2225f45b52b1 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_soc.c | 6 ++--- .../include/cam_csiphy_1_2_2_hwreg.h | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 3c1c01337bda..c96baff8c662 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_csiphy_soc.h" @@ -321,11 +321,11 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2; csiphy_dev->ctrl_reg->csiphy_common_reg = - csiphy_common_reg_1_2; + csiphy_common_reg_1_2_2; csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_2; csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; - csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2_2; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->is_divisor_32_comp = false; csiphy_dev->hw_version = CSIPHY_VERSION_V12; diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h index dd88ba7cca38..119b6b575b60 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_2_2_HWREG_H_ @@ -8,6 +8,29 @@ #include "../cam_csiphy_dev.h" +struct csiphy_reg_parms_t csiphy_v1_2_2 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 8, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 18, + .csiphy_3ph_config_array_size = 33, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_2_2[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x088C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, +}; + struct csiphy_reg_t csiphy_2ph_v1_2_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { -- GitLab From 3d9e22bd91e638952516805a8b5cd6b1d3df4644 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Thu, 2 Jan 2020 14:19:15 +0530 Subject: [PATCH 233/410] msm: camera: isp: Change state of all CID resource to RESERVE on deinit This change is to update state of all acquired CID resources state to Reserve on disable CSI2. It will allow, proper release of all CID resources even in case multiple CID for single CSID. CRs-Fixed: 2587914 Change-Id: I9e88ef814851eb6f953a753d3806086ddf64cb38 Signed-off-by: Ayush Kumar --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 20 +++++++++++++------ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 81fdd87b8679..4013a0bebd5a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -414,7 +414,6 @@ static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, return -EINVAL; } - static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) { struct cam_hw_soc_info *soc_info; @@ -1538,8 +1537,8 @@ static int cam_ife_csid_enable_csi2( csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; - CAM_DBG(CAM_ISP, "CSID:%d count:%d config csi2 rx", - csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + CAM_DBG(CAM_ISP, "CSID:%d count:%d config csi2 rx res_id:%d", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt, res->res_id); /* overflow check before increment */ if (csid_hw->csi2_cfg_cnt == UINT_MAX) { @@ -1549,7 +1548,7 @@ static int cam_ife_csid_enable_csi2( } cid_data = (struct cam_ife_csid_cid_data *)res->res_priv; - + cid_data->init_cnt++; res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; csid_hw->csi2_cfg_cnt++; if (csid_hw->csi2_cfg_cnt > 1) @@ -1640,6 +1639,7 @@ static int cam_ife_csid_disable_csi2( { const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_cid_data *cid_data; if (res->res_id >= CAM_IFE_CSID_CID_MAX) { CAM_ERR(CAM_ISP, "CSID:%d Invalid res id :%d", @@ -1649,11 +1649,19 @@ static int cam_ife_csid_disable_csi2( csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; - CAM_DBG(CAM_ISP, "CSID:%d cnt : %d Disable csi2 rx", - csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + cid_data = (struct cam_ife_csid_cid_data *)res->res_priv; + CAM_DBG(CAM_ISP, "CSID:%d cnt : %d Disable csi2 rx res->res_id:%d", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt, res->res_id); + + if (cid_data->init_cnt) + cid_data->init_cnt--; + if (!cid_data->init_cnt) + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; if (csid_hw->csi2_cfg_cnt) csid_hw->csi2_cfg_cnt--; + CAM_DBG(CAM_ISP, "res_id %d res_state=%d", + res->res_id, res->res_state); if (csid_hw->csi2_cfg_cnt) return 0; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 71a451b89198..885cd07b6ff7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -454,6 +454,7 @@ struct cam_ife_csid_tpg_cfg { * @cnt: Cid resource reference count. * @tpg_set: Tpg used for this cid resource * @is_valid_vc1_dt1: Valid vc1 and dt1 + * @init_cnt cid resource init count * */ struct cam_ife_csid_cid_data { @@ -464,6 +465,7 @@ struct cam_ife_csid_cid_data { uint32_t cnt; uint32_t tpg_set; uint32_t is_valid_vc1_dt1; + uint32_t init_cnt; }; -- GitLab From 7f7032a632ca9610f76229adfed65f7c3e2a5525 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Tue, 4 Feb 2020 11:33:11 +0530 Subject: [PATCH 234/410] msm: camera: core: Fix context release timing issue When sync object is invalid and num_in_map > 1, it will lead to context ref leak. Check sync object first, then register sync call back. CRs-Fixed: 2594185 Change-Id: I2d39ce3ea43bbe7bc05420b86b37fdfba4aa795a Signed-off-by: Ayush Kumar --- drivers/cam_core/cam_context_utils.c | 19 +++++++++++---- drivers/cam_sync/cam_sync.c | 35 +++++++++++++++++++++++++++- drivers/cam_sync/cam_sync_api.h | 11 ++++++++- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 87abebabaf00..09f164561d69 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -451,6 +451,17 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, "[%s][%d] : Moving req[%llu] from free_list to pending_list", ctx->dev_name, ctx->ctx_id, req->request_id); + for (j = 0; j < req->num_in_map_entries; j++) { + rc = cam_sync_check_valid( + req->in_map_entries[j].sync_id); + if (rc) { + CAM_ERR(CAM_CTXT, + "invalid in map sync object %d", + req->in_map_entries[j].sync_id); + goto put_ref; + } + } + for (j = 0; j < req->num_in_map_entries; j++) { cam_context_getref(ctx); rc = cam_sync_register_callback( @@ -472,7 +483,8 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, ctx->dev_name, ctx->ctx_id, req->request_id); - goto put_ctx_ref; + cam_context_putref(ctx); + goto put_ref; } CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", req->in_map_entries[j].sync_id, rc); @@ -480,9 +492,6 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, } return rc; -put_ctx_ref: - for (; j >= 0; j--) - cam_context_putref(ctx); put_ref: for (--i; i >= 0; i--) { if (cam_sync_put_obj_ref(req->out_map_entries[i].sync_id)) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index 5f205361d1e9..dfb8ac10ee22 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -286,6 +286,7 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) int rc; long idx = 0; bool bit; + int i = 0; if (!sync_obj || !merged_obj) { CAM_ERR(CAM_SYNC, "Invalid pointer(s)"); @@ -303,6 +304,14 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) return -EINVAL; } + for (i = 0; i < num_objs; i++) { + rc = cam_sync_check_valid(sync_obj[i]); + if (rc) { + CAM_ERR(CAM_SYNC, "Sync_obj[%d] %d valid check fail", + i, sync_obj[i]); + return rc; + } + } do { idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); if (idx >= CAM_SYNC_MAX_OBJS) @@ -374,6 +383,30 @@ int cam_sync_destroy(int32_t sync_obj) return cam_sync_deinit_object(sync_dev->sync_table, sync_obj); } +int cam_sync_check_valid(int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + + if (!test_bit(sync_obj, sync_dev->bitmap)) { + CAM_ERR(CAM_SYNC, "Error: Released sync obj received %d", + sync_obj); + return -EINVAL; + } + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + return 0; +} + int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms) { unsigned long timeleft; diff --git a/drivers/cam_sync/cam_sync_api.h b/drivers/cam_sync/cam_sync_api.h index 3d99bc15eb18..3304acb50bba 100644 --- a/drivers/cam_sync/cam_sync_api.h +++ b/drivers/cam_sync/cam_sync_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef __CAM_SYNC_API_H__ @@ -140,5 +140,14 @@ int cam_sync_destroy(int32_t sync_obj); */ int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms); +/** + * @brief: Check if sync object is valid + * + * @param sync_obj: int referencing the sync object to be checked + * + * @return 0 upon success, -EINVAL if sync object is in bad state or arguments + * are invalid + */ +int cam_sync_check_valid(int32_t sync_obj); #endif /* __CAM_SYNC_API_H__ */ -- GitLab From b44fa2f932263189dac2f4597ace0c6d11c4b7e7 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Wed, 29 Jan 2020 14:10:55 -0800 Subject: [PATCH 235/410] msm: camera: smmu: Add map and unmap monitor Add map and unmap events in monitor array for each context bank and dump the last set of events whenever some smmu related issue happens. CRs-Fixed: 2538876 Change-Id: I18941e9a64ebd6828419e13471938bb32438122c Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_smmu/cam_smmu_api.c | 105 +++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 090d01dcd5d5..04184c037734 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. */ #include @@ -35,6 +35,11 @@ #define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK)) #define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK) +#define CAM_SMMU_MONITOR_MAX_ENTRIES 100 +#define CAM_SMMU_INC_MONITOR_HEAD(head, ret) \ + div_u64_rem(atomic64_add_return(1, head),\ + CAM_SMMU_MONITOR_MAX_ENTRIES, (ret)) + static int g_num_pf_handled = 4; module_param(g_num_pf_handled, int, 0644); @@ -93,6 +98,17 @@ struct secheap_buf_info { struct sg_table *table; }; +struct cam_smmu_monitor { + struct timespec64 timestamp; + bool is_map; + + /* map-unmap info */ + int ion_fd; + dma_addr_t paddr; + size_t len; + enum cam_smmu_region_id region_id; +}; + struct cam_context_bank_info { struct device *dev; struct iommu_domain *domain; @@ -140,6 +156,9 @@ struct cam_context_bank_info { /* discard iova - non-zero values are valid */ dma_addr_t discard_iova_start; size_t discard_iova_len; + + atomic64_t monitor_head; + struct cam_smmu_monitor monitor_entries[CAM_SMMU_MONITOR_MAX_ENTRIES]; }; struct cam_iommu_cb_set { @@ -262,6 +281,76 @@ static int cam_smmu_probe(struct platform_device *pdev); static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr); +static void cam_smmu_update_monitor_array( + struct cam_context_bank_info *cb_info, + bool is_map, + struct cam_dma_buff_info *mapping_info) +{ + int iterator; + + CAM_SMMU_INC_MONITOR_HEAD(&cb_info->monitor_head, &iterator); + + ktime_get_real_ts64(&cb_info->monitor_entries[iterator].timestamp); + + cb_info->monitor_entries[iterator].is_map = is_map; + cb_info->monitor_entries[iterator].ion_fd = mapping_info->ion_fd; + cb_info->monitor_entries[iterator].paddr = mapping_info->paddr; + cb_info->monitor_entries[iterator].len = mapping_info->len; + cb_info->monitor_entries[iterator].region_id = mapping_info->region_id; +} + +static void cam_smmu_dump_monitor_array( + struct cam_context_bank_info *cb_info) +{ + int i = 0; + int64_t state_head = 0; + uint32_t index, num_entries, oldest_entry; + uint64_t ms, tmp, hrs, min, sec; + struct timespec64 *ts = NULL; + + state_head = atomic64_read(&cb_info->monitor_head); + + if (state_head == -1) { + return; + } else if (state_head < CAM_SMMU_MONITOR_MAX_ENTRIES) { + num_entries = state_head; + oldest_entry = 0; + } else { + num_entries = CAM_SMMU_MONITOR_MAX_ENTRIES; + div_u64_rem(state_head + 1, + CAM_SMMU_MONITOR_MAX_ENTRIES, &oldest_entry); + } + + CAM_INFO(CAM_SMMU, + "========Dumping monitor information for cb %s===========", + cb_info->name); + + index = oldest_entry; + + for (i = 0; i < num_entries; i++) { + ts = &cb_info->monitor_entries[index].timestamp; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); + + CAM_INFO(CAM_SMMU, + "**** %llu:%llu:%llu.%llu : Index[%d] [%s] : ion_fd=%d start=0x%x end=0x%x len=%u region=%d", + hrs, min, sec, ms, + index, + cb_info->monitor_entries[index].is_map ? "MAP" : "UNMAP", + cb_info->monitor_entries[index].ion_fd, + (void *)cb_info->monitor_entries[index].paddr, + ((uint64_t)cb_info->monitor_entries[index].paddr + + (uint64_t)cb_info->monitor_entries[index].len), + (unsigned int)cb_info->monitor_entries[index].len, + cb_info->monitor_entries[index].region_id); + + index = (index + 1) % CAM_SMMU_MONITOR_MAX_ENTRIES; + } +} + static void cam_smmu_page_fault_work(struct work_struct *work) { int j; @@ -344,6 +433,8 @@ static void cam_smmu_dump_cb_info(int idx) (unsigned int)mapping->len, mapping->region_id); } + + cam_smmu_dump_monitor_array(&iommu_cb_set.cb_info[idx]); } } @@ -1895,6 +1986,9 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + cam_smmu_update_monitor_array(&iommu_cb_set.cb_info[idx], true, + mapping_info); + return 0; } @@ -1920,6 +2014,9 @@ static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list); + cam_smmu_update_monitor_array(&iommu_cb_set.cb_info[idx], true, + mapping_info); + return 0; } @@ -1944,6 +2041,9 @@ static int cam_smmu_unmap_buf_and_remove_from_list( return -EINVAL; } + cam_smmu_update_monitor_array(&iommu_cb_set.cb_info[idx], false, + mapping_info); + CAM_DBG(CAM_SMMU, "region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", mapping_info->region_id, mapping_info->paddr, mapping_info->len, @@ -2902,6 +3002,7 @@ int cam_smmu_get_iova(int handle, int ion_fd, if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); rc = -EINVAL; + cam_smmu_dump_cb_info(idx); goto get_addr_end; } @@ -3247,6 +3348,8 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, cb->is_fw_allocated = false; cb->is_secheap_allocated = false; + atomic64_set(&cb->monitor_head, -1); + /* Create a pool with 64K granularity for supporting shared memory */ if (cb->shared_support) { cb->shared_mem_pool = gen_pool_create( -- GitLab From 7960bf9d26b2fc77e8f64d54e80d95860a24c63f Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 23 Jan 2020 12:10:52 -0800 Subject: [PATCH 236/410] msm: camera: fd: Fix race condition in resetting ready_to_process Do not unlock frame_req_mutex until the request is added into processing list after submitting the frame to hw. This can cause a race condition where Flush comes before adding the frame into processing list and thinks there is no frame with HW. And there is a possibility that FrameDone IRQ thread can get the mutex and thinks no frame in processing list - causing never to reset the flag ready_to_process. This will cause all subsequent camera usage to fail as requests will never be submitted to hw. CRs-Fixed: 2600443 Change-Id: Icd12e155192fccd9adbc7b774b073ca623f1d7ba Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 84 +++++++++++++------ drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h | 3 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 2 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 2 + 4 files changed, 66 insertions(+), 25 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index a293770542ec..6a422038f5a5 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -240,6 +240,15 @@ static int cam_fd_mgr_util_release_device(struct cam_fd_hw_mgr *hw_mgr, mutex_lock(&hw_mgr->hw_mgr_mutex); hw_device->num_ctxts--; + + if (!hw_device->num_ctxts) { + mutex_lock(&hw_device->lock); + hw_device->ready_to_process = true; + hw_device->req_id = -1; + hw_device->cur_hw_ctx = NULL; + mutex_unlock(&hw_device->lock); + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); hw_ctx->device_index = -1; @@ -277,6 +286,11 @@ static int cam_fd_mgr_util_select_device(struct cam_fd_hw_mgr *hw_mgr, (!fd_acquire_args->get_raw_results || hw_device->hw_caps.raw_results_available)) { CAM_DBG(CAM_FD, "Found dedicated HW Index=%d", i); + mutex_lock(&hw_device->lock); + hw_device->ready_to_process = true; + hw_device->req_id = -1; + hw_device->cur_hw_ctx = NULL; + mutex_unlock(&hw_device->lock); hw_device->num_ctxts++; break; } @@ -294,7 +308,9 @@ static int cam_fd_mgr_util_select_device(struct cam_fd_hw_mgr *hw_mgr, (!fd_acquire_args->get_raw_results || hw_device->hw_caps.raw_results_available)) { hw_device->num_ctxts++; - CAM_DBG(CAM_FD, "Found sharing HW Index=%d", i); + CAM_DBG(CAM_FD, + "Found sharing HW Index=%d, num_ctxts=%d", + i, hw_device->num_ctxts); break; } } @@ -846,6 +862,11 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data) mutex_lock(&hw_device->lock); if (hw_device->ready_to_process == false) { + if (hw_mgr->num_pending_frames > 6) { + CAM_WARN(CAM_FD, + "Device busy for longer time with cur_hw_ctx=%pK, ReqId=%lld", + hw_device->cur_hw_ctx, hw_device->req_id); + } mutex_unlock(&hw_device->lock); mutex_unlock(&hw_mgr->frame_req_mutex); return -EBUSY; @@ -854,7 +875,9 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data) trace_cam_submit_to_hw("FD", frame_req->request_id); list_del_init(&frame_req->list); - mutex_unlock(&hw_mgr->frame_req_mutex); + hw_mgr->num_pending_frames--; + frame_req->submit_timestamp = ktime_get(); + list_add_tail(&frame_req->list, &hw_mgr->frame_processing_list); if (hw_device->hw_intf->hw_ops.start) { start_args.hw_ctx = hw_ctx; @@ -869,12 +892,16 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data) sizeof(start_args)); if (rc) { CAM_ERR(CAM_FD, "Failed in HW Start %d", rc); + list_del_init(&frame_req->list); mutex_unlock(&hw_device->lock); + mutex_unlock(&hw_mgr->frame_req_mutex); goto put_req_into_free_list; } } else { CAM_ERR(CAM_FD, "Invalid hw_ops.start"); + list_del_init(&frame_req->list); mutex_unlock(&hw_device->lock); + mutex_unlock(&hw_mgr->frame_req_mutex); rc = -EPERM; goto put_req_into_free_list; } @@ -883,30 +910,9 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data) hw_device->cur_hw_ctx = hw_ctx; hw_device->req_id = frame_req->request_id; mutex_unlock(&hw_device->lock); - frame_req->submit_timestamp = ktime_get(); - - rc = cam_fd_mgr_util_put_frame_req( - &hw_mgr->frame_processing_list, &frame_req); - if (rc) { - CAM_ERR(CAM_FD, - "Failed in putting frame req in processing list"); - goto stop_unlock; - } + mutex_unlock(&hw_mgr->frame_req_mutex); return rc; - -stop_unlock: - if (hw_device->hw_intf->hw_ops.stop) { - struct cam_fd_hw_stop_args stop_args; - - stop_args.hw_ctx = hw_ctx; - stop_args.ctx_hw_private = hw_ctx->ctx_hw_private; - stop_args.hw_req_private = &frame_req->hw_req_private; - if (hw_device->hw_intf->hw_ops.stop( - hw_device->hw_intf->hw_priv, &stop_args, - sizeof(stop_args))) - CAM_ERR(CAM_FD, "Failed in HW Stop %d", rc); - } put_req_into_free_list: cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, &frame_req); @@ -1274,11 +1280,11 @@ static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) if (hw_device->hw_intf->hw_ops.init) { hw_init_args.hw_ctx = hw_ctx; hw_init_args.ctx_hw_private = hw_ctx->ctx_hw_private; + hw_init_args.is_hw_reset = false; if (fd_core->hw_static_info->enable_errata_wa.skip_reset) hw_init_args.reset_required = false; else hw_init_args.reset_required = true; - rc = hw_device->hw_intf->hw_ops.init( hw_device->hw_intf->hw_priv, &hw_init_args, sizeof(hw_init_args)); @@ -1286,6 +1292,14 @@ static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) CAM_ERR(CAM_FD, "Failed in HW Init %d", rc); return rc; } + + if (hw_init_args.is_hw_reset) { + mutex_lock(&hw_device->lock); + hw_device->ready_to_process = true; + hw_device->req_id = -1; + hw_device->cur_hw_ctx = NULL; + mutex_unlock(&hw_device->lock); + } } else { CAM_ERR(CAM_FD, "Invalid init function"); return -EINVAL; @@ -1333,6 +1347,7 @@ static int cam_fd_mgr_hw_flush_req(void *hw_mgr_priv, if (frame_req->request_id != flush_req->request_id) continue; + hw_mgr->num_pending_frames--; list_del_init(&frame_req->list); break; } @@ -1345,6 +1360,7 @@ static int cam_fd_mgr_hw_flush_req(void *hw_mgr_priv, if (frame_req->request_id != flush_req->request_id) continue; + hw_mgr->num_pending_frames--; list_del_init(&frame_req->list); break; } @@ -1427,6 +1443,7 @@ static int cam_fd_mgr_hw_flush_ctx(void *hw_mgr_priv, if (frame_req->hw_ctx != hw_ctx) continue; + hw_mgr->num_pending_frames--; list_del_init(&frame_req->list); } @@ -1435,6 +1452,7 @@ static int cam_fd_mgr_hw_flush_ctx(void *hw_mgr_priv, if (frame_req->hw_ctx != hw_ctx) continue; + hw_mgr->num_pending_frames--; list_del_init(&frame_req->list); } @@ -1816,6 +1834,7 @@ static int cam_fd_mgr_hw_config(void *hw_mgr_priv, void *hw_config_args) struct cam_fd_mgr_frame_request *frame_req; int rc; int i; + uint64_t req_id; if (!hw_mgr || !config) { CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", hw_mgr, config); @@ -1834,6 +1853,7 @@ static int cam_fd_mgr_hw_config(void *hw_mgr_priv, void *hw_config_args) } frame_req = config->priv; + req_id = frame_req->request_id; trace_cam_apply_req("FD", frame_req->request_id); CAM_DBG(CAM_FD, "FrameHWConfig : Frame[%lld]", frame_req->request_id); @@ -1863,6 +1883,13 @@ static int cam_fd_mgr_hw_config(void *hw_mgr_priv, void *hw_config_args) goto put_free_list; } + mutex_lock(&g_fd_hw_mgr.frame_req_mutex); + hw_mgr->num_pending_frames++; + CAM_DBG(CAM_FD, + "Adding ctx[%pK] Req[%llu] : Total number of pending frames %d", + hw_ctx, req_id, hw_mgr->num_pending_frames); + mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); + rc = cam_fd_mgr_util_schedule_frame_worker_task(hw_mgr); if (rc) { CAM_ERR(CAM_FD, "Worker task scheduling failed %d", rc); @@ -1882,6 +1909,10 @@ static int cam_fd_mgr_hw_config(void *hw_mgr_priv, void *hw_config_args) cam_fd_mgr_util_get_frame_req( &hw_mgr->frame_pending_list_normal, &frame_req); } + + mutex_lock(&g_fd_hw_mgr.frame_req_mutex); + hw_mgr->num_pending_frames--; + mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); put_free_list: cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, &frame_req); @@ -1952,6 +1983,8 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, hw_device->valid = true; hw_device->hw_intf = hw_intf; hw_device->ready_to_process = true; + hw_device->req_id = -1; + hw_device->cur_hw_ctx = NULL; if (hw_device->hw_intf->hw_ops.process_cmd) { struct cam_fd_hw_cmd_set_irq_cb irq_cb_args; @@ -2004,6 +2037,7 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, g_fd_hw_mgr.device_iommu.secure = -1; g_fd_hw_mgr.cdm_iommu.non_secure = -1; g_fd_hw_mgr.cdm_iommu.secure = -1; + g_fd_hw_mgr.num_pending_frames = 0; rc = cam_smmu_get_handle("fd", &g_fd_hw_mgr.device_iommu.non_secure); diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h index bbbc77bef6a3..53daf2185203 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h @@ -159,6 +159,8 @@ struct cam_fd_mgr_work_data { * @work : Worker handle * @work_data : Worker data * @fd_caps : FD driver capabilities + * @num_pending_frames : Number of total frames pending for processing + * across contexts */ struct cam_fd_hw_mgr { struct list_head free_ctx_list; @@ -182,6 +184,7 @@ struct cam_fd_hw_mgr { struct cam_req_mgr_core_workq *work; struct cam_fd_mgr_work_data work_data[CAM_FD_WORKQ_NUM_TASK]; struct cam_fd_query_cap_cmd fd_caps; + uint32_t num_pending_frames; }; #endif /* _CAM_FD_HW_MGR_H_ */ diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index 38283ec67bb5..7ff03e806a55 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -753,6 +753,8 @@ int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size) CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc); goto disable_soc; } + + init_args->is_hw_reset = true; } cam_fd_hw_util_enable_power_on_settings(fd_hw); diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h index 85ec6fa390ff..82d18ccf85dd 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -163,11 +163,13 @@ struct cam_fd_hw_release_args { * @hw_ctx : HW context for which init is requested * @ctx_hw_private : HW layer's private information specific to this hw context * @reset_required : Indicates if the reset is required during init or not + * @is_hw_reset : Output from hw layer, whether hw is reset on this init */ struct cam_fd_hw_init_args { void *hw_ctx; void *ctx_hw_private; bool reset_required; + bool is_hw_reset; }; /** -- GitLab From 7bfa314a556c0f46a91d19c469815c52028b46d6 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 9 Jan 2020 12:01:18 -0800 Subject: [PATCH 237/410] msm: camera: ife: Look into next request if res not found In cases where IRQ delays or overlap happens, the IRQ we get for the resource may belong to the 2nd request in the queue. If the IRQ resource is not found in top request, look into the second request as well. CRs-Fixed: 2600457 Change-Id: Ida2665a00169463e2f146de1cfa6be076d8c7d72 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_isp/cam_isp_context.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 3203dd86f2c4..f8614ff6f860 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -766,10 +766,28 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } if (j == req_isp->num_fence_map_out) { - CAM_ERR(CAM_ISP, - "Can not find matching lane handle 0x%x!", - done->resource_handle[i]); - rc = -EINVAL; + if (done_next_req) { + /* + * If not found in current request, it could be + * belonging to next request, This can happen if + * IRQ delay happens. + */ + CAM_WARN(CAM_ISP, + "BUF_DONE for res 0x%x not found in Req %lld ", + __cam_isp_resource_handle_id_to_type( + done->resource_handle[i]), + req->request_id); + + done_next_req->resource_handle + [done_next_req->num_handles++] = + done->resource_handle[i]; + } else { + CAM_ERR(CAM_ISP, + "Can not find matching lane handle 0x%x! in Req %lld", + done->resource_handle[i], + req->request_id); + rc = -EINVAL; + } continue; } -- GitLab From f72f63e208b30b03cbe55edfad94224ec351f10f Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Tue, 10 Dec 2019 14:11:48 -0800 Subject: [PATCH 238/410] msm: camera: cpas: Remove votes on enable_soc failure If enabling soc resources has failed, remove the votes that were voted for this client. CRs-Fixed: 2585080 Change-Id: I05f460e93a1bf7b96a99dd32f3fd03dbde5b094f Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cpas/cam_cpas_hw.c | 44 +++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 829d00870d80..0c4ae1920f47 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1180,6 +1180,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, struct cam_cpas_hw_cmd_start *cmd_hw_start; struct cam_cpas_client *cpas_client; struct cam_ahb_vote *ahb_vote; + struct cam_ahb_vote remove_ahb; struct cam_axi_vote axi_vote = {0}; enum cam_vote_level applied_level = CAM_SVS_VOTE; int rc, i = 0; @@ -1241,7 +1242,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, CAM_ERR(CAM_CPAS, "client=[%d] is not registered", client_indx); rc = -EPERM; - goto done; + goto error; } if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { @@ -1249,7 +1250,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, client_indx, cpas_client->data.identifier, cpas_client->data.cell_index); rc = -EPERM; - goto done; + goto error; } CAM_DBG(CAM_CPAS, @@ -1260,7 +1261,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, ahb_vote, &applied_level); if (rc) - goto done; + goto error; cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Vote", &axi_vote); @@ -1281,7 +1282,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (rc) { CAM_ERR(CAM_CPAS, "Unable to create or translate paths rc: %d", rc); - goto done; + goto remove_ahb_vote; } cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote", @@ -1290,7 +1291,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); if (rc) - goto done; + goto remove_ahb_vote; if (cpas_core->streamon_clients == 0) { atomic_set(&cpas_core->irq_count, 1); @@ -1299,7 +1300,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (rc) { atomic_set(&cpas_core->irq_count, 0); CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc); - goto done; + goto remove_axi_vote; } if (cpas_core->internal_ops.power_on) { @@ -1311,7 +1312,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, CAM_ERR(CAM_CPAS, "failed in power_on settings rc=%d", rc); - goto done; + goto remove_axi_vote; } } CAM_DBG(CAM_CPAS, "irq_count=%d\n", @@ -1325,7 +1326,34 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, CAM_DBG(CAM_CPAS, "client=[%d][%s][%d] streamon_clients=%d", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, cpas_core->streamon_clients); -done: + + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; + +remove_axi_vote: + memset(&axi_vote, 0x0, sizeof(struct cam_axi_vote)); + rc = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); + if (rc) + CAM_ERR(CAM_CPAS, "Unable to create per path votes rc: %d", rc); + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start fail Vote", + &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, &axi_vote); + if (rc) + CAM_ERR(CAM_CPAS, "Unable to remove axi votes rc: %d", rc); + +remove_ahb_vote: + remove_ahb.type = CAM_VOTE_ABSOLUTE; + remove_ahb.vote.level = CAM_SUSPEND_VOTE; + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + &remove_ahb, NULL); + if (rc) + CAM_ERR(CAM_CPAS, "Removing AHB vote failed, rc=%d", rc); + +error: mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return rc; -- GitLab From a82c58be5ab40f8c3413fd68538e81ed348ef6de Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 29 Aug 2019 12:35:25 -0700 Subject: [PATCH 239/410] msm: camera: isp: Add trace events across ISP Add trace events for IRQ's on IFE top side and IFE BUS side in top half. These traces when enabled will help to gather relative timing information of the IRQ's with systrace. CRs-Fixed: 2538876 Change-Id: I856a9df1978f90e260da7c62cadf02fa2fe53202 Signed-off-by: Vishalsingh Hajeri Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cdm/cam_cdm_hw_core.c | 6 +++++ drivers/cam_isp/cam_isp_context.c | 11 +++++++++ .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile | 1 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 24 ++++++++++++++++++- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile | 1 + .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 22 +++++++++++++++++ drivers/cam_utils/cam_trace.h | 23 ++++++++++++++++++ 7 files changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 0663b8d0f30d..4b908dc173d3 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -19,6 +19,7 @@ #include "cam_cdm_soc.h" #include "cam_io_util.h" #include "cam_hw_cdm170_reg.h" +#include "cam_trace.h" #define CAM_HW_CDM_CPAS_0_NAME "qcom,cam170-cpas-cdm0" #define CAM_HW_CDM_IPE_0_NAME "qcom,cam170-ipe0-cdm" @@ -380,6 +381,8 @@ int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw, rc = -EIO; } + trace_cam_log_event("CDM_START", "CDM_START_IRQ", req->data->cookie, 0); + end: return rc; } @@ -679,6 +682,9 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) "Failed to read CDM HW IRQ data"); } } + trace_cam_log_event("CDM_DONE", "CDM_DONE_IRQ", + payload->irq_status, + cdm_hw->soc_info.index); CAM_DBG(CAM_CDM, "Got payload=%d", payload->irq_status); payload->hw = cdm_hw; INIT_WORK((struct work_struct *)&payload->work, diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 3203dd86f2c4..4431c118ac6b 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -723,6 +723,11 @@ static void __cam_isp_ctx_handle_buf_done_fail_log( "Resource Handles that fail to generate buf_done in prev frame"); for (i = 0; i < req_isp->num_fence_map_out; i++) { if (req_isp->fence_map_out[i].sync_id != -1) { + trace_cam_log_event("Buf_done Congestion", + __cam_isp_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle), + request_id, req_isp->fence_map_out[i].sync_id); + CAM_WARN(CAM_ISP, "Resource_Handle: [%s][0x%x] Sync_ID: [0x%x]", __cam_isp_resource_handle_id_to_type( @@ -779,6 +784,10 @@ static int __cam_isp_ctx_handle_buf_done_for_request( req->request_id, i, j, __cam_isp_resource_handle_id_to_type( done->resource_handle[i])); + trace_cam_log_event("Duplicate BufDone", + __cam_isp_resource_handle_id_to_type( + done->resource_handle[i]), + req->request_id, ctx->ctx_id); if (done_next_req) { done_next_req->resource_handle @@ -1459,6 +1468,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_WARN(CAM_ISP, "Notify CRM about Bubble req %lld frame %lld, ctx %u", req->request_id, ctx_isp->frame_id, ctx->ctx_id); + trace_cam_log_event("Bubble", "Rcvd epoch in applied state", + req->request_id, ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); atomic_set(&ctx_isp->process_bubble, 1); } else { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile index d5ab83c81dd7..aa3fb1c74358 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -3,6 +3,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index ef54125f682b..017ad12e9dd7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -21,8 +21,10 @@ #include "cam_vfe_soc.h" #include "cam_debug_util.h" #include "cam_cpas_api.h" +#include "cam_trace.h" static const char drv_name[] = "vfe_bus"; +static char rup_controller_name[32] = ""; #define CAM_VFE_BUS_VER3_IRQ_REG0 0 #define CAM_VFE_BUS_VER3_IRQ_REG1 1 @@ -916,6 +918,7 @@ static int cam_vfe_bus_ver3_handle_rup_top_half(uint32_t evt_id, struct cam_isp_resource_node *vfe_out = NULL; struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; struct cam_vfe_bus_irq_evt_payload *evt_payload; + uint32_t irq_status; vfe_out = th_payload->handler_priv; if (!vfe_out) { @@ -944,6 +947,12 @@ static int cam_vfe_bus_ver3_handle_rup_top_half(uint32_t evt_id, evt_payload->evt_id = evt_id; for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + irq_status = + th_payload->evt_status_arr[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + trace_cam_log_event("RUP", "RUP_IRQ", irq_status, 0); + th_payload->evt_payload_priv = evt_payload; return rc; @@ -2237,6 +2246,8 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, struct cam_isp_resource_node *vfe_out = NULL; struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; struct cam_vfe_bus_irq_evt_payload *evt_payload; + struct cam_vfe_bus_ver3_comp_grp_data *resource_data; + uint32_t status_0; vfe_out = th_payload->handler_priv; if (!vfe_out) { @@ -2245,6 +2256,7 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, } rsrc_data = vfe_out->res_priv; + resource_data = rsrc_data->comp_grp->res_priv; CAM_DBG(CAM_ISP, "VFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X", rsrc_data->common_data->core_index, @@ -2273,6 +2285,17 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, th_payload->evt_payload_priv = evt_payload; + status_0 = th_payload->evt_status_arr[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + if (status_0 & BIT(resource_data->comp_grp_type + + rsrc_data->common_data->comp_done_shift)) { + trace_cam_log_event("bufdone", "bufdone_IRQ", + status_0, resource_data->comp_grp_type); + } + + if (status_0 & 0x1) + trace_cam_log_event("UnexpectedRUP", "RUP_IRQ", status_0, 40); + CAM_DBG(CAM_ISP, "Exit"); return rc; } @@ -3744,7 +3767,6 @@ int cam_vfe_bus_ver3_init( struct cam_vfe_bus *vfe_bus_local; struct cam_vfe_bus_ver3_hw_info *ver3_hw_info = bus_hw_info; struct cam_vfe_soc_private *soc_private = NULL; - char rup_controller_name[12] = ""; CAM_DBG(CAM_ISP, "Enter"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile index 2ab4651e4271..08b95ac27209 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -4,6 +4,7 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 6f1e28110b5f..fd7aaaf27cde 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -18,6 +18,7 @@ #include "cam_debug_util.h" #include "cam_cdm_util.h" #include "cam_cpas_api.h" +#include "cam_trace.h" #define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 @@ -1219,6 +1220,27 @@ static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, th_payload->evt_payload_priv = evt_payload; + if (th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->sof_irq_mask) { + trace_cam_log_event("SOF", "TOP_HALF", + th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + camif_node->hw_intf->hw_idx); + } + + if (th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->epoch0_irq_mask) { + trace_cam_log_event("EPOCH0", "TOP_HALF", + th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + camif_node->hw_intf->hw_idx); + } + + if (th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->eof_irq_mask) { + trace_cam_log_event("EOF", "TOP_HALF", + th_payload->evt_status_arr[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + camif_node->hw_intf->hw_idx); + } + CAM_DBG(CAM_ISP, "Exit"); return rc; } diff --git a/drivers/cam_utils/cam_trace.h b/drivers/cam_utils/cam_trace.h index 838997590771..c564b1582a3a 100644 --- a/drivers/cam_utils/cam_trace.h +++ b/drivers/cam_utils/cam_trace.h @@ -63,6 +63,29 @@ TRACE_EVENT(cam_isp_activated_irq, ) ); +TRACE_EVENT(cam_log_event, + TP_PROTO(const char *string1, const char *string2, + uint64_t val1, uint64_t val2), + TP_ARGS(string1, string2, val1, val2), + TP_STRUCT__entry( + __string(string1, string1) + __string(string2, string2) + __field(uint64_t, val1) + __field(uint64_t, val2) + ), + TP_fast_assign( + __assign_str(string1, string1); + __assign_str(string2, string2); + __entry->val1 = val1; + __entry->val2 = val2; + ), + TP_printk( + "%s: %s val1=%llu val2=%llu", + __get_str(string1), __get_str(string2), + __entry->val1, __entry->val2 + ) +); + TRACE_EVENT(cam_icp_fw_dbg, TP_PROTO(char *dbg_message, uint64_t timestamp), TP_ARGS(dbg_message, timestamp), -- GitLab From a75dd34310346bfb402dbc0bba29e55d75da7311 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Thu, 6 Feb 2020 13:58:09 -0800 Subject: [PATCH 240/410] msm: camera: icp: Remove bw vote of context in Release Do not rely on timer expiry to remove bw of current context if it is getting released. If context release is coming before timer expiry (from last request submit), we are not removing current context's vote from hw mgr and thus from cpas. This will accumulate the bandwidth and causes clocks to go to turbo and also into overflow issues if the bw variables in cpas are wrapping around in long hours testing. CRs-Fixed: 2617278 Change-Id: I11d837bf7224ac4573fee32518f7f57ad9bf49f0 Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cpas/cam_cpas_hw.c | 25 ++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 189 ++++++++++++------ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 2 + 3 files changed, 149 insertions(+), 67 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 5bfd0afad161..0d44156d3c14 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -468,6 +468,13 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( do_div(intermediate_result, 100); required_camnoc_bw += intermediate_result; + if (cpas_core->streamon_clients && (required_camnoc_bw == 0)) { + CAM_DBG(CAM_CPAS, + "Set min vote if streamon_clients is non-zero : streamon_clients=%d", + cpas_core->streamon_clients); + required_camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + } + if ((required_camnoc_bw > 0) && (required_camnoc_bw < soc_private->camnoc_axi_min_ib_bw)) @@ -704,8 +711,12 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( if (camnoc_axi_port->camnoc_bw) camnoc_bw = camnoc_axi_port->camnoc_bw; - else + else if (camnoc_axi_port->additional_bw) camnoc_bw = camnoc_axi_port->additional_bw; + else if (cpas_core->streamon_clients) + camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + camnoc_bw = 0; rc = cam_cpas_util_vote_bus_client_bw( &camnoc_axi_port->bus_client, @@ -881,14 +892,20 @@ static int cam_cpas_util_apply_client_axi_vote( else continue; - CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld", + CAM_DBG(CAM_PERF, + "Port[%s] : ab=%lld ib=%lld additional=%lld, streamon_clients=%d", mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw, - mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw); + mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw, + cpas_core->streamon_clients); if (mnoc_axi_port->ab_bw) mnoc_ab_bw = mnoc_axi_port->ab_bw; - else + else if (mnoc_axi_port->additional_bw) mnoc_ab_bw = mnoc_axi_port->additional_bw; + else if (cpas_core->streamon_clients) + mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + mnoc_ab_bw = 0; if (cpas_core->axi_port[i].ib_bw_voting_needed) mnoc_ib_bw = mnoc_axi_port->ib_bw; 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 f0bf17855753..70630d870224 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 @@ -415,73 +415,48 @@ static int32_t cam_icp_deinit_idle_clk(void *priv, void *data) return rc; } -static int32_t cam_icp_ctx_timer(void *priv, void *data) +static int cam_icp_remove_ctx_bw(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) { - struct clk_work_data *task_data = (struct clk_work_data *)data; - struct cam_icp_hw_ctx_data *ctx_data = - (struct cam_icp_hw_ctx_data *)task_data->data; - struct cam_icp_hw_mgr *hw_mgr = &icp_hw_mgr; + int rc = 0; + struct cam_hw_intf *dev_intf = NULL; uint32_t id; uint64_t temp; - struct cam_hw_intf *ipe0_dev_intf = NULL; - struct cam_hw_intf *ipe1_dev_intf = NULL; - struct cam_hw_intf *bps_dev_intf = NULL; - struct cam_hw_intf *dev_intf = NULL; struct cam_icp_clk_info *clk_info; struct cam_icp_cpas_vote clk_update; int i = 0; int device_share_ratio = 1; uint64_t total_ab_bw = 0; - if (!ctx_data) { - CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk"); + if (!ctx_data->icp_dev_acquire_info) { + CAM_WARN(CAM_ICP, "NULL acquire info"); return -EINVAL; } - mutex_lock(&ctx_data->ctx_mutex); - if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) || - (ctx_data->watch_dog_reset_counter == 0)) { - CAM_DBG(CAM_PERF, "state %d, counter=%d", - ctx_data->state, ctx_data->watch_dog_reset_counter); - mutex_unlock(&ctx_data->ctx_mutex); - return 0; - } - - if (cam_icp_frame_pending(ctx_data)) { - cam_icp_ctx_timer_reset(ctx_data); - mutex_unlock(&ctx_data->ctx_mutex); - return -EBUSY; + if ((!hw_mgr->ipe0_dev_intf) || (!hw_mgr->bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + return -EINVAL; } CAM_DBG(CAM_PERF, - "E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", + "ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", ctx_data->ctx_id, ctx_data->clk_info.uncompressed_bw, ctx_data->clk_info.compressed_bw, ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); - ipe0_dev_intf = hw_mgr->ipe0_dev_intf; - ipe1_dev_intf = hw_mgr->ipe1_dev_intf; - bps_dev_intf = hw_mgr->bps_dev_intf; - - if ((!ipe0_dev_intf) || (!bps_dev_intf)) { - CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); - mutex_unlock(&ctx_data->ctx_mutex); - return -EINVAL; - } - - if (!ctx_data->icp_dev_acquire_info) { - CAM_WARN(CAM_ICP, "NULL acquire info"); - mutex_unlock(&ctx_data->ctx_mutex); - return -EINVAL; + if (!ctx_data->clk_info.bw_included) { + CAM_DBG(CAM_PERF, "ctx_id = %d BW vote already removed", + ctx_data->ctx_id); + return 0; } if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { - dev_intf = bps_dev_intf; + dev_intf = hw_mgr->bps_dev_intf; clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; id = CAM_ICP_BPS_CMD_VOTE_CPAS; } else { - dev_intf = ipe0_dev_intf; + dev_intf = hw_mgr->ipe0_dev_intf; clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; id = CAM_ICP_IPE_CMD_VOTE_CPAS; } @@ -492,7 +467,7 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) * to vote on each device */ if ((ctx_data->icp_dev_acquire_info->dev_type != - CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) + CAM_ICP_RES_TYPE_BPS) && (hw_mgr->ipe1_dev_intf)) device_share_ratio = 2; if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { @@ -549,23 +524,20 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) * votes only. */ path_index = - ctx_data->clk_info.axi_path[i] - .transac_type - - CAM_AXI_TRANSACTION_READ; + ctx_data->clk_info.axi_path[i].transac_type - + CAM_AXI_TRANSACTION_READ; } else { path_index = - ctx_data->clk_info.axi_path[i] - .path_data_type - - CAM_AXI_PATH_DATA_IPE_START_OFFSET; + ctx_data->clk_info.axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IPE_START_OFFSET; } if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { CAM_WARN(CAM_PERF, - "Invalid path %d, start offset=%d, max=%d", - ctx_data->clk_info.axi_path[i] - .path_data_type, - CAM_AXI_PATH_DATA_IPE_START_OFFSET, - CAM_ICP_MAX_PER_PATH_VOTES); + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i].path_data_type, + CAM_AXI_PATH_DATA_IPE_START_OFFSET, + CAM_ICP_MAX_PER_PATH_VOTES); continue; } @@ -582,6 +554,30 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) total_ab_bw += clk_info->axi_path[path_index].mnoc_ab_bw; + + CAM_DBG(CAM_PERF, + "Removing ctx bw from path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", + cam_cpas_axi_util_path_type_to_string( + ctx_data->clk_info.axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + ctx_data->clk_info.axi_path[i].transac_type), + ctx_data->clk_info.axi_path[i].camnoc_bw, + ctx_data->clk_info.axi_path[i].mnoc_ab_bw, + ctx_data->clk_info.axi_path[i].mnoc_ib_bw, + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type)); + + CAM_DBG(CAM_PERF, + "Final HW bw for path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", + cam_cpas_axi_util_path_type_to_string( + clk_info->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + clk_info->axi_path[i].transac_type), + clk_info->axi_path[i].camnoc_bw, + clk_info->axi_path[i].mnoc_ab_bw, + clk_info->axi_path[i].mnoc_ib_bw, + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type)); } memset(&ctx_data->clk_info.axi_path[0], 0, @@ -628,22 +624,76 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) clk_update.ahb_vote_valid = false; } - dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + rc = dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, "Failed in updating cpas vote, rc=%d", rc); /* * Vote half bandwidth each on both devices. * Total bw at mnoc - CPAS will take care of adding up. * camnoc clk calculate is more accurate this way. */ - if ((ctx_data->icp_dev_acquire_info->dev_type != - CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) - ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, id, - &clk_update, sizeof(clk_update)); + if ((!rc) && (hw_mgr->ipe1_dev_intf) && + (ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS)) { + dev_intf = hw_mgr->ipe1_dev_intf; + rc = dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, + id, &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, + "Failed in updating cpas vote for ipe 2, rc=%d", + rc); + } + + ctx_data->clk_info.bw_included = false; CAM_DBG(CAM_PERF, "X :ctx_id = %d curr_fc = %u bc = %u", ctx_data->ctx_id, ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); + + return rc; + +} + + +static int32_t cam_icp_ctx_timer(void *priv, void *data) +{ + struct clk_work_data *task_data = (struct clk_work_data *)data; + struct cam_icp_hw_ctx_data *ctx_data = + (struct cam_icp_hw_ctx_data *)task_data->data; + + if (!ctx_data) { + CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + + CAM_DBG(CAM_PERF, + "ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", + ctx_data->ctx_id, + ctx_data->clk_info.uncompressed_bw, + ctx_data->clk_info.compressed_bw, + ctx_data->clk_info.curr_fc, + ctx_data->clk_info.base_clk); + + if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) || + (ctx_data->watch_dog_reset_counter == 0)) { + CAM_DBG(CAM_PERF, "state %d, counter=%d", + ctx_data->state, ctx_data->watch_dog_reset_counter); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + if (cam_icp_frame_pending(ctx_data)) { + cam_icp_ctx_timer_reset(ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + return -EBUSY; + } + + cam_icp_remove_ctx_bw(&icp_hw_mgr, ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); return 0; @@ -1184,6 +1234,8 @@ static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw); } + ctx_data->clk_info.bw_included = true; + if (hw_mgr_clk_info->num_paths < ctx_data->clk_info.num_paths) hw_mgr_clk_info->num_paths = ctx_data->clk_info.num_paths; @@ -1250,6 +1302,8 @@ static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, } } + ctx_data->clk_info.bw_included = true; + return true; } @@ -1432,6 +1486,7 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, struct cam_icp_hw_ctx_data *ctx_data) { + int rc = 0; uint32_t id; uint64_t temp; int i = 0; @@ -1529,8 +1584,10 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, } clk_update.axi_vote_valid = true; - dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + rc = dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, "Failed in updating cpas vote, rc=%d", rc); /* * Vote half bandwidth each on both devices. @@ -1538,11 +1595,16 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, * camnoc clk calculate is more accurate this way. */ if ((ctx_data->icp_dev_acquire_info->dev_type != - CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) - ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, id, - &clk_update, sizeof(clk_update)); + CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) { + rc = ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, + id, &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, + "Failed in updating cpas vote for ipe 2, rc=%d", + rc); + } - return 0; + return rc; } static int cam_icp_mgr_ipe_bps_clk_update(struct cam_icp_hw_mgr *hw_mgr, @@ -3344,6 +3406,7 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id) } mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + cam_icp_remove_ctx_bw(hw_mgr, &hw_mgr->ctx_data[ctx_id]); if (hw_mgr->ctx_data[ctx_id].state != CAM_ICP_CTX_STATE_ACQUIRED) { mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index c438d438e892..a4b3817680e8 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -207,6 +207,7 @@ struct hfi_frame_process_info { * @clk_rate: Supported clock rates for the context * @num_paths: Number of valid AXI paths * @axi_path: ctx based per path bw vote + * @bw_included: Whether bw of this context is included in overal voting */ struct cam_ctx_clk_info { uint32_t curr_fc; @@ -218,6 +219,7 @@ struct cam_ctx_clk_info { int32_t clk_rate[CAM_MAX_VOTE]; uint32_t num_paths; struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; + bool bw_included; }; /** * struct cam_icp_hw_ctx_data -- GitLab From f7a9682c54254479335c0e1505d5dd886b470f8b Mon Sep 17 00:00:00 2001 From: Pavan Kumar Chilamkurthi Date: Wed, 11 Dec 2019 13:31:46 -0800 Subject: [PATCH 241/410] msm: camera: smmu: Profile time taken for map, unmap Add debugging capability to profile ion alloc, smmu map and unmap calls. Enable below debugfs settings to get the traces with corresponding latencies. Alloc : echo 1 > /sys/kernel/debug/camera_memmgr/alloc_profile_enable Map, Unmap : echo 1 > /sys/kernel/debug/camera_smmu/map_profile_enable Capture the profiling numbers in traces. CRs-Fixed: 2538876 Change-Id: I92dc58416a9febc77a7836b8f7b1523b547c128f Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_req_mgr/cam_mem_mgr.c | 45 +++++++++++++++++++++++++++-- drivers/cam_req_mgr/cam_mem_mgr.h | 4 +++ drivers/cam_smmu/Makefile | 1 + drivers/cam_smmu/cam_smmu_api.c | 40 ++++++++++++++++++++++++- drivers/cam_utils/cam_common_util.h | 19 ++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index eef1583451ba..ae0f167e189f 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -10,11 +10,14 @@ #include #include #include +#include #include "cam_req_mgr_util.h" #include "cam_mem_mgr.h" #include "cam_smmu_api.h" #include "cam_debug_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" static struct cam_mem_table tbl; static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); @@ -116,6 +119,29 @@ static int cam_mem_util_unmap_cpu_va(struct dma_buf *dmabuf, return rc; } +static int cam_mem_mgr_create_debug_fs(void) +{ + tbl.dentry = debugfs_create_dir("camera_memmgr", NULL); + if (!tbl.dentry) { + CAM_ERR(CAM_MEM, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("alloc_profile_enable", + 0644, + tbl.dentry, + &tbl.alloc_profile_enable)) { + CAM_ERR(CAM_MEM, + "failed to create alloc_profile_enable"); + goto err; + } + + return 0; +err: + debugfs_remove_recursive(tbl.dentry); + return -ENOMEM; +} + int cam_mem_mgr_init(void) { int i; @@ -141,6 +167,8 @@ int cam_mem_mgr_init(void) atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED); + cam_mem_mgr_create_debug_fs(); + return 0; } @@ -375,12 +403,17 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, { struct dma_buf *dmabuf = NULL; int rc = 0; + struct timespec64 ts1, ts2; + long microsec = 0; if (!buf || !fd) { CAM_ERR(CAM_MEM, "Invalid params, buf=%pK, fd=%pK", buf, fd); return -EINVAL; } + if (tbl.alloc_profile_enable) + CAM_GET_TIMESTAMP(ts1); + *buf = ion_alloc(len, heap_id_mask, flags); if (IS_ERR_OR_NULL(*buf)) return -ENOMEM; @@ -403,6 +436,13 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, rc = -EINVAL; } + if (tbl.alloc_profile_enable) { + CAM_GET_TIMESTAMP(ts2); + CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec); + trace_cam_log_event("IONAllocProfile", "size and time in micro", + len, microsec); + } + return rc; get_fd_fail: @@ -639,8 +679,9 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) if (rc) { CAM_ERR(CAM_MEM, - "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", - cmd->flags, fd, region, cmd->num_hdl, rc); + "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->len, cmd->flags, fd, region, + cmd->num_hdl, rc); goto map_hw_fail; } } diff --git a/drivers/cam_req_mgr/cam_mem_mgr.h b/drivers/cam_req_mgr/cam_mem_mgr.h index 6ce30db66fe3..415639a67172 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/cam_req_mgr/cam_mem_mgr.h @@ -65,12 +65,16 @@ struct cam_mem_buf_queue { * @bitmap: bitmap of the mem mgr utility * @bits: max bits of the utility * @bufq: array of buffers + * @dentry: Debugfs entry + * @alloc_profile_enable: Whether to enable alloc profiling */ struct cam_mem_table { struct mutex m_lock; void *bitmap; size_t bits; struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX]; + struct dentry *dentry; + bool alloc_profile_enable; }; /** diff --git a/drivers/cam_smmu/Makefile b/drivers/cam_smmu/Makefile index b674b48ceb2d..2968a7a1e2af 100644 --- a/drivers/cam_smmu/Makefile +++ b/drivers/cam_smmu/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index 090d01dcd5d5..1860d2e30741 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -21,6 +21,8 @@ #include #include "cam_smmu_api.h" #include "cam_debug_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" #define SHARED_MEM_POOL_GRANULARITY 16 @@ -152,6 +154,7 @@ struct cam_iommu_cb_set { u32 non_fatal_fault; struct dentry *dentry; bool cb_dump_enable; + bool map_profile_enable; }; static const struct of_device_id msm_cam_smmu_dt_match[] = { @@ -1715,6 +1718,8 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, size_t size = 0; uint32_t iova = 0; int rc = 0; + struct timespec64 ts1, ts2; + long microsec = 0; if (IS_ERR_OR_NULL(buf)) { rc = PTR_ERR(buf); @@ -1729,6 +1734,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, goto err_out; } + if (iommu_cb_set.map_profile_enable) + CAM_GET_TIMESTAMP(ts1); + attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev); if (IS_ERR_OR_NULL(attach)) { rc = PTR_ERR(attach); @@ -1788,7 +1796,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, table = dma_buf_map_attachment(attach, dma_dir); if (IS_ERR_OR_NULL(table)) { rc = PTR_ERR(table); - CAM_ERR(CAM_SMMU, "Error: dma map attachment failed"); + CAM_ERR(CAM_SMMU, + "Error: dma map attachment failed, size=%zu", + buf->size); goto err_detach; } @@ -1805,6 +1815,13 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, "iova=%pK, region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", iova, region_id, *paddr_ptr, *len_ptr, attach->dma_map_attrs); + if (iommu_cb_set.map_profile_enable) { + CAM_GET_TIMESTAMP(ts2); + CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec); + trace_cam_log_event("SMMUMapProfile", "size and time in micro", + *len_ptr, microsec); + } + if (table->sgl) { CAM_DBG(CAM_SMMU, "DMA buf: %pK, device: %pK, attach: %pK, table: %pK", @@ -1931,6 +1948,8 @@ static int cam_smmu_unmap_buf_and_remove_from_list( int rc; size_t size; struct iommu_domain *domain; + struct timespec64 ts1, ts2; + long microsec = 0; if ((!mapping_info->buf) || (!mapping_info->table) || (!mapping_info->attach)) { @@ -1949,6 +1968,9 @@ static int cam_smmu_unmap_buf_and_remove_from_list( mapping_info->region_id, mapping_info->paddr, mapping_info->len, mapping_info->attach->dma_map_attrs); + if (iommu_cb_set.map_profile_enable) + CAM_GET_TIMESTAMP(ts1); + if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) { CAM_DBG(CAM_SMMU, "Removing SHARED buffer paddr = %pK, len = %zu", @@ -1985,6 +2007,13 @@ static int cam_smmu_unmap_buf_and_remove_from_list( dma_buf_detach(mapping_info->buf, mapping_info->attach); dma_buf_put(mapping_info->buf); + if (iommu_cb_set.map_profile_enable) { + CAM_GET_TIMESTAMP(ts2); + CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec); + trace_cam_log_event("SMMUUnmapProfile", + "size and time in micro", mapping_info->len, microsec); + } + mapping_info->buf = NULL; list_del_init(&mapping_info->list); @@ -3716,6 +3745,15 @@ static int cam_smmu_create_debug_fs(void) goto err; } + if (!debugfs_create_bool("map_profile_enable", + 0644, + iommu_cb_set.dentry, + &iommu_cb_set.map_profile_enable)) { + CAM_ERR(CAM_SMMU, + "failed to create map_profile_enable"); + goto err; + } + return 0; err: debugfs_remove_recursive(iommu_cb_set.dentry); diff --git a/drivers/cam_utils/cam_common_util.h b/drivers/cam_utils/cam_common_util.h index e202bae5b761..ebe75f6eb5e9 100644 --- a/drivers/cam_utils/cam_common_util.h +++ b/drivers/cam_utils/cam_common_util.h @@ -14,6 +14,25 @@ #define PTR_TO_U64(ptr) ((uint64_t)(uintptr_t)ptr) #define U64_TO_PTR(ptr) ((void *)(uintptr_t)ptr) +#define CAM_GET_TIMESTAMP(timestamp) ktime_get_real_ts64(&(timestamp)) +#define CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts_start, ts_end, diff_microsec) \ +({ \ + diff_microsec = 0; \ + if (ts_end.tv_nsec >= ts_start.tv_nsec) { \ + diff_microsec = \ + (ts_end.tv_nsec - ts_start.tv_nsec) / 1000; \ + diff_microsec += \ + (ts_end.tv_sec - ts_start.tv_sec) * 1000 * 1000; \ + } else { \ + diff_microsec = \ + (ts_end.tv_nsec + \ + (1000*1000*1000 - ts_start.tv_nsec)) / 1000; \ + diff_microsec += \ + (ts_end.tv_sec - ts_start.tv_sec - 1) * 1000 * 1000; \ + } \ +}) + + /** * cam_common_util_get_string_index() * -- GitLab From 64cf59a98d53058361e99494fd9ce98673d9af59 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Wed, 5 Feb 2020 19:43:49 +0530 Subject: [PATCH 242/410] msm: camera: csiphy: Add settings for csiphy version 1.2.3 Add csiphy settings file for csiphy version 1.2.3. CRs-Fixed: 2616088 Change-Id: Iaba3fb1cdd64ba1106e0040b926b7573d1cb9b8c Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_soc.c | 21 + .../include/cam_csiphy_1_2_3_hwreg.h | 431 ++++++++++++++++++ 2 files changed, 452 insertions(+) create mode 100644 drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index c96baff8c662..aa4de0d0a51b 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -10,6 +10,7 @@ #include "include/cam_csiphy_1_2_hwreg.h" #include "include/cam_csiphy_1_2_1_hwreg.h" #include "include/cam_csiphy_1_2_2_hwreg.h" +#include "include/cam_csiphy_1_2_3_hwreg.h" #include "include/cam_csiphy_2_0_hwreg.h" #define CSIPHY_DIVISOR_16 16 @@ -332,6 +333,26 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->clk_lane = 0; csiphy_dev->ctrl_reg->data_rates_settings_table = &data_rate_delta_table_1_2; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2.3")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_3_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_3_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_3_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2_3; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2_3; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2_3; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2_3; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = true; + csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2_3; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h new file mode 100644 index 000000000000..f05e9f9ecee5 --- /dev/null +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -0,0 +1,431 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_2_3_HWREG_H_ +#define _CAM_CSIPHY_1_2_3_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_2_3 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 7, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 18, + .csiphy_3ph_config_array_size = 33, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_2_3[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_2_3[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_2_3[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct +csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +struct csiphy_reg_t +csiphy_2ph_v1_2_3_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +struct +csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct data_rate_settings_t data_rate_delta_table_1_2_3 = { + .num_data_rate_settings = 3, + .data_rate_settings = { + { + /* (2.5 * 10**3 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 3, + .csiphy_data_rate_regs = { + {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (3.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 7980000000, + .data_rate_reg_array_size = 15, + .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + }, + { + /* (4.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 10260000000, + .data_rate_reg_array_size = 15, + .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + } + } +}; +#endif /* _CAM_CSIPHY_1_2_HWREG_H_ */ -- GitLab From 6b2833c20d2ccbbe8efb17bef0026b550cd54ad8 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Mon, 10 Feb 2020 20:09:37 +0530 Subject: [PATCH 243/410] msm: camera: cpas: Setting the vote level on max supported clock lvl basis In Some targets number of use cases are 7 and it was an issue during setting TURBO clock level. Changed the validation from number of client usecase to MAX supported clock level. CRs-Fixed: 2571273 Change-Id: I05cd06ff11c2c43eb4b70d69314e04055894c5fc Signed-off-by: Chandan Kumar Jha --- drivers/cam_cpas/cam_cpas_hw.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 5ae03680ad2f..06ff6dc51fe8 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -62,9 +62,11 @@ static int cam_cpas_util_vote_bus_client_level( return -EINVAL; } - if (level >= bus_client->num_usecases) { - CAM_ERR(CAM_CPAS, "Invalid vote level=%d, usecases=%d", level, - bus_client->num_usecases); + if (level >= CAM_MAX_VOTE) { + CAM_ERR(CAM_CPAS, + "Invalid votelevel=%d,usecases=%d,Bus client=[%d][%s]", + level, bus_client->num_usecases, + bus_client->client_id, bus_client->name); return -EINVAL; } -- GitLab From 827e32663be4ff70f21701a3f068b04a3d8f9c19 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Fri, 31 Jan 2020 15:05:23 -0800 Subject: [PATCH 244/410] msm: camera: ife: Change data type for timeout This commit changes the data type used to capture wait for completion timeout return value from integer type to the more appropriate unsigned long type. CRs-Fixed: 2620807 Change-Id: Ifcf54bdee133df5277ce56f0ba85442d32046eac Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 32 +++++++++---------- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 19 ++++++----- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 20b08740d2ec..1d8aac9b68a9 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -3540,6 +3540,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, struct cam_cdm_bl_request *cdm_cmd; struct cam_ife_hw_mgr_ctx *ctx; struct cam_isp_prepare_hw_update_data *hw_update_data; + unsigned long rem_jiffies = 0; if (!hw_mgr_priv || !config_hw_args) { CAM_ERR(CAM_ISP, @@ -3652,21 +3653,18 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, } if (cfg->init_packet) { - rc = wait_for_completion_timeout( + rem_jiffies = wait_for_completion_timeout( &ctx->config_done_complete, msecs_to_jiffies(30)); - if (rc <= 0) { + if (rem_jiffies == 0) { CAM_ERR(CAM_ISP, - "config done completion timeout for req_id=%llu rc=%d ctx_index %d", - cfg->request_id, rc, ctx->ctx_index); - if (rc == 0) - rc = -ETIMEDOUT; - } else { - rc = 0; + "config done completion timeout for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); + rc = -ETIMEDOUT; + } else CAM_DBG(CAM_ISP, "config done Success for req_id=%llu ctx_index %d", cfg->request_id, ctx->ctx_index); - } } } else { CAM_ERR(CAM_ISP, "No commands to config"); @@ -3814,6 +3812,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) struct cam_ife_hw_mgr_ctx *ctx; enum cam_ife_csid_halt_cmd csid_halt_type; uint32_t i, master_base_idx = 0; + unsigned long rem_jiffies = 0; if (!hw_mgr_priv || !stop_hw_args) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -3913,9 +3912,9 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) cam_ife_mgr_pause_hw(ctx); - rc = wait_for_completion_timeout(&ctx->config_done_complete, + rem_jiffies = wait_for_completion_timeout(&ctx->config_done_complete, msecs_to_jiffies(10)); - if (rc == 0) { + if (rem_jiffies == 0) { CAM_WARN(CAM_ISP, "config done completion timeout for last applied req_id=%llu rc=%d ctx_index %d", ctx->applied_req_id, rc, ctx->ctx_index); @@ -6147,6 +6146,7 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_cmd_args->ctxt_to_hw_map; struct cam_isp_hw_cmd_args *isp_hw_cmd_args = NULL; struct cam_packet *packet; + unsigned long rem_jiffies = 0; if (!hw_mgr_priv || !cmd_args) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -6220,15 +6220,13 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) if (ctx->last_dump_flush_req_id == ctx->applied_req_id) return 0; - rc = wait_for_completion_timeout( + rem_jiffies = wait_for_completion_timeout( &ctx->config_done_complete, msecs_to_jiffies(30)); - if (rc <= 0) { + if (rem_jiffies == 0) CAM_ERR(CAM_ISP, - "config done completion timeout, Reg dump will be unreliable rc=%d ctx_index %d", - rc, ctx->ctx_index); - rc = 0; - } + "config done completion timeout, Reg dump will be unreliable ctx_index %d", + ctx->ctx_index); ctx->last_dump_flush_req_id = ctx->applied_req_id; rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 4013a0bebd5a..c4b34bd18693 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -3284,7 +3284,7 @@ static int cam_ife_csid_reset_regs( csid_hw->csid_info->csid_reg; struct cam_hw_soc_info *soc_info; uint32_t val = 0; - unsigned long flags; + unsigned long flags, rem_jiffies = 0; soc_info = &csid_hw->hw_info->soc_info; @@ -3327,9 +3327,9 @@ static int cam_ife_csid_reset_regs( spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); CAM_DBG(CAM_ISP, "CSID reset start"); - rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + rem_jiffies = wait_for_completion_timeout(&csid_hw->csid_top_complete, msecs_to_jiffies(IFE_CSID_TIMEOUT)); - if (rc <= 0) { + if (rem_jiffies == 0) { val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_status_addr); if (val & 0x1) { @@ -3341,19 +3341,18 @@ static int cam_ife_csid_reset_regs( CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", - rc); - rc = 0; + rem_jiffies); goto end; } CAM_ERR(CAM_ISP, "CSID:%d csid_reset %s fail rc = %d", - csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", + rem_jiffies); rc = -ETIMEDOUT; goto end; - } else { + } else CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", - csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); - rc = 0; - } + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", + rem_jiffies); end: return rc; -- GitLab From 5a0f02f8d1de53b48e4ce2f5350ede93bf47f090 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Wed, 5 Feb 2020 16:50:54 -0800 Subject: [PATCH 245/410] msm: camera: ife: Change halt type This commit changes halt type when HVX streamer is enabled as halting immediately will lead to HVX hang. CRs-Fixed: 2620821 Change-Id: Iab28cb91018899acec1eb671a87aec05b872391e Signed-off-by: Venkat Chinta --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 8 +++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 20b08740d2ec..adf001787e4b 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2467,6 +2467,7 @@ static int cam_ife_mgr_acquire_hw_for_ctx( bool crop_enable = true; is_dual_vfe = in_port->usage_type; + ife_ctx->dsp_enabled = (bool)in_port->dsp_mode; /* get root node resource */ rc = cam_ife_hw_mgr_acquire_res_root(ife_ctx, in_port); @@ -3830,7 +3831,8 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) stop_isp = (struct cam_isp_stop_args *)stop_args->args; /* Set the csid halt command */ - if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) + if ((stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) || + ctx->dsp_enabled) csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY; else csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; @@ -4378,6 +4380,10 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->custom_enabled = false; ctx->use_frame_header_ts = false; ctx->num_reg_dump_buf = 0; + ctx->is_dual = false; + ctx->dsp_enabled = false; + ctx->is_fe_enabled = false; + ctx->is_offline = false; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 9c6dc72190a8..6f1eeafc85d3 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -143,6 +143,7 @@ struct cam_ife_hw_mgr_debug { * @use_frame_header_ts obtain qtimer ts using frame header * @ts captured timestamp when the ctx is acquired * @is_offline Indicate whether context is for offline IFE + * @dsp_enabled Indicate whether dsp is enabled in this context */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -193,6 +194,7 @@ struct cam_ife_hw_mgr_ctx { bool use_frame_header_ts; struct timespec64 ts; bool is_offline; + bool dsp_enabled; }; /** -- GitLab From 2c2b4c9f7df3cefd459aa723a14901c933700626 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Thu, 13 Feb 2020 14:40:00 +0530 Subject: [PATCH 246/410] msm: camera: csiphy: Update settings for csiphy v1.2.3 Update csiphy v1.2.3 settings for lagoon as per the latest HPG (rev. Q). CRs-Fixed: 2616088 Change-Id: I07fedfd4704af801812a8fbd435316dd9f8d1535 Signed-off-by: Shravan Nevatia --- .../include/cam_csiphy_1_2_3_hwreg.h | 300 ++++++++++-------- 1 file changed, 173 insertions(+), 127 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h index f05e9f9ecee5..42bef5eb5b11 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -14,8 +14,8 @@ struct csiphy_reg_parms_t csiphy_v1_2_3 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 18, - .csiphy_3ph_config_array_size = 33, + .csiphy_2ph_config_array_size = 22, + .csiphy_3ph_config_array_size = 38, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -23,11 +23,11 @@ struct csiphy_reg_parms_t csiphy_v1_2_3 = { struct csiphy_reg_t csiphy_common_reg_1_2_3[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, + {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, }; struct csiphy_reg_t csiphy_reset_reg_1_2_3[] = { @@ -56,113 +56,139 @@ struct csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x00C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x07C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x02C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x04C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x06C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0664, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; struct csiphy_reg_t -csiphy_2ph_v1_2_3_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + csiphy_2ph_v1_2_3_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x00C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -170,19 +196,23 @@ csiphy_2ph_v1_2_3_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x07C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -190,19 +220,23 @@ csiphy_2ph_v1_2_3_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x02C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -210,19 +244,23 @@ csiphy_2ph_v1_2_3_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x04C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -230,33 +268,35 @@ csiphy_2ph_v1_2_3_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x06C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, - {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -274,7 +314,7 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -292,10 +332,15 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -304,12 +349,12 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -327,10 +372,15 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -344,7 +394,7 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -362,10 +412,15 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -375,57 +430,48 @@ struct data_rate_settings_t data_rate_delta_table_1_2_3 = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 3, + .data_rate_reg_array_size = 8, .csiphy_data_rate_regs = { {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { /* (3.5 * 10**3 * 2.28) rounded value */ .bandwidth = 7980000000, - .data_rate_reg_array_size = 15, + .data_rate_reg_array_size = 8, .csiphy_data_rate_regs = { - {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }, { /* (4.5 * 10**3 * 2.28) rounded value */ .bandwidth = 10260000000, - .data_rate_reg_array_size = 15, + .data_rate_reg_array_size = 8, .csiphy_data_rate_regs = { - {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, }, } } }; -#endif /* _CAM_CSIPHY_1_2_HWREG_H_ */ +#endif /* _CAM_CSIPHY_1_2_3_HWREG_H_ */ -- GitLab From c105d3b89d588c1c2942465504de3a48ec8763cf Mon Sep 17 00:00:00 2001 From: Shankar Ravi Date: Mon, 10 Feb 2020 14:50:18 +0530 Subject: [PATCH 247/410] msm: camera: eeprom: Correct EEPROM Read return EEPROM Read using QUP I2C returns the number of bytes read from the EEPROM, While CCI/SPI returns zero value. Return Error only when if the value is less than zero. CRs-Fixed: 2617882 External Impact: No Change-Id: I9a9674366c10de4efce779f75dd36b293838c47b Signed-off-by: Shankar Ravi --- drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index c50230309c57..caf5132b3df2 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -108,7 +108,7 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, emap[j].mem.addr_type, emap[j].mem.data_type, emap[j].mem.valid_size); - if (rc) { + if (rc < 0) { CAM_ERR(CAM_EEPROM, "read failed rc %d", rc); return rc; -- GitLab From 67556a535adb96947139613a9f80b2a99eb722ad Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Wed, 19 Feb 2020 14:55:50 +0530 Subject: [PATCH 248/410] msm: camera: cpas: Update QOS settings for lagoon This commit updates some QOS settings for lagoon. Change-Id: Iae0992d3eec182fb1ad1fcefa261da32838af781 CRs-Fixed: 2571273 Signed-off-by: Gaurav Jindal --- drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 14 +- drivers/cam_cpas/cpas_top/cpastop_v170_200.h | 136 +++++++++---------- drivers/cam_cpas/include/cam_cpas_api.h | 9 +- 3 files changed, 87 insertions(+), 72 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index a4d44a3feff6..873d0f490e88 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPASTOP_HW_H_ @@ -20,12 +20,18 @@ * @CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: Triggered if any error * detected in the IFE UBWC- * Stats encoder instance + * @CAM_CAMNOC_HW_IRQ_IFE01_UBWC_ENCODE_ERROR : Triggered if any error + * detected in the IFE1 UBWC + * encoder instance * @CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error * detected in the IFE0 UBWC * encoder instance * @CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error * detected in the IFE1 or IFE3 * UBWC encoder instance + * @CAM_CAMNOC_HW_IRQ_IFE23_UBWC_ENCODE_ERROR : Triggered if any error + * detected in the IFE2 or IFE3 + * UBWC encoder instance * @CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR: Triggered if any error * detected in the IPE1/BPS read * path decoder instance @@ -54,10 +60,14 @@ enum cam_camnoc_hw_irq_type { CAM_CAMNOC_IRQ_SLAVE_ERROR, CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR = CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE01_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE01_UBWC_ENCODE_ERROR, CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR = CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR = CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE23_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE23_UBWC_ENCODE_ERROR, CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR = CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR = @@ -109,8 +119,10 @@ enum cam_camnoc_hw_irq_type { */ enum cam_camnoc_port_type { CAM_CAMNOC_CDM, + CAM_CAMNOC_IFE01, CAM_CAMNOC_IFE02, CAM_CAMNOC_IFE13, + CAM_CAMNOC_IFE23, CAM_CAMNOC_IFE_LINEAR, CAM_CAMNOC_IFE_UBWC_STATS, CAM_CAMNOC_IFE_RDI_WR, diff --git a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h index 98aabc984c87..1754029e1b06 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V170_200_H_ @@ -47,62 +47,62 @@ static struct cam_camnoc_irq_err .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .offset = 0x3D88, /* ERRLOGGER_MAINCTL_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .offset = 0x3D90, /* ERRLOGGER_ERRVLD_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .offset = 0x3D98, /* ERRLOGGER_ERRCLR_LOW */ .value = 1, }, }, { - .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .irq_type = CAM_CAMNOC_HW_IRQ_IFE01_UBWC_ENCODE_ERROR, .enable = true, .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .offset = 0x25a0, /* SPECIFIC_IFE01_ENCERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + .offset = 0x2590, /* SPECIFIC_IFE01_ENCERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .offset = 0x2598, /* SPECIFIC_IFE01_ENCERRCLR_LOW */ .value = 1, }, }, { - .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .irq_type = CAM_CAMNOC_HW_IRQ_IFE23_UBWC_ENCODE_ERROR, .enable = true, .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .offset = 0x27a0, /* SPECIFIC_IFE23_ENCERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + .offset = 0x2790, /* SPECIFIC_IFE23_ENCERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .offset = 0x2798, /* SPECIFIC_IFE23_ENCERRCLR_LOW */ .value = 1, }, }, @@ -113,18 +113,18 @@ static struct cam_camnoc_irq_err .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .offset = 0x2920, /* SPECIFIC_IBL_RD_DECERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + .offset = 0x2910, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .offset = 0x2918, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ .value = 1, }, }, @@ -135,19 +135,19 @@ static struct cam_camnoc_irq_err .err_enable = { .access_type = CAM_REG_TYPE_READ_WRITE, .enable = true, - .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .offset = 0x2ba0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ .value = 1, }, .err_status = { .access_type = CAM_REG_TYPE_READ, .enable = true, - .offset = 0x1190, + .offset = 0x2b90, /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ }, .err_clear = { .access_type = CAM_REG_TYPE_WRITE, .enable = true, - .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .offset = 0x2b98, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ .value = 1, }, }, @@ -208,37 +208,37 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ - .value = 0x22222222, + .offset = 0x2230, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x33333333, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ - .value = 0x22222222, + .offset = 0x2234, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x33333333, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 1, - .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .offset = 0x2238, /* SPECIFIC_CDM_URGENCY_LOW */ .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ - .value = 0x2, + .value = 0x3, }, .danger_lut = { .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .offset = 0x2240, /* SPECIFIC_CDM_DANGERLUT_LOW */ .value = 0x0, }, .safe_lut = { .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .offset = 0x2248, /* SPECIFIC_CDM_SAFELUT_LOW */ .value = 0x0, }, .ubwc_ctl = { @@ -246,98 +246,98 @@ static struct cam_camnoc_specific }, }, { - .port_type = CAM_CAMNOC_IFE02, + .port_type = CAM_CAMNOC_IFE01, .enable = true, .priority_lut_low = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ - .value = 0x66666543, + .offset = 0x2430, /* SPECIFIC_IFE01_PRIORITYLUT_LOW */ + .value = 0x66665643, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .offset = 0x2434, /* SPECIFIC_IFE01_PRIORITYLUT_HIGH */ .value = 0x66666666, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 1, - .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ - /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .offset = 0x2438, /* SPECIFIC_IFE01_URGENCY_LOW */ + /* SPECIFIC_IFE01_URGENCY_LOW_WRITE_MASK */ .mask = 0x70, - /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + /* SPECIFIC_IFE01_URGENCY_LOW_WRITE_SHIFT */ .shift = 0x4, .value = 3, }, .danger_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .offset = 0x2440, /* SPECIFIC_IFE01_DANGERLUT_LOW */ .value = 0xFFFFFF00, }, .safe_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ - .value = 0x1, + .offset = 0x2448, /* SPECIFIC_IFE01_SAFELUT_LOW */ + .value = 0x0000000f, }, .ubwc_ctl = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .offset = 0x2588, /* SPECIFIC_IFE01_ENCCTL_LOW */ .value = 1, }, }, { - .port_type = CAM_CAMNOC_IFE13, + .port_type = CAM_CAMNOC_IFE23, .enable = true, .priority_lut_low = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ - .value = 0x66666543, + .offset = 0x2630, /* SPECIFIC_IFE23_PRIORITYLUT_LOW */ + .value = 0x66665643, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .offset = 0x2634, /* SPECIFIC_IFE23_PRIORITYLUT_HIGH */ .value = 0x66666666, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 1, - .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ - /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .offset = 0x2638, /* SPECIFIC_IFE23_URGENCY_LOW */ + /* SPECIFIC_IFE23_URGENCY_LOW_WRITE_MASK */ .mask = 0x70, - /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + /* SPECIFIC_IFE23_URGENCY_LOW_WRITE_SHIFT */ .shift = 0x4, .value = 3, }, .danger_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .offset = 0x2640, /* SPECIFIC_IFE23_DANGERLUT_LOW */ .value = 0xFFFFFF00, }, .safe_lut = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, - .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ - .value = 0x1, + .offset = 0x2648, /* SPECIFIC_IFE23_SAFELUT_LOW */ + .value = 0x0000000f, }, .ubwc_ctl = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .offset = 0x2788, /* SPECIFIC_IFE23_ENCCTL_LOW */ .value = 1, }, }, @@ -348,46 +348,46 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .offset = 0x2830, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ .value = 0x33333333, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .offset = 0x2834, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ .value = 0x33333333, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 1, - .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + .offset = 0x2838, /* SPECIFIC_IBL_RD_URGENCY_LOW */ /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ .mask = 0x7, /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ - .shift = 0x0, + .shift = 0x4, .value = 3, }, .danger_lut = { .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .offset = 0x2840, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ .value = 0x0, }, .safe_lut = { .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .offset = 0x2848, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ .value = 0x0, }, .ubwc_ctl = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .offset = 0x2908, /* SPECIFIC_IBL_RD_DECCTL_LOW */ .value = 1, }, }, @@ -398,21 +398,21 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .offset = 0x2A30, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ .value = 0x33333333, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .offset = 0x2A34, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ .value = 0x33333333, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 1, - .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + .offset = 0x2A38, /* SPECIFIC_IBL_WR_URGENCY_LOW */ /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ .mask = 0x70, /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ @@ -423,21 +423,21 @@ static struct cam_camnoc_specific .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .offset = 0x2A40, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ .value = 0x0, }, .safe_lut = { .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ .value = 0x0, }, .ubwc_ctl = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ .value = 1, }, }, @@ -448,45 +448,41 @@ static struct cam_camnoc_specific .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .offset = 0x2C30, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ .value = 0x22222222, }, .priority_lut_high = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .offset = 0x2C34, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ .value = 0x22222222, }, .urgency = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .offset = 0x2C38, /* SPECIFIC_JPEG_URGENCY_LOW */ .value = 0x22, }, .danger_lut = { .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .offset = 0x2C40, /* SPECIFIC_JPEG_DANGERLUT_LOW */ .value = 0x0, }, .safe_lut = { .enable = false, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, - .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .offset = 0x2C48, /* SPECIFIC_JPEG_SAFELUT_LOW */ .value = 0x0, }, .ubwc_ctl = { .enable = false, }, }, - { - .port_type = CAM_CAMNOC_FD, - .enable = false, - }, { .port_type = CAM_CAMNOC_ICP, .enable = true, diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 6bb226377056..67a2a50b5816 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_API_H_ @@ -113,11 +113,16 @@ enum cam_cpas_hw_version { * @CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: Triggered if any error detected * in the IFE UBWC-Stats encoder * instance + * @CAM_CAMNOC_IRQ_IFE01_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE1 UBWC encoder instance * @CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error detected * in the IFE0 UBWC encoder instance * @CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error detected * in the IFE1 or IFE3 UBWC encoder * instance + * @CAM_CAMNOC_IRQ_IFE23_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE2 or IFE3 UBWC encoder + * instance * @CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR : Triggered if any error detected * in the IFE0 UBWC encoder instance * @CAM_CAMNOC_IRQ_IFE1_WR_UBWC_ENCODE_ERROR : Triggered if any error detected @@ -141,8 +146,10 @@ enum cam_cpas_hw_version { enum cam_camnoc_irq_type { CAM_CAMNOC_IRQ_SLAVE_ERROR, CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE01_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE23_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, CAM_CAMNOC_IRQ_IPE1_BPS_UBWC_DECODE_ERROR, -- GitLab From 70649193fe848ddf2ca599ef869caead2b338e29 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Fri, 21 Feb 2020 14:59:16 +0530 Subject: [PATCH 249/410] msm: camera: isp: Add CPAS version in Secure Camera call In IFE hw manager, SCM call is based on CPAS versions. This commit adds the cpas version for lagoon while making SCM call for secure camera. Change-Id: I04a4ef6b49be1288fdc60a84f2abb8db2c7f82f5 CRs-Fixed: 2571273 Signed-off-by: Gaurav Jindal --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index fd7bf4baf348..a37dee5ccce9 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -183,6 +183,7 @@ static int cam_ife_notify_safe_lut_scm(bool safe_trigger) if (!rc) { switch (camera_hw_version) { case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V200: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_175_V100: -- GitLab From 3e7663e901145fc8fe64ff194401c61953e4c462 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Fri, 14 Feb 2020 11:18:15 +0530 Subject: [PATCH 250/410] msm: camera: cpas: Change port index to set CAMNOC bandwidth Correction of typo. Modify the correct index to set CAMNOC bandwidth. CRs-Fixed: 2571273 Change-Id: I411cb9417bb5686442e833dac78c51de42cc63f5 Signed-off-by: Chandan Kumar Jha --- drivers/cam_cpas/cam_cpas_hw.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 1747fbe83597..3e0960caa36a 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -642,6 +642,7 @@ static int cam_cpas_update_axi_vote_bw( struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + int idx; if (cpas_tree_node->axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d", @@ -658,9 +659,15 @@ static int cam_cpas_update_axi_vote_bw( if (soc_private->control_camnoc_axi_clk) return 0; - cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx].camnoc_bw = - cpas_tree_node->camnoc_bw; - camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true; + if (cpas_tree_node->camnoc_axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid camnoc_axi_port_idx: %d", + cpas_tree_node->camnoc_axi_port_idx); + return -EINVAL; + } + + idx = cpas_tree_node->camnoc_axi_port_idx; + cpas_core->camnoc_axi_port[idx].camnoc_bw = cpas_tree_node->camnoc_bw; + camnoc_axi_port_updated[idx] = true; return 0; } -- GitLab From a467c0e4d5a0c5f29d7d722ad22b50e8bd55a6d9 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Thu, 6 Feb 2020 13:06:06 +0800 Subject: [PATCH 251/410] msm: camera: reqmgr: Also check the idx if the rd slot has applied - Also check the idx if the rd slot is applied, since the status is APPLIED before sync link process next frame, there is a big chance that sync link rd slot is APPLIED if current link is processing the frame, then CRM won't do the idx checking if we don't check APPLIED status. CRs-Fixed: 2615873 Change-Id: I8fa6f004cec536afcfee5774617165bd0480064d Signed-off-by: Depeng Shao --- drivers/cam_req_mgr/cam_req_mgr_core.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index b5f10a232b89..901500e530b3 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1117,6 +1117,7 @@ static int __cam_req_mgr_check_sync_req_is_ready( int64_t req_id = 0, sync_req_id = 0; int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; int32_t sync_num_slots = 0; + int32_t max_idx_diff; uint64_t sync_frame_duration = 0; uint64_t sof_timestamp_delta = 0; uint64_t master_slave_diff = 0; @@ -1220,12 +1221,20 @@ static int __cam_req_mgr_check_sync_req_is_ready( return -EAGAIN; } + /* + * When the status of sync rd slot is APPLIED, + * the maximum diff between sync_slot_idx and + * sync_rd_idx is 1, since the next processed + * req maybe the request in (sync_rd_idx + 1)th + * slot. + */ + max_idx_diff = + (sync_rd_slot->status == CRM_SLOT_STATUS_REQ_APPLIED) ? 1 : 0; + if ((sync_link->req.in_q->slot[sync_slot_idx].status != CRM_SLOT_STATUS_REQ_APPLIED) && (((sync_slot_idx - sync_rd_idx + sync_num_slots) % - sync_num_slots) >= 1) && - (sync_rd_slot->status != - CRM_SLOT_STATUS_REQ_APPLIED)) { + sync_num_slots) > max_idx_diff)) { CAM_DBG(CAM_CRM, "Req: %lld [other link] not next req to be applied on link: %x", req_id, sync_link->link_hdl); -- GitLab From 1879b1908cfa6eaa91855575c0ec6a03b874df0b Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 20 Feb 2020 10:21:38 +0530 Subject: [PATCH 252/410] msm: camera: reqmgr: increase the rd idx if no lower pd device For link with maximum pipeline delay of 1 e.g., TPG use case or sensors with pipeline delay of 1, if the request is not submitted before 2 consecutive triggers we do not get chance to increment rd idx, in the mean time the slot which was last applied will be reset and we will not be able to apply request even if new requests are scheduled. This will cause the camera to not apply any request further, hence increasing the rd idx if no lower pd devices are pending will fix the issue. CRs-Fixed: 2626743 Change-Id: Ie60ac2751585d9a8019d36d9b0124f2d36483224 Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_req_mgr_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index b5f10a232b89..05750b350af1 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -2580,6 +2580,8 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) CAM_DBG(CAM_REQ, "No pending req to apply to lower pd devices"); rc = 0; + __cam_req_mgr_inc_idx(&in_q->rd_idx, + 1, in_q->num_slots); goto release_lock; } __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); -- GitLab From b679a203faf6031eef5c34e149596a51d68f29e7 Mon Sep 17 00:00:00 2001 From: Mangalaram ARCHANA Date: Thu, 5 Dec 2019 15:32:46 +0530 Subject: [PATCH 253/410] msm: camera: reqmgr: skip re_apply of ISP for buf_done request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit crm applied both sensor and isp packets,sensor packet failed to apply due to CCI timeout error. In the meantime ISP packet applied and that request of ISP moved to free_list.In the next epoch crm trying to reapply both the packets of sensor and isp again.In this case ISP always reporting an apply failure because its pending queue doesn’t have that request.To handle this we are skipping to re-apply the ISP successful buf_done request and trying to apply only sensor packet in this scenario. CRs-Fixed: 2599186 Change-Id: Id7e72fc016a75782b57f05558c615b069b416ffe Signed-off-by: Mangalaram ARCHANA --- drivers/cam_isp/cam_isp_context.c | 8 ++++++++ drivers/cam_req_mgr/cam_req_mgr_core.c | 5 +++++ drivers/cam_req_mgr/cam_req_mgr_core.h | 2 ++ drivers/cam_req_mgr/cam_req_mgr_debug.c | 9 ++++++++- drivers/cam_req_mgr/cam_req_mgr_interface.h | 2 ++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 4020e5bea264..2a44ffa71917 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -2446,6 +2446,14 @@ static int __cam_isp_ctx_apply_req_in_activated_state( goto end; } + if (apply->re_apply) + if (apply->request_id <= ctx_isp->last_applied_req_id) { + CAM_INFO(CAM_ISP, + "Trying to reapply the same request %llu again", + apply->request_id); + return 0; + } + spin_lock_bh(&ctx->lock); req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index b5f10a232b89..af27858834b9 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -659,6 +659,11 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, apply_req.link_hdl = link->link_hdl; apply_req.report_if_bubble = 0; + apply_req.re_apply = false; + if (link->retry_cnt > 0) { + if (g_crm_core_dev->recovery_on_apply_fail) + apply_req.re_apply = true; + } for (i = 0; i < link->num_devs; i++) { dev = &link->l_dev[i]; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index b037c4364790..cc97a52643d4 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -408,10 +408,12 @@ struct cam_req_mgr_core_session { * - Core camera request manager data struct * @session_head : list head holding sessions * @crm_lock : mutex lock to protect session creation & destruction + * @recovery_on_apply_fail : Recovery on apply failure using debugfs. */ struct cam_req_mgr_core_device { struct list_head session_head; struct mutex crm_lock; + bool recovery_on_apply_fail; }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_debug.c b/drivers/cam_req_mgr/cam_req_mgr_debug.c index 6b428c41c1b0..db6bec704370 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_debug.c +++ b/drivers/cam_req_mgr/cam_req_mgr_debug.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include "cam_req_mgr_debug.h" @@ -128,5 +128,12 @@ int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev) debugfs_root, core_dev, &bubble_recovery)) return -ENOMEM; + if (!debugfs_create_bool("recovery_on_apply_fail", + 0644, + debugfs_root, + &core_dev->recovery_on_apply_fail)) { + return -ENOMEM; + } + return 0; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index 7c184d675c6f..5989ef13f5a7 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -325,6 +325,7 @@ struct cam_req_mgr_core_dev_link_setup { * @request_id : request id settings to apply * @report_if_bubble : report to crm if failure in applying * @trigger_point : the trigger point of this apply + * @re_apply : to skip re_apply for buf_done request * */ struct cam_req_mgr_apply_request { @@ -333,6 +334,7 @@ struct cam_req_mgr_apply_request { uint64_t request_id; int32_t report_if_bubble; uint32_t trigger_point; + bool re_apply; }; /** -- GitLab From dac863f477a01ef1ff4c2fde1e1135cf2a8c3cbb Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 30 Dec 2019 10:59:26 +0530 Subject: [PATCH 254/410] msm: camera: csiphy: Update DPHY combo-mode settings for csiphy v1.2 Update DPHY combo-mode settings for lito v1 as per HPG revision N. CRs-Fixed: 2614237 Change-Id: If40ed2d1342d8940abcaabf807ebbe768311304f Signed-off-by: Shravan Nevatia --- .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 179ccebddc54..3cf02e90358d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_2_HWREG_H_ @@ -14,7 +14,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 18, + .csiphy_2ph_config_array_size = 19, .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -73,6 +73,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -93,6 +94,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -113,6 +115,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -133,6 +136,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -153,6 +157,7 @@ csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0664, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; @@ -177,6 +182,7 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -197,6 +203,7 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -217,13 +224,15 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0418, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -250,13 +259,14 @@ csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; -- GitLab From a6781f69397a1ec2405a46cbbb91d347dc03a5dd Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 23 Jan 2020 18:18:16 -0800 Subject: [PATCH 255/410] msm: camera: cci: Add hardware index in dumps This change adds hardware index to register dump. CRs-Fixed: 2632034 Change-Id: Ibdd96d4f9f7a99c71118950fc0ee0b8aec9a7340 Signed-off-by: Venkat Chinta --- drivers/cam_sensor_module/cam_cci/cam_cci_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index 4a2a643a7408..6efa77a8d55d 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -192,6 +192,9 @@ static void cam_cci_dump_registers(struct cci_device *cci_dev, uint32_t reg_offset = 0; void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base; + CAM_INFO(CAM_CCI, "**** CCI:%d register dump ****", + cci_dev->soc_info->index); + /* CCI Top Registers */ CAM_INFO(CAM_CCI, "****CCI TOP Registers ****"); for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) { @@ -205,6 +208,9 @@ static void cam_cci_dump_registers(struct cci_device *cci_dev, CAM_INFO(CAM_CCI, "****CCI MASTER %d Registers ****", master); for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) { + if ((i * 4) == 0x18) + continue; + reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4; read_val = cam_io_r_mb(base + reg_offset); CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", -- GitLab From fd66b87be1766dd4de631052a3b46d2aff7fee75 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 1 Nov 2019 13:43:33 -0700 Subject: [PATCH 256/410] msm: camera: reqmgr: Add support for dual trigger Currently CRM waits for a single trigger to apply settings for all the devices on a given link. This change provides provision for CRM to wait on two triggers prior to applying a given setting. CRs-Fixed: 2627065 Change-Id: If6e4c9281cfd1bf1a8ffa369daee060d79f3c39e Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/cam_isp_context.c | 6 ++ drivers/cam_isp/cam_isp_context.h | 2 + drivers/cam_req_mgr/cam_req_mgr_core.c | 77 ++++++++++++++++++++- drivers/cam_req_mgr/cam_req_mgr_core.h | 7 ++ drivers/cam_req_mgr/cam_req_mgr_interface.h | 28 ++++---- 5 files changed, 105 insertions(+), 15 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 2a44ffa71917..ac4128e1f3b5 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1272,6 +1272,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( notify.trigger = CAM_TRIGGER_POINT_SOF; notify.req_id = ctx_isp->req_info.last_bufdone_req_id; notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; + notify.trigger_id = ctx_isp->trigger_id; ctx->ctx_crm_intf->notify_trigger(¬ify); CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", @@ -4484,6 +4485,7 @@ static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx, ctx->link_hdl = link->link_hdl; ctx->ctx_crm_intf = link->crm_cb; ctx_isp->subscribe_event = link->subscribe_event; + ctx_isp->trigger_id = link->trigger_id; /* change state only if we had the init config */ if (ctx_isp->init_received) { @@ -4500,9 +4502,12 @@ static int __cam_isp_ctx_unlink_in_acquired(struct cam_context *ctx, struct cam_req_mgr_core_dev_link_setup *unlink) { int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; ctx->link_hdl = -1; ctx->ctx_crm_intf = NULL; + ctx_isp->trigger_id = -1; return rc; } @@ -4517,6 +4522,7 @@ static int __cam_isp_ctx_get_dev_info_in_acquired(struct cam_context *ctx, dev_info->dev_id = CAM_REQ_MGR_DEVICE_IFE; dev_info->p_delay = 1; dev_info->trigger = CAM_TRIGGER_POINT_SOF; + dev_info->trigger_on = true; return rc; } diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 89b203d1fde9..2e01868f9c94 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -255,6 +255,7 @@ struct cam_isp_context_event_record { * @rxd_epoch: Indicate whether epoch has been received. Used to * decide whether to apply request in offline ctx * @workq: Worker thread for offline ife + * @trigger_id: ID provided by CRM for each ctx on the link * */ struct cam_isp_context { @@ -296,6 +297,7 @@ struct cam_isp_context { unsigned int init_timestamp; atomic_t rxd_epoch; struct cam_req_mgr_core_workq *workq; + int32_t trigger_id; }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 87698aa80cbc..2a24f0010610 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -40,6 +40,9 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) link->open_req_cnt = 0; link->last_flush_id = 0; link->initial_sync_req = -1; + link->dual_trigger = false; + link->trigger_cnt[0] = 0; + link->trigger_cnt[1] = 0; link->in_msync_mode = false; link->retry_cnt = 0; link->is_shutdown = false; @@ -2767,6 +2770,33 @@ static int cam_req_mgr_cb_notify_err( return rc; } +static int __cam_req_mgr_check_for_dual_trigger( + struct cam_req_mgr_core_link *link) +{ + int rc = -EAGAIN; + + if (link->trigger_cnt[0] == link->trigger_cnt[1]) { + link->trigger_cnt[0] = 0; + link->trigger_cnt[1] = 0; + rc = 0; + return rc; + } + + if ((link->trigger_cnt[0] && + (link->trigger_cnt[0] - link->trigger_cnt[1] > 1)) || + (link->trigger_cnt[1] && + (link->trigger_cnt[1] - link->trigger_cnt[0] > 1))) { + + CAM_ERR(CAM_CRM, + "One of the devices could not generate trigger"); + return rc; + } + + CAM_DBG(CAM_CRM, "Only one device has generated trigger"); + + return rc; +} + /** * cam_req_mgr_cb_notify_timer() * @@ -2885,7 +2915,7 @@ static int cam_req_mgr_cb_notify_stop( static int cam_req_mgr_cb_notify_trigger( struct cam_req_mgr_trigger_notify *trigger_data) { - int rc = 0; + int32_t rc = 0, trigger_id = 0; struct crm_workq_task *task = NULL; struct cam_req_mgr_core_link *link = NULL; struct cam_req_mgr_trigger_notify *notify_trigger; @@ -2905,6 +2935,8 @@ static int cam_req_mgr_cb_notify_trigger( goto end; } + trigger_id = trigger_data->trigger_id; + spin_lock_bh(&link->link_state_spin_lock); if (link->state < CAM_CRM_LINK_STATE_READY) { CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); @@ -2916,6 +2948,23 @@ static int cam_req_mgr_cb_notify_trigger( if ((link->watchdog) && (link->watchdog->pause_timer)) link->watchdog->pause_timer = false; + if (link->dual_trigger) { + if ((trigger_id >= 0) && (trigger_id < + CAM_REQ_MGR_MAX_TRIGGERS)) { + link->trigger_cnt[trigger_id]++; + rc = __cam_req_mgr_check_for_dual_trigger(link); + if (rc) { + spin_unlock_bh(&link->link_state_spin_lock); + goto end; + } + } else { + CAM_ERR(CAM_CRM, "trigger_id invalid %d", trigger_id); + rc = -EINVAL; + spin_unlock_bh(&link->link_state_spin_lock); + goto end; + } + } + crm_timer_reset(link->watchdog); spin_unlock_bh(&link->link_state_spin_lock); @@ -2970,16 +3019,18 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, struct cam_req_mgr_req_tbl *pd_tbl; enum cam_pipeline_delay max_delay; uint32_t subscribe_event = 0; + uint32_t num_trigger_devices = 0; if (link_info->version == VERSION_1) { if (link_info->u.link_info_v1.num_devices > CAM_REQ_MGR_MAX_HANDLES) return -EPERM; - } + } else if (link_info->version == VERSION_2) { if (link_info->u.link_info_v2.num_devices > CAM_REQ_MGR_MAX_HANDLES_V2) return -EPERM; - } + } + mutex_init(&link->req.lock); CAM_DBG(CAM_CRM, "LOCK_DBG in_q lock %pK", &link->req.lock); link->req.num_tbl = 0; @@ -3059,6 +3110,17 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, subscribe_event |= (uint32_t)dev->dev_info.trigger; } + + if (dev->dev_info.trigger_on) + num_trigger_devices++; + } + + if (num_trigger_devices > CAM_REQ_MGR_MAX_TRIGGERS) { + CAM_ERR(CAM_CRM, + "Unsupported number of trigger devices %u", + num_trigger_devices); + rc = -EINVAL; + goto error; } link->subscribe_event = subscribe_event; @@ -3067,7 +3129,10 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, link_data.crm_cb = &cam_req_mgr_ops; link_data.max_delay = max_delay; link_data.subscribe_event = subscribe_event; + if (num_trigger_devices == CAM_REQ_MGR_MAX_TRIGGERS) + link->dual_trigger = true; + num_trigger_devices = 0; for (i = 0; i < num_devices; i++) { dev = &link->l_dev[i]; @@ -3107,6 +3172,12 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, CAM_DBG(CAM_CRM, "dev_bit %u name %s pd %u mask %d", dev->dev_bit, dev->dev_info.name, pd_tbl->pd, pd_tbl->dev_mask); + link_data.trigger_id = -1; + if ((dev->dev_info.trigger_on) && (link->dual_trigger)) { + link_data.trigger_id = num_trigger_devices; + num_trigger_devices++; + } + /* Communicate with dev to establish the link */ dev->ops->link_setup(&link_data); diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index cc97a52643d4..1893eed379c5 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -37,6 +37,7 @@ #define VERSION_1 1 #define VERSION_2 2 +#define CAM_REQ_MGR_MAX_TRIGGERS 2 /** * enum crm_workq_task_type @@ -345,6 +346,9 @@ struct cam_req_mgr_connected_device { * as part of shutdown. * @sof_timestamp_value : SOF timestamp value * @prev_sof_timestamp : Previous SOF timestamp value + * @dual_trigger : Links needs to wait for two triggers prior to + * applying the settings + * @trigger_cnt : trigger count value per device initiating the trigger */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -375,6 +379,9 @@ struct cam_req_mgr_core_link { bool is_shutdown; uint64_t sof_timestamp; uint64_t prev_sof_timestamp; + bool dual_trigger; + uint32_t trigger_cnt[CAM_REQ_MGR_MAX_TRIGGERS]; + }; /** diff --git a/drivers/cam_req_mgr/cam_req_mgr_interface.h b/drivers/cam_req_mgr/cam_req_mgr_interface.h index 5989ef13f5a7..899d8ed70cb0 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -204,13 +204,14 @@ enum cam_req_mgr_link_evt_type { /** * struct cam_req_mgr_trigger_notify - * @link_hdl : link identifier - * @dev_hdl : device handle which has sent this req id - * @frame_id : frame id for internal tracking - * @trigger : trigger point of this notification, CRM will send apply + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @frame_id : frame id for internal tracking + * @trigger : trigger point of this notification, CRM will send apply * only to the devices which subscribe to this point. * @sof_timestamp_val: Captured time stamp value at sof hw event - * @req_id : req id which returned buf_done + * @req_id : req id which returned buf_done + * @trigger_id: ID to differentiate between the trigger devices */ struct cam_req_mgr_trigger_notify { int32_t link_hdl; @@ -219,6 +220,7 @@ struct cam_req_mgr_trigger_notify { uint32_t trigger; uint64_t sof_timestamp_val; uint64_t req_id; + int32_t trigger_id; }; /** @@ -284,12 +286,12 @@ struct cam_req_mgr_notify_stop { /* CRM to KMD devices */ /** * struct cam_req_mgr_device_info - * @dev_hdl : Input_param : device handle for reference - * @name : link link or unlink - * @dev_id : device id info - * @p_delay : delay between time settings applied and take effect - * @trigger : Trigger point for the client - * + * @dev_hdl : Input_param : device handle for reference + * @name : link link or unlink + * @dev_id : device id info + * @p_delay : delay between time settings applied and take effect + * @trigger : Trigger point for the client + * @trigger_on : This device provides trigger */ struct cam_req_mgr_device_info { int32_t dev_hdl; @@ -297,6 +299,7 @@ struct cam_req_mgr_device_info { enum cam_req_mgr_device_id dev_id; enum cam_pipeline_delay p_delay; uint32_t trigger; + bool trigger_on; }; /** @@ -307,7 +310,7 @@ struct cam_req_mgr_device_info { * @max_delay : max pipeline delay on this link * @crm_cb : callback funcs to communicate with req mgr * @subscribe_event : the mask of trigger points this link subscribes - * + * @trigger_id : Unique ID provided to the triggering device */ struct cam_req_mgr_core_dev_link_setup { int32_t link_enable; @@ -316,6 +319,7 @@ struct cam_req_mgr_core_dev_link_setup { enum cam_pipeline_delay max_delay; struct cam_req_mgr_crm_cb *crm_cb; uint32_t subscribe_event; + int32_t trigger_id; }; /** -- GitLab From 1200da17c957205334b4739b84472f13e8727a37 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Wed, 4 Mar 2020 17:09:39 +0530 Subject: [PATCH 257/410] msm: camera: icp: Send error notification for camnoc recovery Handle firmware error HFI_ERR_SYS_RESET_FAILURE. On above error, notify UMD to do full recovery. CRs-Fixed: 2633629 Change-Id: I1e6379fdaf1d4238c9f448aaa138329158462afb Signed-off-by: Trishansh Bhardwaj --- drivers/cam_core/cam_context_utils.c | 1 + drivers/cam_core/cam_hw_mgr_intf.h | 2 ++ drivers/cam_icp/fw_inc/hfi_sys_defs.h | 1 + .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 32 ++++++++++++++++++- include/uapi/media/cam_req_mgr.h | 2 ++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 77e44591cdf2..ed091b6a0e7c 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -559,6 +559,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, param.event_cb = ctx->irq_cb_intf; param.num_acq = cmd->num_resources; param.acquire_info = cmd->resource_hdl; + param.session_hdl = cmd->session_handle; /* call HW manager to reserve the resource */ rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 422a47bf354a..2168146a30ca 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -99,6 +99,7 @@ struct cam_hw_done_event_data { * @context_data: Context data pointer for the callback function * @event_cb: Callback function array * @num_acq: Total number of acquire in the payload + * @session_hdl: Session Handle * @acquire_info: Acquired resource array pointer * @ctxt_to_hw_map: HW context (returned) * @custom_enabled: ctx has custom enabled @@ -114,6 +115,7 @@ struct cam_hw_acquire_args { void *context_data; cam_hw_event_cb_func event_cb; uint32_t num_acq; + uint32_t session_hdl; uint32_t acquire_info_size; uintptr_t acquire_info; void *ctxt_to_hw_map; diff --git a/drivers/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/cam_icp/fw_inc/hfi_sys_defs.h index f62e8cc99430..a197503e7413 100644 --- a/drivers/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/cam_icp/fw_inc/hfi_sys_defs.h @@ -36,6 +36,7 @@ #define HFI_ERR_SYS_UNSUPPORT_CMD (HFI_COMMON_BASE + 0x4) #define HFI_ERR_SYS_CMDFAILED (HFI_COMMON_BASE + 0x5) #define HFI_ERR_SYS_CMDSIZE (HFI_COMMON_BASE + 0x6) +#define HFI_ERR_SYS_RESET_FAILURE (HFI_COMMON_BASE + 0x7) /* System Level Event types */ #define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1) 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 70630d870224..4f331b6b0d42 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 @@ -19,6 +19,7 @@ #include #include #include +#include #include "cam_sync_api.h" #include "cam_packet_util.h" @@ -44,6 +45,7 @@ #include "cam_trace.h" #include "cam_cpas_api.h" #include "cam_common_util.h" +#include "cam_req_mgr_dev.h" #define ICP_WORKQ_TASK_CMD_TYPE 1 #define ICP_WORKQ_TASK_MSG_TYPE 2 @@ -2487,7 +2489,9 @@ static int cam_icp_mgr_process_fatal_error( struct cam_icp_hw_mgr *hw_mgr, uint32_t *msg_ptr) { struct hfi_msg_event_notify *event_notify; - int rc = 0; + int rc = 0, i = 0; + struct cam_req_mgr_message req_msg; + struct cam_acquire_dev_cmd *acq_cmd; CAM_DBG(CAM_ICP, "Enter"); @@ -2507,6 +2511,31 @@ static int cam_icp_mgr_process_fatal_error( if (event_notify->event_data1 == HFI_ERR_SYS_FATAL) { CAM_ERR(CAM_ICP, "received HFI_ERR_SYS_FATAL"); BUG(); + } else if (event_notify->event_data1 == + HFI_ERR_SYS_RESET_FAILURE) { + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + if (hw_mgr->ctx_data[i].state != + CAM_CTX_ACQUIRED) + continue; + + acq_cmd = &hw_mgr->ctx_data[i].acquire_dev_cmd; + CAM_INFO(CAM_ICP, + "Sending Full Recovery on sess %x", + acq_cmd->session_handle); + + req_msg.session_hdl = + acq_cmd->session_handle; + req_msg.u.err_msg.device_hdl = -1; + req_msg.u.err_msg.link_hdl = -1; + req_msg.u.err_msg.request_id = 0; + req_msg.u.err_msg.resource_size = 0x0; + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY; + cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, + V4L_EVENT_CAM_REQ_MGR_EVENT); + break; + } } rc = cam_icp_mgr_trigger_recovery(hw_mgr); cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); @@ -5601,6 +5630,7 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } ctx_data = &hw_mgr->ctx_data[ctx_id]; ctx_data->ctx_id = ctx_id; + ctx_data->acquire_dev_cmd.session_handle = args->session_hdl; mutex_lock(&ctx_data->ctx_mutex); rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data); diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 45f5fdcd0ad2..56223e99d8be 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -418,12 +418,14 @@ struct cam_mem_cache_ops_cmd { * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered * @CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE: SOF freeze, can be recovered + * @CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY: Full recovery, can be recovered */ #define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 #define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 #define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 #define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 #define CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE 4 +#define CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY 5 /** * struct cam_req_mgr_error_msg -- GitLab From 8783850987dd900120ad0ef4591b00c76a08e433 Mon Sep 17 00:00:00 2001 From: Mangalaram ARCHANA Date: Mon, 3 Feb 2020 17:45:14 +0530 Subject: [PATCH 258/410] msm: camera: ife: IFE debug enhancement for overflow debugging In many error cases it is required to know the bandwidth applied on axi ports and camnoc axi clock rate values. Added cpas api to print the current axi bus votes, camnoc axi clock and ahb vote level.This api can be called for isp errors such as bus overflow, pxl overflow cases. On RDI overflow printing last applied IFE clock, dumping the CAMNOC fill-level registers to know the pending and queued transactions, SOF EPOCH and EOF timing to know exactly at what time the RDI overflow came, Width and height of specific Write master. CRs-Fixed: 2623885 Change-Id: I92a9097efe9f6726748ec27ca39dd51c8c6de1b6 Signed-off-by: Mangalaram ARCHANA --- drivers/cam_cpas/cam_cpas_hw.c | 71 ++++++++++- drivers/cam_cpas/cam_cpas_hw.h | 6 + drivers/cam_cpas/cam_cpas_hw_intf.h | 3 +- drivers/cam_cpas/cam_cpas_intf.c | 26 +++- drivers/cam_cpas/include/cam_cpas_api.h | 10 ++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 76 +++++++++++- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 2 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h | 4 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 13 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 9 ++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 43 +++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 95 +++++++-------- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c | 72 ++++++++++- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 68 ++++++++++- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 67 +++++++++- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 68 ++++++++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 115 +++++++++++++++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h | 11 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 28 ++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 17 +++ 21 files changed, 731 insertions(+), 75 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 1747fbe83597..69debdee6845 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -83,7 +83,7 @@ static int cam_cpas_util_vote_bus_client_level( static int cam_cpas_util_vote_bus_client_bw( struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, - bool camnoc_bw) + bool camnoc_bw, uint64_t *applied_ab, uint64_t *applied_ib) { struct msm_bus_paths *path; struct msm_bus_scale_pdata *pdata; @@ -146,6 +146,10 @@ static int cam_cpas_util_vote_bus_client_bw( CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", bus_client->client_id, bus_client->name, ab, ib, idx); msm_bus_scale_client_update_request(bus_client->client_id, idx); + if (applied_ab) + *applied_ab = ab; + if (applied_ib) + *applied_ib = ib; return 0; } @@ -221,7 +225,8 @@ static int cam_cpas_util_unregister_bus_client( return -EINVAL; if (bus_client->dyn_vote) - cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); + cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false, + NULL, NULL); else cam_cpas_util_vote_bus_client_level(bus_client, 0); @@ -309,6 +314,7 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, int rc, i = 0; struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; uint64_t ab_bw, ib_bw; + uint64_t applied_ab_bw = 0, applied_ib_bw = 0; rc = cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, (enable == true) ? CAM_SVS_VOTE : CAM_SUSPEND_VOTE); @@ -329,13 +335,15 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, for (i = 0; i < cpas_core->num_axi_ports; i++) { rc = cam_cpas_util_vote_bus_client_bw( &cpas_core->axi_port[i].bus_client, - ab_bw, ib_bw, false); + ab_bw, ib_bw, false, &applied_ab_bw, &applied_ib_bw); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, rc=%d", enable, rc); goto remove_ahb_vote; } + cpas_core->axi_port[i].applied_ab_bw = applied_ab_bw; + cpas_core->axi_port[i].applied_ib_bw = applied_ib_bw; } return 0; @@ -494,6 +502,8 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); + + cpas_core->applied_camnoc_axi_rate = clk_rate; } } @@ -675,6 +685,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( int rc = 0; struct cam_cpas_axi_port *camnoc_axi_port = NULL; uint64_t camnoc_bw; + uint64_t applied_ab = 0, applied_ib = 0; if (soc_private->control_camnoc_axi_clk) { rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); @@ -711,7 +722,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( rc = cam_cpas_util_vote_bus_client_bw( &camnoc_axi_port->bus_client, - 0, camnoc_bw, true); + 0, camnoc_bw, true, &applied_ab, &applied_ib); CAM_DBG(CAM_CPAS, "camnoc vote camnoc_bw[%llu] rc=%d %s", @@ -722,6 +733,8 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( camnoc_bw, rc); break; } + camnoc_axi_port->applied_ab_bw = applied_ab; + camnoc_axi_port->applied_ib_bw = applied_ib; } return rc; } @@ -744,6 +757,7 @@ static int cam_cpas_util_apply_client_axi_vote( curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; int rc = 0, i = 0; + uint64_t applied_ab = 0, applied_ib = 0; mutex_lock(&cpas_core->tree_lock); if (!cpas_client->tree_node_valid) { @@ -899,13 +913,16 @@ static int cam_cpas_util_apply_client_axi_vote( rc = cam_cpas_util_vote_bus_client_bw( &mnoc_axi_port->bus_client, - mnoc_ab_bw, mnoc_ib_bw, false); + mnoc_ab_bw, mnoc_ib_bw, false, &applied_ab, + &applied_ib); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", mnoc_ab_bw, mnoc_ib_bw, rc); goto unlock_tree; } + mnoc_axi_port->applied_ab_bw = applied_ab; + mnoc_axi_port->applied_ib_bw = applied_ib; } rc = cam_cpas_camnoc_set_vote_axi_clk_rate( cpas_hw, camnoc_axi_port_updated); @@ -1652,6 +1669,46 @@ static int cam_cpas_hw_get_hw_info(void *hw_priv, return 0; } +static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + int rc = 0; + uint32_t i; + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + CAM_INFO(CAM_CPAS, + "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", + cpas_core->axi_port[i].axi_port_name, + cpas_core->axi_port[i].ab_bw, + cpas_core->axi_port[i].ib_bw, + cpas_core->axi_port[i].additional_bw, + cpas_core->axi_port[i].applied_ab_bw, + cpas_core->axi_port[i].applied_ib_bw); + } + + if (soc_private->control_camnoc_axi_clk) { + CAM_INFO(CAM_CPAS, "applied camnoc axi clk[%lld]", + cpas_core->applied_camnoc_axi_rate); + } else { + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + CAM_INFO(CAM_CPAS, + "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", + cpas_core->camnoc_axi_port[i].axi_port_name, + cpas_core->camnoc_axi_port[i].ab_bw, + cpas_core->camnoc_axi_port[i].ib_bw, + cpas_core->camnoc_axi_port[i].additional_bw, + cpas_core->camnoc_axi_port[i].applied_ab_bw, + cpas_core->camnoc_axi_port[i].applied_ib_bw); + } + } + + CAM_INFO(CAM_CPAS, "ahb client curr vote level[%d]", + cpas_core->ahb_bus_client.curr_vote_level); + + return rc; +} static int cam_cpas_hw_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -1755,6 +1812,10 @@ static int cam_cpas_hw_process_cmd(void *hw_priv, cmd_axi_vote->client_handle, cmd_axi_vote->axi_vote); break; } + case CAM_CPAS_HW_CMD_LOG_VOTE: { + rc = cam_cpas_log_vote(hw_priv); + break; + } default: CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type); break; diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index cfa7dfbb69b2..acad4ba44b17 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -155,6 +155,8 @@ struct cam_cpas_bus_client { * @ib_bw: IB bw value for this port * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients + * @applied_ab_bw: applied ab bw for this port + * @applied_ib_bw: applied ib bw for this port */ struct cam_cpas_axi_port { const char *axi_port_name; @@ -165,6 +167,8 @@ struct cam_cpas_axi_port { uint64_t ib_bw; uint64_t camnoc_bw; uint64_t additional_bw; + uint64_t applied_ab_bw; + uint64_t applied_ib_bw; }; /** @@ -189,6 +193,7 @@ struct cam_cpas_axi_port { * @irq_count_wq: wait variable to ensure all irq's are handled * @dentry: debugfs file entry * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus + * @applied_camnoc_axi_rate: applied camnoc axi clock rate */ struct cam_cpas { struct cam_cpas_hw_caps hw_caps; @@ -210,6 +215,7 @@ struct cam_cpas { wait_queue_head_t irq_count_wq; struct dentry *dentry; bool ahb_bus_scaling_disable; + uint64_t applied_camnoc_axi_rate; }; int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); diff --git a/drivers/cam_cpas/cam_cpas_hw_intf.h b/drivers/cam_cpas/cam_cpas_hw_intf.h index 0926e6e3d8d1..3f644363062c 100644 --- a/drivers/cam_cpas/cam_cpas_hw_intf.h +++ b/drivers/cam_cpas/cam_cpas_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_HW_INTF_H_ @@ -38,6 +38,7 @@ enum cam_cpas_hw_cmd_process { CAM_CPAS_HW_CMD_REG_READ, CAM_CPAS_HW_CMD_AHB_VOTE, CAM_CPAS_HW_CMD_AXI_VOTE, + CAM_CPAS_HW_CMD_LOG_VOTE, CAM_CPAS_HW_CMD_INVALID, }; diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index a1d8b4026059..d63ac2263355 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -392,6 +392,30 @@ int cam_cpas_start(uint32_t client_handle, } EXPORT_SYMBOL(cam_cpas_start); +void cam_cpas_log_votes(void) +{ + uint32_t dummy_args; + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args, + sizeof(dummy_args)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + } + +} +EXPORT_SYMBOL(cam_cpas_log_votes); + int cam_cpas_unregister_client(uint32_t client_handle) { int rc; diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 6bb226377056..bc9aca5cb295 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -617,5 +617,15 @@ const char *cam_cpas_axi_util_path_type_to_string( const char *cam_cpas_axi_util_trans_type_to_string( uint32_t path_data_type); +/** + * cam_cpas_log_votes() + * + * @brief: API to print the all bw votes of axi client. It also print the + * applied camnoc axi clock vote value and ahb vote value + * + * @return 0 on success. + * + */ +void cam_cpas_log_votes(void); #endif /* _CAM_CPAS_API_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 20b08740d2ec..a015106b3a97 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6727,15 +6727,87 @@ static int cam_ife_hw_mgr_find_affected_ctx( return 0; } +static int cam_ife_hw_mgr_handle_hw_dump_info( + void *ctx, + void *evt_info) +{ + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = + (struct cam_ife_hw_mgr_ctx *)ctx; + struct cam_isp_hw_event_info *event_info = + (struct cam_isp_hw_event_info *)evt_info; + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_hw_intf *hw_intf; + uint32_t i, out_port_id; + int rc = 0; + + list_for_each_entry(hw_mgr_res, + &ife_hw_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF) { + hw_intf = rsrc_node->hw_intf; + if (hw_intf && + hw_intf->hw_ops.process_cmd) + rc = + hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CAMIF_DATA, + rsrc_node, + sizeof( + struct + cam_isp_resource_node)); + } + } + } + + + out_port_id = event_info->res_id & 0xFF; + hw_mgr_res = + &ife_hw_mgr_ctx->res_list_ife_out[out_port_id]; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_BUS_INFO, + (void *)event_info, + sizeof(struct cam_isp_hw_event_info)); + } + } + + return rc; +} + static int cam_ife_hw_mgr_handle_hw_err( + void *ctx, void *evt_info) { + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx; struct cam_isp_hw_event_info *event_info = evt_info; - uint32_t core_idx; + uint32_t core_idx; struct cam_isp_hw_error_event_data error_event_data = {0}; struct cam_hw_event_recovery_data recovery_data = {0}; int rc = -EINVAL; + if (ctx) { + ife_hw_mgr_ctx = + (struct cam_ife_hw_mgr_ctx *)ctx; + if (event_info->res_type == + CAM_ISP_RESOURCE_VFE_IN && + !ife_hw_mgr_ctx->is_rdi_only_context && + event_info->res_id != + CAM_ISP_HW_VFE_IN_CAMIF) + cam_ife_hw_mgr_handle_hw_dump_info( + ife_hw_mgr_ctx, event_info); + } + if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) error_event_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_IN) @@ -7112,7 +7184,7 @@ static int cam_ife_hw_mgr_event_handler( break; case CAM_ISP_HW_EVENT_ERROR: - rc = cam_ife_hw_mgr_handle_hw_err(evt_info); + rc = cam_ife_hw_mgr_handle_hw_err(priv, evt_info); break; default: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index fc6951b2fa1e..5ab4478408e6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -94,8 +94,10 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, CAM_ISP_HW_CMD_UBWC_UPDATE, + CAM_ISP_HW_CMD_DUMP_BUS_INFO, CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, + CAM_ISP_HW_CMD_CAMIF_DATA, CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index cd32edbc0565..fb7c4309bff7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -594,6 +594,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CORE_CONFIG: case CAM_ISP_HW_CMD_BW_UPDATE_V2: case CAM_ISP_HW_CMD_DUMP_HW: + case CAM_ISP_HW_CMD_CAMIF_DATA: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); @@ -605,6 +606,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_UBWC_UPDATE: case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + case CAM_ISP_HW_CMD_DUMP_BUS_INFO: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h index 64d9de084ec1..eef02079628a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_SOC_H_ @@ -24,6 +24,7 @@ * @cpas_version: Has cpas version read from Hardware * @ubwc_static_ctrl: UBWC static control configuration * @is_ife_lite: Flag to indicate full vs lite IFE + * @ife_clk_src: IFE source clock */ struct cam_vfe_soc_private { uint32_t cpas_handle; @@ -33,6 +34,7 @@ struct cam_vfe_soc_private { int32_t dsp_clk_rate; uint32_t ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX]; bool is_ife_lite; + uint64_t ife_clk_src; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 63df625221cc..a65d7aa966fd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -170,6 +170,14 @@ struct cam_vfe_top_dump_data vfe170_dump_data = { }, }; +static struct cam_vfe_rdi_overflow_status vfe170_rdi_irq_status = { + .rdi0_overflow_mask = 0x8, + .rdi1_overflow_mask = 0x10, + .rdi2_overflow_mask = 0x18, + .rdi3_overflow_mask = 0x20, + .rdi_overflow_mask = 0x3c, +}; + static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .common_reg = &vfe170_top_common_reg, .camif_hw_info = { @@ -183,8 +191,9 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .reg_data = NULL, }, .rdi_hw_info = { - .common_reg = &vfe170_top_common_reg, - .rdi_reg = &vfe170_rdi_reg, + .common_reg = &vfe170_top_common_reg, + .rdi_reg = &vfe170_rdi_reg, + .rdi_irq_status = &vfe170_rdi_irq_status, .reg_data = { &vfe_170_rdi_0_data, &vfe_170_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 946ac2267d95..c5f08440fa20 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -27,6 +27,14 @@ static struct cam_irq_register_set vfe175_130_top_irq_reg_set[2] = { }, }; +static struct cam_vfe_rdi_overflow_status vfe175_130_rdi_irq_status = { + .rdi0_overflow_mask = 0x8, + .rdi1_overflow_mask = 0x10, + .rdi2_overflow_mask = 0x18, + .rdi3_overflow_mask = 0x20, + .rdi_overflow_mask = 0x3c, +}; + static struct cam_irq_controller_reg_info vfe175_130_top_irq_reg_info = { .num_registers = 2, .irq_reg_set = vfe175_130_top_irq_reg_set, @@ -268,6 +276,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { .common_reg = &vfe175_130_top_common_reg, .rdi_reg = &vfe175_130_rdi_reg, .common_reg_data = &vfe175_130_rdi_reg_data, + .rdi_irq_status = &vfe175_130_rdi_irq_status, .reg_data = { &vfe_175_130_rdi_0_data, &vfe_175_130_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 92f0e700a485..3d5835c87029 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -140,6 +140,8 @@ struct cam_vfe_bus_ver2_wm_resource_data { uint32_t ubwc_lossy_threshold_0; uint32_t ubwc_lossy_threshold_1; uint32_t ubwc_bandwidth_limit; + uint32_t acquired_width; + uint32_t acquired_height; }; struct cam_vfe_bus_ver2_comp_grp_data { @@ -983,6 +985,8 @@ static int cam_vfe_bus_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; + rsrc_data->acquired_width = out_port_info->width; + rsrc_data->acquired_height = out_port_info->height; rsrc_data->is_dual = is_dual; /* Set WM offset value to default */ rsrc_data->offset = 0; @@ -3532,6 +3536,42 @@ static int __cam_vfe_bus_process_cmd(void *priv, return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); } +int cam_vfe_bus_dump_wm_data(void *priv, void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv = + (struct cam_vfe_bus_ver2_priv *) priv; + struct cam_isp_hw_event_info *event_info = + (struct cam_isp_hw_event_info *)cmd_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + int i, wm_idx; + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id; + + vfe_out_res_id = cam_vfe_bus_get_out_res_id(event_info->res_id); + rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; + rsrc_data = rsrc_node->res_priv; + for (i = 0; i < rsrc_data->num_wm; i++) { + wm_idx = cam_vfe_bus_get_wm_idx(vfe_out_res_id, i); + if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d", + vfe_out_res_id); + return -EINVAL; + } + wm_data = bus_priv->bus_client[wm_idx].res_priv; + CAM_INFO(CAM_ISP, + "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", + wm_data->common_data->core_index, wm_idx, + wm_data->width, + wm_data->height, + wm_data->stride, wm_data->h_init, + wm_data->en_cfg, + wm_data->acquired_width, + wm_data->acquired_height); + } + return 0; +} + static int cam_vfe_bus_process_cmd( struct cam_isp_resource_node *priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -3570,6 +3610,9 @@ static int cam_vfe_bus_process_cmd( case CAM_ISP_HW_CMD_UBWC_UPDATE: rc = cam_vfe_bus_update_ubwc_config(cmd_args); break; + case CAM_ISP_HW_CMD_DUMP_BUS_INFO: + rc = cam_vfe_bus_dump_wm_data(priv, cmd_args, arg_size); + break; case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: rc = cam_vfe_bus_update_ubwc_config_v2(cmd_args); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 017ad12e9dd7..1b108e51e5a1 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -128,6 +128,8 @@ struct cam_vfe_bus_ver3_wm_resource_data { uint32_t ubwc_lossy_threshold_1; uint32_t ubwc_offset_lossy_variance; uint32_t ubwc_bandwidth_limit; + uint32_t acquired_width; + uint32_t acquired_height; }; struct cam_vfe_bus_ver3_comp_grp_data { @@ -1130,6 +1132,8 @@ static int cam_vfe_bus_ver3_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; + rsrc_data->acquired_width = out_port_info->width; + rsrc_data->acquired_height = out_port_info->height; rsrc_data->is_dual = is_dual; /* Set WM offset value to default */ rsrc_data->offset = 0; @@ -2444,34 +2448,37 @@ static int cam_vfe_bus_ver3_deinit_vfe_out_resource( return 0; } -static void cam_vfe_bus_ver3_print_dimensions( +static int cam_vfe_bus_ver3_print_dimensions( enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, - enum cam_vfe_bus_plane_type plane, struct cam_vfe_bus_ver3_priv *bus_priv) { - struct cam_isp_resource_node *wm_res = NULL; - struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; - int wm_idx = 0; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + int i, wm_idx; - wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, plane, - bus_priv->common_data.is_lite); - - if (wm_idx < 0 || wm_idx >= bus_priv->num_client || plane > PLANE_C) { - CAM_ERR(CAM_ISP, - "Unsupported VFE out_type:0x%X plane:%d wm_idx:%d max_idx:%d", - vfe_out_res_id, plane, wm_idx, - bus_priv->num_client - 1); - return; + rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; + rsrc_data = rsrc_node->res_priv; + for (i = 0; i < rsrc_data->num_wm; i++) { + wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, i, + bus_priv->common_data.is_lite); + if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d", + vfe_out_res_id); + return -EINVAL; + } + wm_data = bus_priv->bus_client[wm_idx].res_priv; + CAM_INFO(CAM_ISP, + "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", + wm_data->common_data->core_index, wm_idx, + wm_data->width, + wm_data->height, + wm_data->stride, wm_data->h_init, + wm_data->en_cfg, + wm_data->acquired_width, + wm_data->acquired_height); } - - wm_res = &bus_priv->bus_client[wm_idx]; - wm_data = wm_res->res_priv; - - CAM_INFO(CAM_ISP, - "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u", - wm_data->common_data->core_index, wm_idx, wm_data->width, - wm_data->height, wm_data->stride, wm_data->h_init, - wm_data->en_cfg); + return 0; } static int cam_vfe_bus_ver3_handle_bus_irq(uint32_t evt_id, @@ -2577,7 +2584,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 0 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI0, - PLANE_Y, bus_priv); } @@ -2586,7 +2592,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI1, - PLANE_Y, bus_priv); } @@ -2595,7 +2600,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 2 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI2, - PLANE_Y, bus_priv); } @@ -2604,7 +2608,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 3 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI3, - PLANE_Y, bus_priv); } } @@ -2639,7 +2642,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID Y 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL, - PLANE_Y, bus_priv); } @@ -2647,7 +2649,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID C 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL, - PLANE_C, bus_priv); } @@ -2655,7 +2656,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID YC 4:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS4, - PLANE_Y, bus_priv); } @@ -2663,7 +2663,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID YC 16:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS16, - PLANE_Y, bus_priv); } @@ -2671,7 +2670,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP Y 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, - PLANE_Y, bus_priv); } @@ -2679,7 +2677,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP C 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, - PLANE_C, bus_priv); } @@ -2687,7 +2684,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP YC 4:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, - PLANE_Y, bus_priv); } @@ -2695,7 +2691,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP YC 16:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, - PLANE_Y, bus_priv); } @@ -2703,7 +2698,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "FD Y image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FD, - PLANE_Y, bus_priv); } @@ -2711,7 +2705,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "FD C image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FD, - PLANE_C, bus_priv); } @@ -2720,7 +2713,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "PIXEL RAW DUMP image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, - PLANE_Y, bus_priv); } @@ -2728,7 +2720,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS HDR BE image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, - PLANE_Y, bus_priv); } @@ -2737,7 +2728,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "STATS HDR BHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, - PLANE_Y, bus_priv); } @@ -2746,7 +2736,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "STATS TINTLESS BG image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, - PLANE_Y, bus_priv); } @@ -2754,7 +2743,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS AWB BG image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, - PLANE_Y, bus_priv); } @@ -2762,7 +2750,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS BHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, - PLANE_Y, bus_priv); } @@ -2770,7 +2757,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS RS image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, - PLANE_Y, bus_priv); } @@ -2778,7 +2764,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS CS image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, - PLANE_Y, bus_priv); } @@ -2786,7 +2771,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS IHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, - PLANE_Y, bus_priv); } @@ -2794,7 +2778,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS BAF image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, - PLANE_Y, bus_priv); } @@ -2802,7 +2785,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "PD image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_2PD, - PLANE_Y, bus_priv); } @@ -2810,7 +2792,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "LCR image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_LCR, - PLANE_Y, bus_priv); } @@ -2818,7 +2799,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 0 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI0, - PLANE_Y, bus_priv); } @@ -2826,7 +2806,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI1, - PLANE_Y, bus_priv); } @@ -2834,7 +2813,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 2 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI2, - PLANE_Y, bus_priv); } @@ -3740,6 +3718,19 @@ static int cam_vfe_bus_ver3_process_cmd( bus_priv->error_irq_handle = 0; } break; + case CAM_ISP_HW_CMD_DUMP_BUS_INFO: { + struct cam_isp_hw_event_info *event_info; + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id; + + event_info = + (struct cam_isp_hw_event_info *)cmd_args; + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + vfe_out_res_id = + cam_vfe_bus_ver3_get_out_res_id(event_info->res_id); + rc = cam_vfe_bus_ver3_print_dimensions( + vfe_out_res_id, bus_priv); + break; + } case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: rc = cam_vfe_bus_ver3_update_ubwc_config_v2(cmd_args); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c index 9ea8d74a35ca..e4ff7255df5b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -36,6 +36,7 @@ struct cam_vfe_mux_camif_lite_data { evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; struct list_head free_payload_list; spinlock_t spin_lock; + struct timeval error_ts; }; static int cam_vfe_camif_lite_get_evt_payload( @@ -133,6 +134,12 @@ static int cam_vfe_camif_lite_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_lite_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_lite_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -301,6 +308,9 @@ static int cam_vfe_camif_lite_resource_start( } } + rsrc_data->error_ts.tv_sec = 0; + rsrc_data->error_ts.tv_usec = 0; + CAM_DBG(CAM_ISP, "Start Camif Lite IFE %d Done", camif_lite_res->hw_intf->hw_idx); return rc; @@ -405,6 +415,44 @@ static int cam_vfe_camif_lite_handle_irq_top_half(uint32_t evt_id, return rc; } +static int cam_vfe_camif_lite_cpas_fifo_levels_reg_dump( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv) +{ + struct cam_vfe_soc_private *soc_private = + camif_lite_priv->soc_info->soc_private; + uint32_t val; + + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || + soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_INFO(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + + } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } + + return 0; + +} + static int cam_vfe_camif_lite_handle_irq_bottom_half( void *handler_priv, void *evt_payload_priv) @@ -416,6 +464,9 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( struct cam_isp_hw_event_info evt_info; uint32_t irq_status0; uint32_t irq_status1; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -427,6 +478,9 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( payload = evt_payload_priv; irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + soc_info = camif_lite_priv->soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; evt_info.hw_idx = camif_lite_node->hw_intf->hw_idx; evt_info.res_id = camif_lite_node->res_id; @@ -464,11 +518,27 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE Received ERROR", evt_info.hw_idx); + cam_vfe_camif_lite_cpas_fifo_levels_reg_dump(camif_lite_priv); + + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + CAM_INFO(CAM_ISP, + "ERROR time %lld:%lld", + camif_lite_priv->error_ts.tv_sec, + camif_lite_priv->error_ts.tv_usec); + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + cam_cpas_log_votes(); + } cam_vfe_camif_lite_put_evt_payload(camif_lite_priv, &payload); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index bfb17d2145f8..b54c43a145bc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include @@ -40,6 +40,10 @@ struct cam_vfe_mux_camif_lite_data { uint32_t camif_debug; struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; + struct timeval sof_ts; + struct timeval epoch_ts; + struct timeval eof_ts; + struct timeval error_ts; }; static int cam_vfe_camif_lite_get_evt_payload( @@ -137,6 +141,12 @@ static int cam_vfe_camif_lite_err_irq_top_half( return rc; cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_lite_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_lite_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -293,6 +303,15 @@ static int cam_vfe_camif_lite_resource_start( rsrc_data->mem_base + rsrc_data->camif_lite_reg->lite_epoch_irq); + rsrc_data->error_ts.tv_sec = 0; + rsrc_data->error_ts.tv_usec = 0; + rsrc_data->sof_ts.tv_sec = 0; + rsrc_data->sof_ts.tv_usec = 0; + rsrc_data->epoch_ts.tv_sec = 0; + rsrc_data->epoch_ts.tv_usec = 0; + rsrc_data->eof_ts.tv_sec = 0; + rsrc_data->eof_ts.tv_usec = 0; + skip_core_cfg: camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; @@ -888,6 +907,7 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); + cam_cpas_log_votes(); } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { @@ -1062,6 +1082,8 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( struct cam_vfe_soc_private *soc_private = NULL; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; int i = 0; + uint32_t status_0 = 0; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -1097,6 +1119,10 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received SOF", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; + camif_lite_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_lite_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, @@ -1108,6 +1134,10 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EPOCH", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; + camif_lite_priv->epoch_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_lite_priv->epoch_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, @@ -1119,18 +1149,50 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EOF", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; + camif_lite_priv->eof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_lite_priv->eof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); } - if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] - & camif_lite_priv->reg_data->error_irq_mask0) { + status_0 = irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_lite_priv->reg_data->error_irq_mask0; + if (status_0) { CAM_ERR(CAM_ISP, "VFE:%d Overflow", camif_lite_node->hw_intf->hw_idx); evt_info.err_type = CAM_VFE_IRQ_STATUS_OVERFLOW; + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + CAM_INFO(CAM_ISP, + "ERROR time %lld:%lld", + camif_lite_priv->error_ts.tv_sec, + camif_lite_priv->error_ts.tv_usec); + + if (camif_lite_node->rdi_only_ctx) + CAM_INFO(CAM_ISP, + "SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_lite_priv->sof_ts.tv_sec, + camif_lite_priv->sof_ts.tv_usec, + camif_lite_priv->epoch_ts.tv_sec, + camif_lite_priv->epoch_ts.tv_usec, + camif_lite_priv->eof_ts.tv_sec, + camif_lite_priv->eof_ts.tv_usec); + + if (status_0 & 0x8000000) + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_2; + + if (status_0 & 0x10000000) + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (status_0 & 0x20000000) + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_0; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 23cf5d1642f4..3f9a94aece9f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -50,6 +50,10 @@ struct cam_vfe_mux_camif_data { uint32_t camif_debug; uint32_t dual_hw_idx; uint32_t is_dual; + struct timeval sof_ts; + struct timeval epoch_ts; + struct timeval eof_ts; + struct timeval error_ts; }; static int cam_vfe_camif_get_evt_payload( @@ -144,6 +148,12 @@ static int cam_vfe_camif_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -293,6 +303,14 @@ static int cam_vfe_camif_resource_init( if (rc) CAM_ERR(CAM_ISP, "failed to enable dsp clk"); } + camif_data->sof_ts.tv_sec = 0; + camif_data->sof_ts.tv_usec = 0; + camif_data->epoch_ts.tv_sec = 0; + camif_data->epoch_ts.tv_usec = 0; + camif_data->eof_ts.tv_sec = 0; + camif_data->eof_ts.tv_usec = 0; + camif_data->error_ts.tv_sec = 0; + camif_data->error_ts.tv_usec = 0; return rc; } @@ -626,6 +644,26 @@ static int cam_vfe_camif_sof_irq_debug( return 0; } +int cam_vfe_camif_dump_timestamps( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_data *camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + + CAM_INFO(CAM_ISP, + "CAMIF ERROR time %lld:%lld SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->error_ts.tv_sec, + camif_priv->error_ts.tv_usec, + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); + + return 0; +} + static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -650,6 +688,9 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; camif_priv->camif_debug = *((uint32_t *)cmd_args); break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_camif_dump_timestamps(rsrc_node, cmd_args); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -705,6 +746,7 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, uint32_t irq_status0; uint32_t irq_status1; uint32_t val; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -726,6 +768,10 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { CAM_DBG(CAM_ISP, "Received EOF"); + camif_priv->eof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->eof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -747,8 +793,13 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, false; camif_priv->irq_debug_cnt = 0; } - } else + } else { CAM_DBG(CAM_ISP, "Received SOF"); + camif_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; + } if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -769,6 +820,10 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "Received EPOCH"); + camif_priv->epoch_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->epoch_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -780,6 +835,11 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->error_irq_mask0) { CAM_DBG(CAM_ISP, "Received ERROR"); + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); @@ -795,6 +855,11 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { CAM_DBG(CAM_ISP, "Received ERROR"); + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index fd7aaaf27cde..de4299a47034 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -55,6 +55,10 @@ struct cam_vfe_mux_camif_ver3_data { uint32_t qcfa_bin; bool is_fe_enabled; bool is_offline; + struct timeval sof_ts; + struct timeval epoch_ts; + struct timeval eof_ts; + struct timeval error_ts; }; static int cam_vfe_camif_ver3_get_evt_payload( @@ -140,6 +144,12 @@ static int cam_vfe_camif_ver3_err_irq_top_half( return rc; cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -296,6 +306,14 @@ static int cam_vfe_camif_ver3_resource_init( CAM_ERR(CAM_ISP, "failed to enable dsp clk, rc = %d", rc); } + camif_data->sof_ts.tv_sec = 0; + camif_data->sof_ts.tv_usec = 0; + camif_data->epoch_ts.tv_sec = 0; + camif_data->epoch_ts.tv_usec = 0; + camif_data->eof_ts.tv_sec = 0; + camif_data->eof_ts.tv_usec = 0; + camif_data->error_ts.tv_sec = 0; + camif_data->error_ts.tv_usec = 0; return rc; } @@ -746,6 +764,26 @@ static int cam_vfe_camif_ver3_sof_irq_debug( return 0; } +int cam_vfe_camif_ver3_dump_timestamps( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv = + (struct cam_vfe_mux_camif_ver3_data *)rsrc_node->res_priv; + + CAM_INFO(CAM_ISP, + "CAMIF ERROR time %lld:%lld SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->error_ts.tv_sec, + camif_priv->error_ts.tv_usec, + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); + + return 0; +} + static int cam_vfe_camif_ver3_process_cmd( struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -782,6 +820,9 @@ static int cam_vfe_camif_ver3_process_cmd( *((struct cam_hw_soc_info **)cmd_args) = camif_priv->soc_info; rc = 0; break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_camif_ver3_dump_timestamps(rsrc_node, cmd_args); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -943,6 +984,7 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); + cam_cpas_log_votes(); return; } @@ -1254,6 +1296,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; + struct timespec64 ts; uint32_t val = 0; int i = 0; @@ -1291,9 +1334,14 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, false; camif_priv->irq_debug_cnt = 0; } - } else + } else { CAM_DBG(CAM_ISP, "VFE:%d Received SOF", evt_info.hw_idx); + camif_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; + } if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1306,6 +1354,10 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); evt_info.th_reg_val = payload->th_reg_val; + camif_priv->epoch_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->epoch_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1317,6 +1369,10 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->eof_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EOF", evt_info.hw_idx); + camif_priv->eof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->eof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1329,6 +1385,11 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, & camif_priv->reg_data->error_irq_mask0) { CAM_ERR(CAM_ISP, "VFE:%d Overflow", evt_info.hw_idx); + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); @@ -1353,6 +1414,11 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index a0e7741e5505..b766c1ee844b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -21,7 +21,9 @@ struct cam_vfe_mux_rdi_data { struct cam_vfe_top_ver2_reg_offset_common *common_reg; struct cam_vfe_rdi_ver2_reg *rdi_reg; struct cam_vfe_rdi_common_reg_data *rdi_common_reg_data; + struct cam_vfe_rdi_overflow_status *rdi_irq_status; struct cam_vfe_rdi_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; cam_hw_mgr_event_cb_func event_cb; void *priv; @@ -33,6 +35,8 @@ struct cam_vfe_mux_rdi_data { spinlock_t spin_lock; enum cam_isp_hw_sync_mode sync_mode; + struct timeval sof_ts; + struct timeval error_ts; }; static int cam_vfe_rdi_get_evt_payload( @@ -81,6 +85,44 @@ static int cam_vfe_rdi_put_evt_payload( return 0; } +static int cam_vfe_rdi_cpas_reg_dump( +struct cam_vfe_mux_rdi_data *rdi_priv) +{ + struct cam_vfe_soc_private *soc_private = + rdi_priv->soc_info->soc_private; + uint32_t val; + + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || + soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_INFO(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + + } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } + + return 0; + +} + static int cam_vfe_rdi_err_irq_top_half( uint32_t evt_id, struct cam_irq_th_payload *th_payload) @@ -124,6 +166,12 @@ static int cam_vfe_rdi_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + rdi_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + rdi_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -282,6 +330,11 @@ static int cam_vfe_rdi_resource_start( } } + rsrc_data->sof_ts.tv_sec = 0; + rsrc_data->sof_ts.tv_usec = 0; + rsrc_data->error_ts.tv_sec = 0; + rsrc_data->error_ts.tv_usec = 0; + CAM_DBG(CAM_ISP, "Start RDI %d", rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0); end: @@ -392,6 +445,11 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status0; + uint32_t irq_status1; + uint32_t irq_rdi_status; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -401,8 +459,12 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, rdi_node = handler_priv; rdi_priv = rdi_node->res_priv; payload = evt_payload_priv; + soc_info = rdi_priv->soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; evt_info.hw_idx = rdi_node->hw_intf->hw_idx; evt_info.res_id = rdi_node->res_id; @@ -412,7 +474,10 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & rdi_priv->reg_data->sof_irq_mask) { CAM_DBG(CAM_ISP, "Received SOF"); - + rdi_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + rdi_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (rdi_priv->event_cb) rdi_priv->event_cb(rdi_priv->priv, CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); @@ -430,6 +495,50 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_SUCCESS; } + irq_rdi_status = + (irq_status1 & + rdi_priv->rdi_irq_status->rdi_overflow_mask); + if (irq_rdi_status) { + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + + cam_vfe_rdi_cpas_reg_dump(rdi_priv); + + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + CAM_INFO(CAM_ISP, + "ERROR time %lld:%lld SOF %lld:%lld", + rdi_priv->error_ts.tv_sec, + rdi_priv->error_ts.tv_usec, + rdi_priv->sof_ts.tv_sec, + rdi_priv->sof_ts.tv_usec); + + if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi0_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_0; + } + else if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi1_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_1; + } + else if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi2_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_2; + } + else if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi3_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_3; + } + + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_ERROR, + (void *)&evt_info); + cam_cpas_log_votes(); + } + cam_vfe_rdi_put_evt_payload(rdi_priv, &payload); CAM_DBG(CAM_ISP, "returing status = %d", ret); return ret; @@ -461,6 +570,8 @@ int cam_vfe_rdi_ver2_init( rdi_priv->rdi_reg = rdi_info->rdi_reg; rdi_priv->vfe_irq_controller = vfe_irq_controller; rdi_priv->rdi_common_reg_data = rdi_info->common_reg_data; + rdi_priv->soc_info = soc_info; + rdi_priv->rdi_irq_status = rdi_info->rdi_irq_status; switch (rdi_node->res_id) { case CAM_ISP_HW_VFE_IN_RDI0: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h index c570e84a011c..70a2cb756cea 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_RDI_H_ @@ -17,6 +17,14 @@ struct cam_vfe_rdi_ver2_reg { uint32_t reg_update_cmd; }; +struct cam_vfe_rdi_overflow_status { + uint32_t rdi0_overflow_mask; + uint32_t rdi1_overflow_mask; + uint32_t rdi2_overflow_mask; + uint32_t rdi3_overflow_mask; + uint32_t rdi_overflow_mask; +}; + struct cam_vfe_rdi_common_reg_data { uint32_t subscribe_irq_mask0; uint32_t subscribe_irq_mask1; @@ -35,6 +43,7 @@ struct cam_vfe_rdi_ver2_hw_info { struct cam_vfe_top_ver2_reg_offset_common *common_reg; struct cam_vfe_rdi_ver2_reg *rdi_reg; struct cam_vfe_rdi_common_reg_data *common_reg_data; + struct cam_vfe_rdi_overflow_status *rdi_irq_status; struct cam_vfe_rdi_reg_data *reg_data[CAM_VFE_RDI_VER2_MAX]; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 6774be8cda3d..753c94ea1878 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -83,8 +83,11 @@ static int cam_vfe_top_set_hw_clk_rate( struct cam_hw_soc_info *soc_info = NULL; int i, rc = 0; unsigned long max_clk_rate = 0; + struct cam_vfe_soc_private *soc_private = NULL; soc_info = top_priv->common_data.soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; for (i = 0; i < top_priv->top_common.num_mux; i++) { if (top_priv->req_clk_rate[i] > max_clk_rate) @@ -96,7 +99,7 @@ static int cam_vfe_top_set_hw_clk_rate( CAM_DBG(CAM_PERF, "VFE: Clock name=%s idx=%d clk=%llu", soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); - + soc_private->ife_clk_src = max_clk_rate; rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); if (!rc) @@ -179,6 +182,19 @@ static int cam_vfe_top_mux_get_reg_update( return -EINVAL; } +static int cam_vfe_top_get_data( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_resource_node *res = cmd_args; + + if (res->process_cmd) + return res->process_cmd(res, + CAM_ISP_HW_CMD_CAMIF_DATA, cmd_args, arg_size); + + return -EINVAL; +} + int cam_vfe_top_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -536,6 +552,8 @@ int cam_vfe_top_stop(void *device_priv, struct cam_vfe_top_ver2_priv *top_priv; struct cam_isp_resource_node *mux_res; struct cam_hw_info *hw_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; int i, rc = 0; if (!device_priv || !stop_args) { @@ -546,6 +564,8 @@ int cam_vfe_top_stop(void *device_priv, top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; mux_res = (struct cam_isp_resource_node *)stop_args; hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; if ((mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || (mux_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) || @@ -576,7 +596,7 @@ int cam_vfe_top_stop(void *device_priv, } } } - + soc_private->ife_clk_src = 0; return rc; } @@ -620,6 +640,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_top_get_data(top_priv, cmd_args, + arg_size); + break; case CAM_ISP_HW_CMD_CLOCK_UPDATE: rc = cam_vfe_top_clock_update(top_priv, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index dc15cab5e2f4..dd22109c1d67 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -212,6 +212,19 @@ static int cam_vfe_top_ver3_mux_get_reg_update( return -EINVAL; } +static int cam_vfe_top_ver3_get_data( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_resource_node *res = cmd_args; + + if (res->process_cmd) + return res->process_cmd(res, + CAM_ISP_HW_CMD_CAMIF_DATA, cmd_args, arg_size); + + return -EINVAL; +} + int cam_vfe_top_ver3_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -538,6 +551,10 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_ver3_mux_get_reg_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_top_ver3_get_data(top_priv, cmd_args, + arg_size); + break; case CAM_ISP_HW_CMD_CLOCK_UPDATE: rc = cam_vfe_top_ver3_clock_update(top_priv, cmd_args, arg_size); -- GitLab From 8169d42364a4ed72a9e08f5e26cbe836433a0eaa Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Wed, 11 Mar 2020 17:05:09 +0530 Subject: [PATCH 259/410] msm: camera: isp: Create debugfs for STATs DMI and cfg dump dmi and cfg dump on violation. CRs-Fixed: 2634602 Change-Id: I76af8dac52310f8bbbc584448c164e89bb7253eb Signed-off-by: Tejas Prajapati --- .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 174 ++++++++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 195 ++++++++++++++++-- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 47 ++++- 3 files changed, 400 insertions(+), 16 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 946ac2267d95..9512ad06c65e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -176,6 +176,179 @@ struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_130_reg = { .enable = 0x0000004C, }; +static struct cam_vfe_bus_ver2_stats_cfg_info stats_175_130_info = { + .dmi_offset_info = { + .auto_increment = 0x00000100, + .cfg_offset = 0x00000C24, + .addr_offset = 0x00000C28, + .data_hi_offset = 0x00000C2C, + .data_lo_offset = 0x00000C30, + }, + .stats_cfg_offset = { + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI0 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI1 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI2 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI3 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FD */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_PDAF */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .cfg_offset = 0x00000AB8, + .num_cfg = 0x00000ABC, + .cfg_size = 0x00000AC0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST */ + { + .res_index = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .cfg_offset = 0x00000AD4, + .num_cfg = 0x00000AD8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x36, + .bank_1 = 0x37, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .cfg_offset = 0x00000AE4, + .num_cfg = 0x00000000, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x40, + .bank_1 = 0x41, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .cfg_offset = 0x00000BC8, + .num_cfg = 0x00000BCC, + .cfg_size = 0x00000BD0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .cfg_offset = 0x00000BE4, + .num_cfg = 0x00000BE8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3A, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .cfg_offset = 0x00000BEC, + .num_cfg = 0x00000BF0, + .cfg_size = 0x00000BF4, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .cfg_offset = 0x00000BF8, + .num_cfg = 0x00000BFC, + .cfg_size = 0x00000C00, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .cfg_offset = 0x00000C04, + .num_cfg = 0x00000C08, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3B, + .bank_1 = 0x3C, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_2PD */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .cfg_offset = 0x00000FF0, + .num_cfg = 0x00000FF4, + .cfg_size = 0x00000FF8, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x44, + .bank_1 = 0x45, + }, + }, + }, +}; + + static struct cam_vfe_top_ver2_reg_offset_common vfe175_130_top_common_reg = { .hw_version = 0x00000000, .hw_capability = 0x00000004, @@ -1125,6 +1298,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { .max_height = 1080, }, }, + .stats_data = &stats_175_130_info, }; struct cam_vfe_hw_info cam_vfe175_130_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 92f0e700a485..231ad336e54d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -27,6 +27,8 @@ static const char drv_name[] = "vfe_bus"; #define CAM_VFE_BUS_IRQ_REG2 2 #define CAM_VFE_BUS_IRQ_MAX 3 +#define CAM_VFE_BUS_LUT_WORD_SIZE_64 1 + #define CAM_VFE_BUS_VER2_PAYLOAD_MAX 256 #define CAM_VFE_BUS_SET_DEBUG_REG 0x82 @@ -100,6 +102,7 @@ struct cam_vfe_bus_ver2_common_data { uint32_t addr_no_sync; cam_hw_mgr_event_cb_func event_cb; bool hw_init; + struct cam_vfe_bus_ver2_stats_cfg_info *stats_data; }; struct cam_vfe_bus_ver2_wm_resource_data { @@ -1366,6 +1369,40 @@ static int cam_vfe_bus_handle_wm_done_bottom_half(void *handler_priv, return rc; } +static void cam_vfe_bus_dump_dmi_reg( + void __iomem *mem_base, + uint32_t lut_word_size, + uint32_t lut_size, + uint32_t lut_bank_sel, + struct cam_vfe_bus_ver2_dmi_offset_common dmi_cfg) +{ + uint32_t i; + uint32_t val_0; + uint32_t val_1; + + val_0 = dmi_cfg.auto_increment | lut_bank_sel; + cam_io_w_mb(val_0, mem_base + dmi_cfg.cfg_offset); + cam_io_w_mb(0, mem_base + dmi_cfg.addr_offset); + for (i = 0; i < lut_size; i++) { + if (lut_word_size == CAM_VFE_BUS_LUT_WORD_SIZE_64) { + val_0 = cam_io_r_mb(mem_base + + dmi_cfg.data_lo_offset); + val_1 = cam_io_r_mb(mem_base + + dmi_cfg.data_hi_offset); + CAM_INFO(CAM_ISP, + "Bank%d : 0x%x, LO: 0x%x, HI:0x%x", + lut_bank_sel, i, val_0, val_1); + } else { + val_0 = cam_io_r_mb(mem_base + + dmi_cfg.data_lo_offset); + CAM_INFO(CAM_ISP, "Bank%d : 0x%x, LO: 0x%x", + lut_bank_sel, i, val_0); + } + } + cam_io_w_mb(0, mem_base + dmi_cfg.cfg_offset); + cam_io_w_mb(0, mem_base + dmi_cfg.addr_offset); +} + static int cam_vfe_bus_err_bottom_half(void *handler_priv, void *evt_payload_priv) @@ -1374,6 +1411,8 @@ static int cam_vfe_bus_err_bottom_half(void *handler_priv, struct cam_vfe_bus_ver2_priv *bus_priv = handler_priv; struct cam_vfe_bus_ver2_common_data *common_data; struct cam_isp_hw_event_info evt_info; + struct cam_vfe_bus_ver2_stats_cfg_offset *stats_cfg; + struct cam_vfe_bus_ver2_dmi_offset_common dmi_cfg; uint32_t val = 0; if (!handler_priv || !evt_payload_priv) @@ -1382,6 +1421,8 @@ static int cam_vfe_bus_err_bottom_half(void *handler_priv, evt_payload = evt_payload_priv; common_data = &bus_priv->common_data; + stats_cfg = common_data->stats_data->stats_cfg_offset; + dmi_cfg = common_data->stats_data->dmi_offset_info; val = evt_payload->debug_status_0; CAM_ERR(CAM_ISP, "Bus Violation: debug_status_0 = 0x%x", val); @@ -1415,35 +1456,158 @@ static int cam_vfe_bus_err_bottom_half(void *handler_priv, if (val & 0x0200) CAM_INFO(CAM_ISP, "RAW DUMP violation"); - if (val & 0x0400) + if (val & 0x0400) { CAM_INFO(CAM_ISP, "PDAF violation"); + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.bank_0, + dmi_cfg); + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].cfg_offset)); + } - if (val & 0x0800) - CAM_INFO(CAM_ISP, "STATs HDR BE violation"); + if (val & 0x0800) { + CAM_INFO(CAM_ISP, "STATs HDR BE vltn RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE].num_cfg)); + } - if (val & 0x01000) + if (val & 0x01000) { CAM_INFO(CAM_ISP, "STATs HDR BHIST violation"); + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.bank_0, + dmi_cfg); + + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.bank_1, + dmi_cfg); + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].num_cfg)); + } if (val & 0x02000) CAM_INFO(CAM_ISP, "STATs TINTLESS BG violation"); - if (val & 0x04000) + if (val & 0x04000) { CAM_INFO(CAM_ISP, "STATs BF violation"); + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_0, + dmi_cfg); + + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_1, + dmi_cfg); + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].cfg_offset)); + } + + if (val & 0x08000) { + CAM_INFO(CAM_ISP, "STATs AWB BG UBWC vltn RGN ofst cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG].num_cfg)); + } + + if (val & 0x010000) { + CAM_INFO(CAM_ISP, "STATs BHIST violation"); + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].lut.bank_0, + dmi_cfg); - if (val & 0x08000) - CAM_INFO(CAM_ISP, "STATs AWB BG UBWC violation"); + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].cfg_offset)); - if (val & 0x010000) - CAM_INFO(CAM_ISP, "STATs BHIST violation"); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].num_cfg)); + } + + if (val & 0x020000) { + CAM_INFO(CAM_ISP, "STATs RS violation RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].cfg_offset)); - if (val & 0x020000) - CAM_INFO(CAM_ISP, "STATs RS violation"); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].num_cfg)); + } + + if (val & 0x040000) { + CAM_INFO(CAM_ISP, "STATs CS violation RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].cfg_offset)); - if (val & 0x040000) - CAM_INFO(CAM_ISP, "STATs CS violation"); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].num_cfg)); + } - if (val & 0x080000) - CAM_INFO(CAM_ISP, "STATs IHIST violation"); + if (val & 0x080000) { + CAM_INFO(CAM_ISP, "STATs IHIST vltn RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST].num_cfg)); + } if (val & 0x0100000) CAM_INFO(CAM_ISP, "DISP Y 1:1 UBWC violation"); @@ -3634,6 +3798,7 @@ int cam_vfe_bus_ver2_init( bus_priv->common_data.addr_no_sync = CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL; bus_priv->common_data.hw_init = false; + bus_priv->common_data.stats_data = ver2_hw_info->stats_data; mutex_init(&bus_priv->common_data.bus_mutex); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index fc1608315330..0455d10b7367 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_BUS_VER2_H_ @@ -61,6 +61,36 @@ enum cam_vfe_bus_ver2_vfe_out_type { CAM_VFE_BUS_VER2_VFE_OUT_MAX, }; +struct cam_vfe_bus_ver2_dmi_lut_bank_info { + uint32_t size; + uint32_t bank_0; + uint32_t bank_1; +}; + +struct cam_vfe_bus_ver2_stats_cfg_offset { + uint32_t res_index; + uint32_t cfg_offset; + uint32_t num_cfg; + uint32_t cfg_size; + uint32_t is_lut; + struct cam_vfe_bus_ver2_dmi_lut_bank_info lut; +}; + +struct cam_vfe_bus_ver2_dmi_offset_common { + uint32_t auto_increment; + uint32_t cfg_offset; + uint32_t addr_offset; + uint32_t data_hi_offset; + uint32_t data_lo_offset; +}; + +struct cam_vfe_bus_ver2_stats_cfg_info { + struct cam_vfe_bus_ver2_dmi_offset_common + dmi_offset_info; + struct cam_vfe_bus_ver2_stats_cfg_offset + stats_cfg_offset[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; +}; + /* * struct cam_vfe_bus_ver2_reg_offset_common: * @@ -168,6 +198,19 @@ struct cam_vfe_bus_ver2_vfe_out_hw_info { uint32_t max_height; }; +/* + * struct cam_vfe_bus_ver2_reg_data: + * + * @Brief: Holds the bus register data + */ + +struct cam_vfe_bus_ver2_reg_data { + uint32_t ubwc_10bit_threshold_lossy_0; + uint32_t ubwc_10bit_threshold_lossy_1; + uint32_t ubwc_8bit_threshold_lossy_0; + uint32_t ubwc_8bit_threshold_lossy_1; +}; + /* * struct cam_vfe_bus_ver2_hw_info: * @@ -188,6 +231,8 @@ struct cam_vfe_bus_ver2_hw_info { uint32_t num_out; struct cam_vfe_bus_ver2_vfe_out_hw_info vfe_out_hw_info[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; + struct cam_vfe_bus_ver2_reg_data reg_data; + struct cam_vfe_bus_ver2_stats_cfg_info *stats_data; }; /* -- GitLab From 50289743d5d8a0e76686cd99ad542f20ca2ac31a Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 9 Mar 2020 17:32:27 +0530 Subject: [PATCH 260/410] msm: camera: csiphy: Update PHY settings for csiphy v1.2.3 Fix DPHY power-up settings and enable skew calibration for csiphy v1.2.3. Also remove CPHY settings for 3.5Gsps/4.5Gsps per trio data-rates. CRs-Fixed: 2642305 Change-Id: I0b170d99b33db983ddbe3455299b649ae2488a31 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_soc.c | 3 +- .../include/cam_csiphy_1_2_3_hwreg.h | 77 ++++++------------- 2 files changed, 24 insertions(+), 56 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index aa4de0d0a51b..3d053643eb49 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -351,8 +351,7 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->is_divisor_32_comp = true; csiphy_dev->hw_version = CSIPHY_VERSION_V12; csiphy_dev->clk_lane = 0; - csiphy_dev->ctrl_reg->data_rates_settings_table = - &data_rate_delta_table_1_2_3; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else if (of_device_is_compatible(soc_info->dev->of_node, "qcom,csiphy-v2.0")) { csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h index 42bef5eb5b11..dcaa8a902391 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -12,9 +12,9 @@ struct csiphy_reg_parms_t csiphy_v1_2_3 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 7, + .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 22, + .csiphy_2ph_config_array_size = 24, .csiphy_3ph_config_array_size = 38, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, @@ -23,8 +23,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_3 = { struct csiphy_reg_t csiphy_common_reg_1_2_3[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, - {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, @@ -76,6 +75,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -100,6 +101,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x070c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -124,6 +127,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -148,6 +153,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -172,6 +179,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -200,6 +209,8 @@ struct csiphy_reg_t {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -224,6 +235,8 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -248,6 +261,8 @@ struct csiphy_reg_t {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -272,6 +287,8 @@ struct csiphy_reg_t {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -296,6 +313,8 @@ struct csiphy_reg_t {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -424,54 +443,4 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { }, }; -struct data_rate_settings_t data_rate_delta_table_1_2_3 = { - .num_data_rate_settings = 3, - .data_rate_settings = { - { - /* (2.5 * 10**3 * 2.28) rounded value*/ - .bandwidth = 5700000000, - .data_rate_reg_array_size = 8, - .csiphy_data_rate_regs = { - {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xA84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xB84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, - } - }, - { - /* (3.5 * 10**3 * 2.28) rounded value */ - .bandwidth = 7980000000, - .data_rate_reg_array_size = 8, - .csiphy_data_rate_regs = { - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - }, - }, - { - /* (4.5 * 10**3 * 2.28) rounded value */ - .bandwidth = 10260000000, - .data_rate_reg_array_size = 8, - .csiphy_data_rate_regs = { - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - }, - } - } -}; #endif /* _CAM_CSIPHY_1_2_3_HWREG_H_ */ -- GitLab From f268f4f4faeb7dd7909a8da34ba4fa05b107e518 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Thu, 12 Mar 2020 22:43:23 +0530 Subject: [PATCH 261/410] msm: camera: common: Bring up changes for lagoon camera 1. Change ubwc config register value to default. 2. Remove camera hw version check to pick fixed camera id. 3. Add camera hw version check to enable crop or drop feature. 4. By pass lrme start and stop on camera hw version basis. This is temporary fix to avoid lag. CRs-Fixed: 2571273 Change-Id: I2144784984be721c34745c7744f3dcb29526701d Signed-off-by: Chandan Kumar Jha --- drivers/cam_cpas/cpas_top/cpastop_v170_200.h | 8 +++--- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 4 +-- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 28 +++++++++++++------ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h index 1754029e1b06..500fcd3bad2f 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h @@ -290,7 +290,7 @@ static struct cam_camnoc_specific .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2588, /* SPECIFIC_IFE01_ENCCTL_LOW */ - .value = 1, + .value = 5, }, }, { @@ -338,7 +338,7 @@ static struct cam_camnoc_specific .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2788, /* SPECIFIC_IFE23_ENCCTL_LOW */ - .value = 1, + .value = 5, }, }, { @@ -431,14 +431,14 @@ static struct cam_camnoc_specific .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ - .value = 0x0, + .value = 0xFFF, }, .ubwc_ctl = { .enable = true, .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ - .value = 1, + .value = 5, }, }, { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index c4b34bd18693..b78f5dee2837 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -763,7 +763,6 @@ int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: - case CAM_CPAS_TITAN_170_V200: if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && csid_hw->hw_intf->hw_idx != 2) { rc = -EINVAL; @@ -2222,7 +2221,8 @@ static int cam_ife_csid_init_config_rdi_path( CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); if (camera_hw_version == CAM_CPAS_TITAN_480_V100 || - camera_hw_version == CAM_CPAS_TITAN_175_V130) { + camera_hw_version == CAM_CPAS_TITAN_175_V130 || + camera_hw_version == CAM_CPAS_TITAN_170_V200) { val |= (path_data->drop_enable << csid_reg->cmn_reg->drop_h_en_shift_val) | (path_data->drop_enable << diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index 4e2609648b30..ef076a3c6279 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -84,6 +84,8 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) const struct of_device_id *match_dev = NULL; struct cam_lrme_hw_info *hw_info; int rc, i; + int32_t camera_hw_version; + lrme_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); if (!lrme_hw) { @@ -152,10 +154,18 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) goto release_cdm; } - rc = cam_lrme_hw_start(lrme_hw, NULL, 0); + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); if (rc) { - CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc); - goto detach_smmu; + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + goto release_cdm; + } + + if (camera_hw_version != CAM_CPAS_TITAN_170_V200) { + rc = cam_lrme_hw_start(lrme_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc); + goto detach_smmu; + } } rc = cam_lrme_hw_util_get_caps(lrme_hw, &lrme_core->hw_caps); @@ -166,10 +176,12 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) goto detach_smmu; } - rc = cam_lrme_hw_stop(lrme_hw, NULL, 0); - if (rc) { - CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc); - goto detach_smmu; + if (camera_hw_version != CAM_CPAS_TITAN_170_V200) { + rc = cam_lrme_hw_stop(lrme_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc); + goto detach_smmu; + } } lrme_core->hw_idx = lrme_hw->soc_info.index; -- GitLab From c4af36503ff45bf6ac0a96b8e6b5ab315bb7906e Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 16 Mar 2020 21:24:05 +0530 Subject: [PATCH 262/410] msm: camera: cpas: Update camnoc axi port vote during cpas start/stop For some cpas clients like csiphy, cci voting is applied and removed during their respective start and stop flow. Such clients do no call for vote update explicitly. For such cases, camnoc axi ports were not updated. This can result in camnoc_sf vote to be present. This commit updates the camnoc ports as well for the clients for who the voting is applied and removed during the start and stop only. CRs-Fixed: 2571273 Change-Id: I2997e5abad904532dc0d582edbf6d6078ac732d7 Signed-off-by: Gaurav Jindal --- drivers/cam_cpas/cam_cpas_hw.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 893ef5866e7e..05cf0416ea1e 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -782,6 +782,20 @@ static int cam_cpas_util_apply_client_axi_vote( } mnoc_axi_port_updated[i] = true; } + + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + if (axi_vote->axi_path[0].camnoc_bw) { + /* start case */ + cpas_core->camnoc_axi_port[i].additional_bw += + CAM_CPAS_DEFAULT_AXI_BW; + } else { + /* stop case */ + cpas_core->camnoc_axi_port[i].additional_bw -= + CAM_CPAS_DEFAULT_AXI_BW; + } + camnoc_axi_port_updated[i] = true; + } + goto vote_start_clients; } -- GitLab From faf8f91b10ae53e3418847cba1c74d8c3485bdc9 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Wed, 18 Mar 2020 20:57:53 +0530 Subject: [PATCH 263/410] msm: camera: isp: Add ldar Dump data for lagoon vfe Add ldar Dump data for lagoon vfe. CRs-Fixed: 2645388 Change-Id: I006f48b051e43bf80bb402009c42eb1fc31e1e95 Signed-off-by: Gaurav Jindal --- .../isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 27 +++++++++++++++++++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 7 +++++ 2 files changed, 34 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h index 15f4380ba935..4c34411a793d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -155,6 +155,32 @@ static struct cam_vfe_rdi_reg_data vfe_170_150_rdi_2_data = { .reg_update_irq_mask = 0x80, }; +struct cam_vfe_top_dump_data vfe170_150_dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0xF94, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x3578, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, +}; + static struct cam_vfe_top_ver2_hw_info vfe170_150_top_hw_info = { .common_reg = &vfe170_150_top_common_reg, .camif_hw_info = { @@ -185,6 +211,7 @@ static struct cam_vfe_top_ver2_hw_info vfe170_150_top_hw_info = { CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, }, + .dump_data = &vfe170_150_dump_data, }; static struct cam_irq_register_set vfe170_150_bus_irq_reg[3] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 6774be8cda3d..332332cfccc0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -224,7 +224,14 @@ static int cam_vfe_hw_dump( dump_args->offset, dump_args->buf_len); return -ENOSPC; } + dump_data = top_priv->common_data.dump_data; + + if (!dump_data) { + CAM_ERR(CAM_ISP, "Dump data not available"); + return -EINVAL; + } + soc_info = top_priv->common_data.soc_info; /*Dump registers */ -- GitLab From 0fcdbe2ee88b58b2b48890a6a4dd75d8fde51374 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 19 Mar 2020 11:03:04 +0530 Subject: [PATCH 264/410] msm: camera: isp: variable should be accessed only if match is found There is a possibility that the priority variable would be accessed even for the HEAD node which would result in out of bound errors, so access the elements of the structure only if the handler is found. CRs-Fixed: 2646173 Change-Id: I0540658b9c9487f6e3a4601a488a1add1e790dda Signed-off-by: Tejas Prajapati --- .../isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index cc1fe18e05fd..5763939fd310 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -515,8 +515,8 @@ int cam_irq_controller_unsubscribe_irq(void *irq_controller, } } - priority = evt_handler->priority; if (found) { + priority = evt_handler->priority; for (i = 0; i < controller->num_registers; i++) { irq_register = &controller->irq_register_arr[i]; irq_register->top_half_enable_mask[priority] &= -- GitLab From 26543c963eef1d7bb8a7181fd1e25fb9ac143d62 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Thu, 2 Jan 2020 10:24:53 +0530 Subject: [PATCH 265/410] msm: camera: isp: Enable format measurement in CSID Enabling format measure helps to find mismatch between the expected sensor width and height with actual sensor width and height. In case of metadata, width is more than 16 bit, hence skip format measure check for it. In case of mismatch CSID will give CSID_PATH_ERROR_PIX_COUNT and CSID_PATH_ERROR_LINE_COUNT. CRs-Fixed: 2634468 Change-Id: Ic57a18ee5217982d36116060371bdc99405ea759 Signed-off-by: Ayush Kumar --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 92 +++++++- .../isp_hw/ife_csid_hw/cam_ife_csid170.h | 6 +- .../isp_hw/ife_csid_hw/cam_ife_csid170_200.h | 4 + .../isp_hw/ife_csid_hw/cam_ife_csid175.h | 6 +- .../isp_hw/ife_csid_hw/cam_ife_csid175_200.h | 6 +- .../isp_hw/ife_csid_hw/cam_ife_csid480.h | 6 +- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 218 +++++++++++++++++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 9 + .../isp_hw/include/cam_ife_csid_hw_intf.h | 14 ++ include/uapi/media/cam_isp.h | 58 ++++- 10 files changed, 396 insertions(+), 23 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index c0e4cce9823d..d8d349bc3ae0 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -36,7 +36,7 @@ (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) #define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ - (CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 + 1) + (CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG + 1) static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, @@ -5119,6 +5119,76 @@ static int cam_isp_blob_clock_update( return rc; } +static int cam_isp_blob_sensor_config( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_sensor_config *dim_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_sensor_dimension_update_args update_args; + int rc = -EINVAL, found = 0; + uint32_t i, j; + struct cam_isp_sensor_dimension *path_config; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + found = 1; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + path_config = &(dim_config->ipp_path); + update_args.ipp_path.width = + path_config->width; + update_args.ipp_path.height = + path_config->height; + update_args.ipp_path.measure_enabled = + path_config->measure_enabled; + path_config = &(dim_config->ppp_path); + update_args.ppp_path.width = + path_config->width; + update_args.ppp_path.height = + path_config->height; + update_args.ppp_path.measure_enabled = + path_config->measure_enabled; + for (j = 0; j < CAM_IFE_RDI_NUM_MAX; j++) { + path_config = + &(dim_config->rdi_path[j]); + update_args.rdi_path[j].width = + path_config->width; + update_args.rdi_path[j].height = + path_config->height; + update_args.rdi_path[j].measure_enabled = + path_config->measure_enabled; + } + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG, + &update_args, + sizeof( + struct + cam_ife_sensor_dimension_update_args) + ); + if (rc) { + CAM_ERR(CAM_ISP, + "Dimension Update failed"); + break; + } + } else + CAM_ERR(CAM_ISP, "hw_intf is NULL"); + } + if (found) + break; + } + + return rc; +} + static int cam_isp_blob_vfe_out_update( uint32_t blob_type, struct cam_isp_generic_blob_info *blob_info, @@ -5739,6 +5809,26 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "CSID Config failed rc: %d", rc); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_DIMENSION_CONFIG: { + struct cam_isp_sensor_config *csid_dim_config; + + if (blob_size < sizeof(struct cam_isp_sensor_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %zu expected %zu", + blob_size, + sizeof(struct cam_isp_sensor_config)); + return -EINVAL; + } + + csid_dim_config = + (struct cam_isp_sensor_config *)blob_data; + + rc = cam_isp_blob_sensor_config(blob_type, blob_info, + csid_dim_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, + "Sensor Dimension Update Failed rc: %d", rc); + } + break; default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h index 714fa8ef2b31..bc564b2e1f77 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_170_H_ @@ -286,6 +286,10 @@ static struct cam_ife_csid_common_reg_offset .ppp_irq_mask_all = 0x0, .measure_en_hbi_vbi_cnt_mask = 0xC, .format_measure_en_val = 1, + .format_measure_height_mask_val = 0xFFFF, + .format_measure_height_shift_val = 0x10, + .format_measure_width_mask_val = 0xFFFF, + .format_measure_width_shift_val = 0x0, }; static struct cam_ife_csid_reg_offset cam_ife_csid_170_reg_offset = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h index 47cb02492412..f7608a73fad6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170_200.h @@ -349,6 +349,10 @@ static struct cam_ife_csid_common_reg_offset .ppp_irq_mask_all = 0xFFFF, .measure_en_hbi_vbi_cnt_mask = 0xC, .format_measure_en_val = 1, + .format_measure_height_mask_val = 0xFFFF, + .format_measure_height_shift_val = 0x10, + .format_measure_width_mask_val = 0xFFFF, + .format_measure_width_shift_val = 0x0, }; static struct cam_ife_csid_reg_offset cam_ife_csid_170_200_reg_offset = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h index 70f96ea416d8..734218bf5144 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_175_H_ @@ -327,6 +327,10 @@ static struct cam_ife_csid_common_reg_offset .ppp_irq_mask_all = 0xFFFF, .measure_en_hbi_vbi_cnt_mask = 0xC, .format_measure_en_val = 1, + .format_measure_height_mask_val = 0xFFFF, + .format_measure_height_shift_val = 0x10, + .format_measure_width_mask_val = 0xFFFF, + .format_measure_width_shift_val = 0x0, }; static struct cam_ife_csid_reg_offset cam_ife_csid_175_reg_offset = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h index 612379ec4bdd..1794a860b84e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_175_200_H_ @@ -345,6 +345,10 @@ static struct cam_ife_csid_common_reg_offset .ppp_irq_mask_all = 0xFFFF, .measure_en_hbi_vbi_cnt_mask = 0xC, .format_measure_en_val = 1, + .format_measure_height_mask_val = 0xFFFF, + .format_measure_height_shift_val = 0x10, + .format_measure_width_mask_val = 0xFFFF, + .format_measure_width_shift_val = 0x0, }; static struct cam_ife_csid_reg_offset cam_ife_csid_175_200_reg_offset = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h index 66c1b32d51b0..316c3e2ab629 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_480_H_ @@ -365,6 +365,10 @@ static struct cam_ife_csid_common_reg_offset .ppp_irq_mask_all = 0xFFFF, .measure_en_hbi_vbi_cnt_mask = 0xC, .format_measure_en_val = 1, + .format_measure_height_mask_val = 0xFFFF, + .format_measure_height_shift_val = 0x10, + .format_measure_width_mask_val = 0xFFFF, + .format_measure_width_shift_val = 0x0, }; static struct cam_ife_csid_reg_offset cam_ife_csid_480_reg_offset = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index b78f5dee2837..e6fc46d1724f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -75,7 +75,7 @@ static int cam_ife_csid_is_ipp_ppp_format_supported( static int cam_ife_csid_get_format_rdi( uint32_t in_format, uint32_t out_format, uint32_t *decode_fmt, - uint32_t *plain_fmt, uint32_t *packing_fmt, bool rpp) + uint32_t *plain_fmt, uint32_t *packing_fmt, bool rpp, uint32_t *in_bpp) { int rc = 0; @@ -97,6 +97,7 @@ static int cam_ife_csid_get_format_rdi( rc = -EINVAL; break; } + *in_bpp = 6; break; case CAM_FORMAT_MIPI_RAW_8: switch (out_format) { @@ -116,6 +117,7 @@ static int cam_ife_csid_get_format_rdi( rc = -EINVAL; break; } + *in_bpp = 8; break; case CAM_FORMAT_MIPI_RAW_10: switch (out_format) { @@ -135,6 +137,7 @@ static int cam_ife_csid_get_format_rdi( rc = -EINVAL; break; } + *in_bpp = 10; break; case CAM_FORMAT_MIPI_RAW_12: switch (out_format) { @@ -153,6 +156,7 @@ static int cam_ife_csid_get_format_rdi( rc = -EINVAL; break; } + *in_bpp = 12; break; case CAM_FORMAT_MIPI_RAW_14: switch (out_format) { @@ -171,6 +175,7 @@ static int cam_ife_csid_get_format_rdi( rc = -EINVAL; break; } + *in_bpp = 14; break; case CAM_FORMAT_MIPI_RAW_16: switch (out_format) { @@ -189,6 +194,7 @@ static int cam_ife_csid_get_format_rdi( rc = -EINVAL; break; } + *in_bpp = 16; break; case CAM_FORMAT_MIPI_RAW_20: switch (out_format) { @@ -207,6 +213,7 @@ static int cam_ife_csid_get_format_rdi( rc = -EINVAL; break; } + *in_bpp = 20; break; case CAM_FORMAT_DPCM_10_6_10: *decode_fmt = 0x7; @@ -1312,6 +1319,7 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) { int rc = -EINVAL; + uint32_t i; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; unsigned long flags; @@ -1352,6 +1360,12 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) spin_lock_irqsave(&csid_hw->lock_state, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->lock_state, flags); + + csid_hw->ipp_path_config.measure_enabled = 0; + csid_hw->ppp_path_config.measure_enabled = 0; + for (i = 0; i <= CAM_IFE_PIX_PATH_RES_RDI_3; i++) + csid_hw->rdi_path_config[i].measure_enabled = 0; + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; csid_hw->prev_boot_timestamp = 0; @@ -1714,6 +1728,7 @@ static int cam_ife_csid_init_config_pxl_path( bool is_ipp; uint32_t decode_format = 0, plain_format = 0, val = 0; uint32_t camera_hw_version; + struct cam_isp_sensor_dimension *path_config; path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -1722,9 +1737,11 @@ static int cam_ife_csid_init_config_pxl_path( if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { is_ipp = true; pxl_reg = csid_reg->ipp_reg; + path_config = &(csid_hw->ipp_path_config); } else { is_ipp = false; pxl_reg = csid_reg->ppp_reg; + path_config = &(csid_hw->ppp_path_config); } if (!pxl_reg) { @@ -1837,6 +1854,25 @@ static int cam_ife_csid_init_config_pxl_path( pxl_reg->csid_pxl_irq_subsample_period_addr); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_irq_subsample_pattern_addr); + + /* configure pixel format measure */ + if (path_config->measure_enabled) { + val = (((path_config->height & + csid_reg->cmn_reg->format_measure_height_mask_val) << + csid_reg->cmn_reg->format_measure_height_shift_val) | + (path_config->width & + csid_reg->cmn_reg->format_measure_width_mask_val)); + CAM_DBG(CAM_ISP, "CSID:%d format measure cfg1 value : 0x%x", + csid_hw->hw_intf->hw_idx, val); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg1_addr); + + /* enable pixel and line counter */ + cam_io_w_mb(3, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + } + /* set pxl drop pattern to 0 and period to 1 */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_pix_drop_pattern_addr); @@ -1986,6 +2022,7 @@ static int cam_ife_csid_enable_pxl_path( const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; bool is_ipp; uint32_t val = 0; + struct cam_isp_sensor_dimension *path_config; path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -1994,9 +2031,11 @@ static int cam_ife_csid_enable_pxl_path( if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { is_ipp = true; pxl_reg = csid_reg->ipp_reg; + path_config = &(csid_hw->ipp_path_config); } else { is_ipp = false; pxl_reg = csid_reg->ppp_reg; + path_config = &(csid_hw->ppp_path_config); } if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { @@ -2066,6 +2105,10 @@ static int cam_ife_csid_enable_pxl_path( if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; + if (path_config->measure_enabled) + val |= (CSID_PATH_ERROR_PIX_COUNT | + CSID_PATH_ERROR_LINE_COUNT); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_irq_mask_addr); @@ -2179,7 +2222,8 @@ static int cam_ife_csid_init_config_rdi_path( const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; uint32_t path_format = 0, plain_fmt = 0, val = 0, id; - uint32_t format_measure_addr, camera_hw_version, packing_fmt = 0; + uint32_t format_measure_addr, camera_hw_version; + uint32_t packing_fmt = 0, in_bpp = 0; path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -2194,7 +2238,7 @@ static int cam_ife_csid_init_config_rdi_path( rc = cam_ife_csid_get_format_rdi(path_data->in_format, path_data->out_format, &path_format, &plain_fmt, &packing_fmt, - path_data->crop_enable || path_data->drop_enable); + path_data->crop_enable || path_data->drop_enable, &in_bpp); if (rc) return rc; @@ -2275,6 +2319,35 @@ static int cam_ife_csid_init_config_rdi_path( csid_reg->rdi_reg[id]->csid_rdi_err_recovery_cfg0_addr); } + /* configure pixel format measure */ + if (csid_hw->rdi_path_config[id].measure_enabled) { + val = ((csid_hw->rdi_path_config[id].height & + csid_reg->cmn_reg->format_measure_height_mask_val) << + csid_reg->cmn_reg->format_measure_height_shift_val); + + if (path_format == 0xF) + val |= (__KERNEL_DIV_ROUND_UP( + (csid_hw->rdi_path_config[id].width * + in_bpp), 8) & + csid_reg->cmn_reg->format_measure_width_mask_val); + else + val |= (csid_hw->rdi_path_config[id].width & + csid_reg->cmn_reg->format_measure_width_mask_val); + + CAM_DBG(CAM_ISP, "CSID:%d format measure cfg1 value : 0x%x", + csid_hw->hw_intf->hw_idx, val); + CAM_DBG(CAM_ISP, "format measure width : 0x%x height : 0x%x", + csid_hw->rdi_path_config[id].width, + csid_hw->rdi_path_config[id].height); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg1_addr); + + /* enable pixel and line counter */ + cam_io_w_mb(3, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg0_addr); + } + /* set frame drop pattern to 0 and period to 1 */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_frm_drop_period_addr); @@ -2371,7 +2444,7 @@ static int cam_ife_csid_init_config_udi_path( const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; uint32_t path_format = 0, plain_fmt = 0, val = 0, val1, id; - uint32_t format_measure_addr, packing_fmt = 0; + uint32_t format_measure_addr, packing_fmt = 0, in_bpp = 0; path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; @@ -2386,7 +2459,7 @@ static int cam_ife_csid_init_config_udi_path( rc = cam_ife_csid_get_format_rdi(path_data->in_format, path_data->out_format, &path_format, &plain_fmt, &packing_fmt, - path_data->crop_enable || path_data->drop_enable); + path_data->crop_enable || path_data->drop_enable, &in_bpp); if (rc) { CAM_ERR(CAM_ISP, "Failed to get format in_format: %u out_format: %u rc: %d", @@ -2650,9 +2723,14 @@ static int cam_ife_csid_enable_rdi_path( if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; + if (csid_hw->rdi_path_config[id].measure_enabled) + val |= (CSID_PATH_ERROR_PIX_COUNT | + CSID_PATH_ERROR_LINE_COUNT); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); @@ -3262,6 +3340,13 @@ int cam_ife_csid_release(void *hw_priv, break; case CAM_ISP_RESOURCE_PIX_PATH: res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) + csid_hw->ipp_path_config.measure_enabled = 0; + else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + csid_hw->ppp_path_config.measure_enabled = 0; + else + csid_hw->rdi_path_config[res->res_id].measure_enabled + = 0; break; default: CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", @@ -3795,6 +3880,58 @@ static int cam_ife_csid_set_csid_clock( return 0; } +static int cam_ife_csid_set_sensor_dimension( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_ife_sensor_dimension_update_args *dimension_update = NULL; + uint32_t i; + + if (!csid_hw) + return -EINVAL; + + dimension_update = + (struct cam_ife_sensor_dimension_update_args *)cmd_args; + csid_hw->ipp_path_config.measure_enabled = + dimension_update->ipp_path.measure_enabled; + if (dimension_update->ipp_path.measure_enabled) { + csid_hw->ipp_path_config.width = + dimension_update->ipp_path.width; + csid_hw->ipp_path_config.height = + dimension_update->ipp_path.height; + CAM_DBG(CAM_ISP, "CSID ipp path width %d height %d", + csid_hw->ipp_path_config.width, + csid_hw->ipp_path_config.height); + } + csid_hw->ppp_path_config.measure_enabled = + dimension_update->ppp_path.measure_enabled; + if (dimension_update->ppp_path.measure_enabled) { + csid_hw->ppp_path_config.width = + dimension_update->ppp_path.width; + csid_hw->ppp_path_config.height = + dimension_update->ppp_path.height; + CAM_DBG(CAM_ISP, "CSID ppp path width %d height %d", + csid_hw->ppp_path_config.width, + csid_hw->ppp_path_config.height); + } + for (i = 0; i <= CAM_IFE_PIX_PATH_RES_RDI_3; i++) { + csid_hw->rdi_path_config[i].measure_enabled + = dimension_update->rdi_path[i].measure_enabled; + if (csid_hw->rdi_path_config[i].measure_enabled) { + csid_hw->rdi_path_config[i].width = + dimension_update->rdi_path[i].width; + csid_hw->rdi_path_config[i].height = + dimension_update->rdi_path[i].height; + if (csid_hw->rdi_path_config[i].height == 1) + csid_hw->rdi_path_config[i].measure_enabled = 0; + CAM_DBG(CAM_ISP, + "CSID rdi path[%d] width %d height %d", + i, csid_hw->rdi_path_config[i].width, + csid_hw->rdi_path_config[i].height); + } + } + return 0; +} + static int cam_ife_csid_set_csid_qcfa( struct cam_ife_csid_hw *csid_hw, void *cmd_args) { @@ -3936,6 +4073,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_IFE_CSID_SET_CONFIG: rc = cam_ife_csid_set_epd_config(csid_hw, cmd_args); break; + case CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG: + rc = cam_ife_csid_set_sensor_dimension(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); @@ -3956,7 +4096,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; uint32_t irq_status_rdi[CAM_IFE_CSID_RDI_MAX] = {0, 0, 0, 0}; uint32_t irq_status_udi[CAM_IFE_CSID_UDI_MAX] = {0, 0, 0}; - uint32_t val, irq_status_ppp = 0; + uint32_t val, val2, irq_status_ppp = 0; bool fatal_err_detected = false; uint32_t sof_irq_debug_en = 0; unsigned long flags; @@ -4275,6 +4415,25 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_ctrl_addr); } + + if ((irq_status_ipp & CSID_PATH_ERROR_PIX_COUNT) || + (irq_status_ipp & CSID_PATH_ERROR_LINE_COUNT)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_format_measure0_addr); + + CAM_ERR(CAM_ISP, + "CSID:%d irq_status_ipp:0x%x", + csid_hw->hw_intf->hw_idx, irq_status_ipp); + CAM_ERR(CAM_ISP, + "Expected:: h: 0x%x w: 0x%x actual:: h: 0x%x w: 0x%x", + csid_hw->ipp_path_config.height, + csid_hw->ipp_path_config.width, + ((val >> + csid_reg->cmn_reg->format_measure_height_shift_val) & + csid_reg->cmn_reg->format_measure_height_mask_val), + val & + csid_reg->cmn_reg->format_measure_width_mask_val); + } } /*read PPP errors */ @@ -4318,6 +4477,25 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_ctrl_addr); } + + if ((irq_status_ppp & CSID_PATH_ERROR_PIX_COUNT) || + (irq_status_ppp & CSID_PATH_ERROR_LINE_COUNT)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_format_measure0_addr); + + CAM_ERR(CAM_ISP, + "CSID:%d irq_status_ppp:0x%x", + csid_hw->hw_intf->hw_idx, irq_status_ppp); + CAM_ERR(CAM_ISP, + "Expected:: h: 0x%x w: 0x%x actual:: h: 0x%x w: 0x%x", + csid_hw->ppp_path_config.height, + csid_hw->ppp_path_config.width, + ((val >> + csid_reg->cmn_reg->format_measure_height_shift_val) & + csid_reg->cmn_reg->format_measure_height_mask_val), + val & + csid_reg->cmn_reg->format_measure_width_mask_val); + } } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { @@ -4358,6 +4536,30 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_ctrl_addr); } + + if ((irq_status_rdi[i] & CSID_PATH_ERROR_PIX_COUNT) || + (irq_status_rdi[i] & CSID_PATH_ERROR_LINE_COUNT)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_format_measure0_addr); + val2 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_format_measure_cfg1_addr + ); + CAM_ERR(CAM_ISP, + "CSID:%d irq_status_rdi[%d]:0x%x", + csid_hw->hw_intf->hw_idx, i, irq_status_rdi[i]); + CAM_ERR(CAM_ISP, + "Expected:: h: 0x%x w: 0x%x actual:: h: 0x%x w: 0x%x", + ((val2 >> + csid_reg->cmn_reg->format_measure_height_shift_val) & + csid_reg->cmn_reg->format_measure_height_mask_val), + val2 & + csid_reg->cmn_reg->format_measure_width_mask_val, + ((val >> + csid_reg->cmn_reg->format_measure_height_shift_val) & + csid_reg->cmn_reg->format_measure_height_mask_val), + val & + csid_reg->cmn_reg->format_measure_width_mask_val); + } } for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { @@ -4569,6 +4771,10 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->csid_debug = 0; ife_csid_hw->error_irq_count = 0; + ife_csid_hw->ipp_path_config.measure_enabled = 0; + ife_csid_hw->ppp_path_config.measure_enabled = 0; + for (i = 0; i <= CAM_IFE_PIX_PATH_RES_RDI_3; i++) + ife_csid_hw->rdi_path_config[i].measure_enabled = 0; return 0; err: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 885cd07b6ff7..472f827ae49d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -373,6 +373,10 @@ struct cam_ife_csid_common_reg_offset { uint32_t measure_en_hbi_vbi_cnt_mask; uint32_t format_measure_en_val; uint32_t num_bytes_out_shift_val; + uint32_t format_measure_width_shift_val; + uint32_t format_measure_width_mask_val; + uint32_t format_measure_height_shift_val; + uint32_t format_measure_height_mask_val; }; /** @@ -581,6 +585,11 @@ struct cam_ife_csid_hw { struct completion csid_udin_complete[CAM_IFE_CSID_UDI_MAX]; uint64_t csid_debug; uint64_t clk_rate; + struct cam_isp_sensor_dimension ipp_path_config; + struct cam_isp_sensor_dimension ppp_path_config; + struct cam_isp_sensor_dimension rdi_path_config[CAM_IFE_CSID_RDI_MAX]; + uint32_t hbi; + uint32_t vbi; bool sof_irq_triggered; uint32_t irq_debug_cnt; uint32_t error_irq_count; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 78c457b6a7cb..1998f19b7918 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -206,6 +206,7 @@ enum cam_ife_csid_cmd_type { CAM_IFE_CSID_SET_CSID_DEBUG, CAM_IFE_CSID_SOF_IRQ_DEBUG, CAM_IFE_CSID_SET_CONFIG, + CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG, CAM_IFE_CSID_CMD_MAX, }; @@ -247,4 +248,17 @@ struct cam_ife_csid_epd_update_args { uint32_t epd_supported; }; +/* + * struct cam_ife_sensor_dim_update_args: + * + * @ppp_path: expected ppp path configuration + * @ipp_path: expected ipp path configuration + * @rdi_path: expected rdi path configuration + */ +struct cam_ife_sensor_dimension_update_args { + struct cam_isp_sensor_dimension ppp_path; + struct cam_isp_sensor_dimension ipp_path; + struct cam_isp_sensor_dimension rdi_path[CAM_IFE_CSID_RDI_MAX]; +}; + #endif /* _CAM_CSID_HW_INTF_H_ */ diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index ef10e615cdf7..b773d17a75a5 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -92,18 +92,19 @@ #define CAM_ISP_DSP_MODE_ROUND 2 /* ISP Generic Cmd Buffer Blob types */ -#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 -#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 -#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 -#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 -#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 -#define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 -#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG_V2 6 -#define CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG 7 -#define CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG 8 -#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 9 -#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CONFIG 10 -#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG 12 +#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 +#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 +#define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 +#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG_V2 6 +#define CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG 7 +#define CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG 8 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 9 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CONFIG 10 +#define CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_DIMENSION_CONFIG 11 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG 12 #define CAM_ISP_VC_DT_CFG 4 @@ -133,6 +134,8 @@ #define CAM_ISP_ACQ_CUSTOM_PRIMARY 1 #define CAM_ISP_ACQ_CUSTOM_SECONDARY 2 +#define CAM_IFE_CSID_RDI_MAX 4 + /* Query devices */ /** * struct cam_isp_dev_cap_info - A cap info for particular hw type @@ -595,6 +598,37 @@ struct cam_fe_config { uint32_t latency_buf_size; } __attribute__((packed)); + +/** + * struct cam_isp_sensor_path_dimension + * + * @width expected width + * @height expected height + * @measure_enabled flag to indicate if pixel measurement is to be enabled + */ +struct cam_isp_sensor_dimension { + uint32_t width; + uint32_t height; + uint32_t measure_enabled; +} __attribute__((packed)); + +/** + * struct cam_isp_sensor_config - Sensor Dimension configuration + * + * @ppp_path: expected ppp path configuration + * @ipp_path: expected ipp path configuration + * @rdi_path: expected rdi path configuration + * @hbi: HBI value + * @vbi: VBI value + */ +struct cam_isp_sensor_config { + struct cam_isp_sensor_dimension ppp_path; + struct cam_isp_sensor_dimension ipp_path; + struct cam_isp_sensor_dimension rdi_path[CAM_IFE_CSID_RDI_MAX]; + uint32_t hbi; + uint32_t vbi; +} __attribute__((packed)); + /** * struct cam_isp_core_config - ISP core registers configuration * -- GitLab From c36fc8091dfa6cb6aaa58c2421d564ce11433751 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Thu, 19 Mar 2020 13:16:17 +0530 Subject: [PATCH 266/410] msm: camera: csiphy: Update PHY settings for csiphy v1.2.3 Update CPHY and DPHY settings for csiphy v1.2.3 to comply with HPG rev T. DPHY updates: clock miss count, PGM delay. CPHY updates: offset calibration. CRs-Fixed: 2644588 Change-Id: I6d831479417e558c8ab9931937e6f630218d85eb Signed-off-by: Shravan Nevatia --- .../include/cam_csiphy_1_2_3_hwreg.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h index dcaa8a902391..37995e31bf67 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -68,7 +68,7 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0028, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0000, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, @@ -94,11 +94,11 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0700, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x070c, 0x16, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0760, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -120,7 +120,7 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0228, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0200, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, @@ -146,7 +146,7 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0428, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0400, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, @@ -172,7 +172,7 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0xD4, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, @@ -278,7 +278,7 @@ struct csiphy_reg_t {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DNP_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -306,7 +306,7 @@ struct csiphy_reg_t {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, @@ -368,8 +368,8 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, -- GitLab From af374fc4976c45a9a54b96391fd12fe994be5e50 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Mon, 2 Mar 2020 22:52:43 +0530 Subject: [PATCH 267/410] msm: camera: sync: Prevent spin lock recursion This commit handle spin lock recursion when both the parent sync object is same as one of its child object. CRs-Fixed: 2629192 Change-Id: I524f8ff176250d6aa32b1a03797cfa7858147c51 Signed-off-by: Ayush Kumar --- drivers/cam_sync/cam_sync_util.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync_util.c b/drivers/cam_sync/cam_sync_util.c index d7e0f4125290..05e59dde9c26 100644 --- a/drivers/cam_sync/cam_sync_util.c +++ b/drivers/cam_sync/cam_sync_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_sync_util.h" @@ -72,6 +72,12 @@ int cam_sync_init_group_object(struct sync_table_row *table, * If any child state is ERROR or SUCCESS, it will not be added to list. */ for (i = 0; i < num_objs; i++) { + if (idx == sync_objs[i]) { + CAM_ERR(CAM_SYNC, + "Invalid, same as parent fence : %i", idx); + rc = -EINVAL; + goto clean_children_info; + } child_row = table + sync_objs[i]; spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); -- GitLab From 289958a52b5eced4a9c366367f052a0381fa01de Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 30 Mar 2020 13:12:22 +0530 Subject: [PATCH 268/410] msm: camera: cpas: Update QOS setting for lagoon Update QOS settings for lagoon IFE_23 and IFE01. CRs-Fixed: 2652098 Change-Id: Ia1ef200414df88f3d5ca958daf6dfb5acefa0c9f Signed-off-by: Gaurav Jindal --- drivers/cam_cpas/cpas_top/cpastop_v170_200.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h index 500fcd3bad2f..4d4f3dac4703 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h @@ -253,7 +253,7 @@ static struct cam_camnoc_specific .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2430, /* SPECIFIC_IFE01_PRIORITYLUT_LOW */ - .value = 0x66665643, + .value = 0x66665433, }, .priority_lut_high = { .enable = true, @@ -301,7 +301,7 @@ static struct cam_camnoc_specific .access_type = CAM_REG_TYPE_READ_WRITE, .masked_value = 0, .offset = 0x2630, /* SPECIFIC_IFE23_PRIORITYLUT_LOW */ - .value = 0x66665643, + .value = 0x66665433, }, .priority_lut_high = { .enable = true, @@ -366,7 +366,7 @@ static struct cam_camnoc_specific /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ .mask = 0x7, /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ - .shift = 0x4, + .shift = 0, .value = 3, }, .danger_lut = { -- GitLab From fed0c5af8722b9ad03ae0e76a48f9da8ff738a95 Mon Sep 17 00:00:00 2001 From: Sridhar Gujje Date: Mon, 30 Mar 2020 22:53:37 +0530 Subject: [PATCH 269/410] Revert "msm: camera: ife: IFE debug enhancement for overflow debugging" This reverts commit 8783850987dd900120ad0ef4591b00c76a08e433. Change-Id: I6ce75770a0121763eb0294f59e846e152f80fecd Signed-off-by: Sridhar Gujje --- drivers/cam_cpas/cam_cpas_hw.c | 71 +---------- drivers/cam_cpas/cam_cpas_hw.h | 6 - drivers/cam_cpas/cam_cpas_hw_intf.h | 1 - drivers/cam_cpas/cam_cpas_intf.c | 24 ---- drivers/cam_cpas/include/cam_cpas_api.h | 10 -- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 76 +----------- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 - .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 2 - .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h | 2 - .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 13 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 9 -- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 43 ------- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 95 ++++++++------- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c | 70 ----------- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 66 +--------- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 67 +---------- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 68 +---------- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 113 +----------------- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h | 9 -- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 28 +---- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 17 --- 21 files changed, 68 insertions(+), 724 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 63c6726feb87..05cf0416ea1e 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -83,7 +83,7 @@ static int cam_cpas_util_vote_bus_client_level( static int cam_cpas_util_vote_bus_client_bw( struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, - bool camnoc_bw, uint64_t *applied_ab, uint64_t *applied_ib) + bool camnoc_bw) { struct msm_bus_paths *path; struct msm_bus_scale_pdata *pdata; @@ -146,10 +146,6 @@ static int cam_cpas_util_vote_bus_client_bw( CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", bus_client->client_id, bus_client->name, ab, ib, idx); msm_bus_scale_client_update_request(bus_client->client_id, idx); - if (applied_ab) - *applied_ab = ab; - if (applied_ib) - *applied_ib = ib; return 0; } @@ -225,8 +221,7 @@ static int cam_cpas_util_unregister_bus_client( return -EINVAL; if (bus_client->dyn_vote) - cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false, - NULL, NULL); + cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); else cam_cpas_util_vote_bus_client_level(bus_client, 0); @@ -314,7 +309,6 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, int rc, i = 0; struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; uint64_t ab_bw, ib_bw; - uint64_t applied_ab_bw = 0, applied_ib_bw = 0; rc = cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, (enable == true) ? CAM_SVS_VOTE : CAM_SUSPEND_VOTE); @@ -335,15 +329,13 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, for (i = 0; i < cpas_core->num_axi_ports; i++) { rc = cam_cpas_util_vote_bus_client_bw( &cpas_core->axi_port[i].bus_client, - ab_bw, ib_bw, false, &applied_ab_bw, &applied_ib_bw); + ab_bw, ib_bw, false); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, rc=%d", enable, rc); goto remove_ahb_vote; } - cpas_core->axi_port[i].applied_ab_bw = applied_ab_bw; - cpas_core->axi_port[i].applied_ib_bw = applied_ib_bw; } return 0; @@ -509,8 +501,6 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); - - cpas_core->applied_camnoc_axi_rate = clk_rate; } } @@ -699,7 +689,6 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( int rc = 0; struct cam_cpas_axi_port *camnoc_axi_port = NULL; uint64_t camnoc_bw; - uint64_t applied_ab = 0, applied_ib = 0; if (soc_private->control_camnoc_axi_clk) { rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); @@ -740,7 +729,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( rc = cam_cpas_util_vote_bus_client_bw( &camnoc_axi_port->bus_client, - 0, camnoc_bw, true, &applied_ab, &applied_ib); + 0, camnoc_bw, true); CAM_DBG(CAM_CPAS, "camnoc vote camnoc_bw[%llu] rc=%d %s", @@ -751,8 +740,6 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( camnoc_bw, rc); break; } - camnoc_axi_port->applied_ab_bw = applied_ab; - camnoc_axi_port->applied_ib_bw = applied_ib; } return rc; } @@ -775,7 +762,6 @@ static int cam_cpas_util_apply_client_axi_vote( curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; int rc = 0, i = 0; - uint64_t applied_ab = 0, applied_ib = 0; mutex_lock(&cpas_core->tree_lock); if (!cpas_client->tree_node_valid) { @@ -951,16 +937,13 @@ static int cam_cpas_util_apply_client_axi_vote( rc = cam_cpas_util_vote_bus_client_bw( &mnoc_axi_port->bus_client, - mnoc_ab_bw, mnoc_ib_bw, false, &applied_ab, - &applied_ib); + mnoc_ab_bw, mnoc_ib_bw, false); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", mnoc_ab_bw, mnoc_ib_bw, rc); goto unlock_tree; } - mnoc_axi_port->applied_ab_bw = applied_ab; - mnoc_axi_port->applied_ib_bw = applied_ib; } rc = cam_cpas_camnoc_set_vote_axi_clk_rate( cpas_hw, camnoc_axi_port_updated); @@ -1707,46 +1690,6 @@ static int cam_cpas_hw_get_hw_info(void *hw_priv, return 0; } -static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw) -{ - struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; - struct cam_cpas_private_soc *soc_private = - (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; - int rc = 0; - uint32_t i; - - for (i = 0; i < cpas_core->num_axi_ports; i++) { - CAM_INFO(CAM_CPAS, - "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", - cpas_core->axi_port[i].axi_port_name, - cpas_core->axi_port[i].ab_bw, - cpas_core->axi_port[i].ib_bw, - cpas_core->axi_port[i].additional_bw, - cpas_core->axi_port[i].applied_ab_bw, - cpas_core->axi_port[i].applied_ib_bw); - } - - if (soc_private->control_camnoc_axi_clk) { - CAM_INFO(CAM_CPAS, "applied camnoc axi clk[%lld]", - cpas_core->applied_camnoc_axi_rate); - } else { - for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { - CAM_INFO(CAM_CPAS, - "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", - cpas_core->camnoc_axi_port[i].axi_port_name, - cpas_core->camnoc_axi_port[i].ab_bw, - cpas_core->camnoc_axi_port[i].ib_bw, - cpas_core->camnoc_axi_port[i].additional_bw, - cpas_core->camnoc_axi_port[i].applied_ab_bw, - cpas_core->camnoc_axi_port[i].applied_ib_bw); - } - } - - CAM_INFO(CAM_CPAS, "ahb client curr vote level[%d]", - cpas_core->ahb_bus_client.curr_vote_level); - - return rc; -} static int cam_cpas_hw_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -1850,10 +1793,6 @@ static int cam_cpas_hw_process_cmd(void *hw_priv, cmd_axi_vote->client_handle, cmd_axi_vote->axi_vote); break; } - case CAM_CPAS_HW_CMD_LOG_VOTE: { - rc = cam_cpas_log_vote(hw_priv); - break; - } default: CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type); break; diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index acad4ba44b17..cfa7dfbb69b2 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -155,8 +155,6 @@ struct cam_cpas_bus_client { * @ib_bw: IB bw value for this port * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients - * @applied_ab_bw: applied ab bw for this port - * @applied_ib_bw: applied ib bw for this port */ struct cam_cpas_axi_port { const char *axi_port_name; @@ -167,8 +165,6 @@ struct cam_cpas_axi_port { uint64_t ib_bw; uint64_t camnoc_bw; uint64_t additional_bw; - uint64_t applied_ab_bw; - uint64_t applied_ib_bw; }; /** @@ -193,7 +189,6 @@ struct cam_cpas_axi_port { * @irq_count_wq: wait variable to ensure all irq's are handled * @dentry: debugfs file entry * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus - * @applied_camnoc_axi_rate: applied camnoc axi clock rate */ struct cam_cpas { struct cam_cpas_hw_caps hw_caps; @@ -215,7 +210,6 @@ struct cam_cpas { wait_queue_head_t irq_count_wq; struct dentry *dentry; bool ahb_bus_scaling_disable; - uint64_t applied_camnoc_axi_rate; }; int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); diff --git a/drivers/cam_cpas/cam_cpas_hw_intf.h b/drivers/cam_cpas/cam_cpas_hw_intf.h index 3f644363062c..580242308346 100644 --- a/drivers/cam_cpas/cam_cpas_hw_intf.h +++ b/drivers/cam_cpas/cam_cpas_hw_intf.h @@ -38,7 +38,6 @@ enum cam_cpas_hw_cmd_process { CAM_CPAS_HW_CMD_REG_READ, CAM_CPAS_HW_CMD_AHB_VOTE, CAM_CPAS_HW_CMD_AXI_VOTE, - CAM_CPAS_HW_CMD_LOG_VOTE, CAM_CPAS_HW_CMD_INVALID, }; diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index d63ac2263355..402710d81741 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -392,30 +392,6 @@ int cam_cpas_start(uint32_t client_handle, } EXPORT_SYMBOL(cam_cpas_start); -void cam_cpas_log_votes(void) -{ - uint32_t dummy_args; - int rc; - - if (!CAM_CPAS_INTF_INITIALIZED()) { - CAM_ERR(CAM_CPAS, "cpas intf not initialized"); - return; - } - - if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { - rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( - g_cpas_intf->hw_intf->hw_priv, - CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args, - sizeof(dummy_args)); - if (rc) - CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); - } else { - CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); - } - -} -EXPORT_SYMBOL(cam_cpas_log_votes); - int cam_cpas_unregister_client(uint32_t client_handle) { int rc; diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index d36800bd13b8..67a2a50b5816 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -624,15 +624,5 @@ const char *cam_cpas_axi_util_path_type_to_string( const char *cam_cpas_axi_util_trans_type_to_string( uint32_t path_data_type); -/** - * cam_cpas_log_votes() - * - * @brief: API to print the all bw votes of axi client. It also print the - * applied camnoc axi clock vote value and ahb vote value - * - * @return 0 on success. - * - */ -void cam_cpas_log_votes(void); #endif /* _CAM_CPAS_API_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index c0e4cce9823d..a37dee5ccce9 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6732,87 +6732,15 @@ static int cam_ife_hw_mgr_find_affected_ctx( return 0; } -static int cam_ife_hw_mgr_handle_hw_dump_info( - void *ctx, - void *evt_info) -{ - struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = - (struct cam_ife_hw_mgr_ctx *)ctx; - struct cam_isp_hw_event_info *event_info = - (struct cam_isp_hw_event_info *)evt_info; - struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; - struct cam_isp_resource_node *rsrc_node = NULL; - struct cam_hw_intf *hw_intf; - uint32_t i, out_port_id; - int rc = 0; - - list_for_each_entry(hw_mgr_res, - &ife_hw_mgr_ctx->res_list_ife_src, list) { - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!hw_mgr_res->hw_res[i]) - continue; - - rsrc_node = hw_mgr_res->hw_res[i]; - if (rsrc_node->res_id == - CAM_ISP_HW_VFE_IN_CAMIF) { - hw_intf = rsrc_node->hw_intf; - if (hw_intf && - hw_intf->hw_ops.process_cmd) - rc = - hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_ISP_HW_CMD_CAMIF_DATA, - rsrc_node, - sizeof( - struct - cam_isp_resource_node)); - } - } - } - - - out_port_id = event_info->res_id & 0xFF; - hw_mgr_res = - &ife_hw_mgr_ctx->res_list_ife_out[out_port_id]; - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!hw_mgr_res->hw_res[i]) - continue; - hw_intf = hw_mgr_res->hw_res[i]->hw_intf; - if (hw_intf->hw_ops.process_cmd) { - rc = hw_intf->hw_ops.process_cmd( - hw_intf->hw_priv, - CAM_ISP_HW_CMD_DUMP_BUS_INFO, - (void *)event_info, - sizeof(struct cam_isp_hw_event_info)); - } - } - - return rc; -} - static int cam_ife_hw_mgr_handle_hw_err( - void *ctx, void *evt_info) { - struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx; struct cam_isp_hw_event_info *event_info = evt_info; - uint32_t core_idx; + uint32_t core_idx; struct cam_isp_hw_error_event_data error_event_data = {0}; struct cam_hw_event_recovery_data recovery_data = {0}; int rc = -EINVAL; - if (ctx) { - ife_hw_mgr_ctx = - (struct cam_ife_hw_mgr_ctx *)ctx; - if (event_info->res_type == - CAM_ISP_RESOURCE_VFE_IN && - !ife_hw_mgr_ctx->is_rdi_only_context && - event_info->res_id != - CAM_ISP_HW_VFE_IN_CAMIF) - cam_ife_hw_mgr_handle_hw_dump_info( - ife_hw_mgr_ctx, event_info); - } - if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) error_event_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_IN) @@ -7189,7 +7117,7 @@ static int cam_ife_hw_mgr_event_handler( break; case CAM_ISP_HW_EVENT_ERROR: - rc = cam_ife_hw_mgr_handle_hw_err(priv, evt_info); + rc = cam_ife_hw_mgr_handle_hw_err(evt_info); break; default: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 5ab4478408e6..fc6951b2fa1e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -94,10 +94,8 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, CAM_ISP_HW_CMD_UBWC_UPDATE, - CAM_ISP_HW_CMD_DUMP_BUS_INFO, CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, - CAM_ISP_HW_CMD_CAMIF_DATA, CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index fb7c4309bff7..cd32edbc0565 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -594,7 +594,6 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CORE_CONFIG: case CAM_ISP_HW_CMD_BW_UPDATE_V2: case CAM_ISP_HW_CMD_DUMP_HW: - case CAM_ISP_HW_CMD_CAMIF_DATA: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); @@ -606,7 +605,6 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_UBWC_UPDATE: case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: - case CAM_ISP_HW_CMD_DUMP_BUS_INFO: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h index eef02079628a..082c535cf3b5 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -24,7 +24,6 @@ * @cpas_version: Has cpas version read from Hardware * @ubwc_static_ctrl: UBWC static control configuration * @is_ife_lite: Flag to indicate full vs lite IFE - * @ife_clk_src: IFE source clock */ struct cam_vfe_soc_private { uint32_t cpas_handle; @@ -34,7 +33,6 @@ struct cam_vfe_soc_private { int32_t dsp_clk_rate; uint32_t ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX]; bool is_ife_lite; - uint64_t ife_clk_src; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index a65d7aa966fd..63df625221cc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -170,14 +170,6 @@ struct cam_vfe_top_dump_data vfe170_dump_data = { }, }; -static struct cam_vfe_rdi_overflow_status vfe170_rdi_irq_status = { - .rdi0_overflow_mask = 0x8, - .rdi1_overflow_mask = 0x10, - .rdi2_overflow_mask = 0x18, - .rdi3_overflow_mask = 0x20, - .rdi_overflow_mask = 0x3c, -}; - static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .common_reg = &vfe170_top_common_reg, .camif_hw_info = { @@ -191,9 +183,8 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .reg_data = NULL, }, .rdi_hw_info = { - .common_reg = &vfe170_top_common_reg, - .rdi_reg = &vfe170_rdi_reg, - .rdi_irq_status = &vfe170_rdi_irq_status, + .common_reg = &vfe170_top_common_reg, + .rdi_reg = &vfe170_rdi_reg, .reg_data = { &vfe_170_rdi_0_data, &vfe_170_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index b26592912c93..9512ad06c65e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -27,14 +27,6 @@ static struct cam_irq_register_set vfe175_130_top_irq_reg_set[2] = { }, }; -static struct cam_vfe_rdi_overflow_status vfe175_130_rdi_irq_status = { - .rdi0_overflow_mask = 0x8, - .rdi1_overflow_mask = 0x10, - .rdi2_overflow_mask = 0x18, - .rdi3_overflow_mask = 0x20, - .rdi_overflow_mask = 0x3c, -}; - static struct cam_irq_controller_reg_info vfe175_130_top_irq_reg_info = { .num_registers = 2, .irq_reg_set = vfe175_130_top_irq_reg_set, @@ -449,7 +441,6 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { .common_reg = &vfe175_130_top_common_reg, .rdi_reg = &vfe175_130_rdi_reg, .common_reg_data = &vfe175_130_rdi_reg_data, - .rdi_irq_status = &vfe175_130_rdi_irq_status, .reg_data = { &vfe_175_130_rdi_0_data, &vfe_175_130_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 34cd67665ba0..231ad336e54d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -143,8 +143,6 @@ struct cam_vfe_bus_ver2_wm_resource_data { uint32_t ubwc_lossy_threshold_0; uint32_t ubwc_lossy_threshold_1; uint32_t ubwc_bandwidth_limit; - uint32_t acquired_width; - uint32_t acquired_height; }; struct cam_vfe_bus_ver2_comp_grp_data { @@ -988,8 +986,6 @@ static int cam_vfe_bus_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; - rsrc_data->acquired_width = out_port_info->width; - rsrc_data->acquired_height = out_port_info->height; rsrc_data->is_dual = is_dual; /* Set WM offset value to default */ rsrc_data->offset = 0; @@ -3700,42 +3696,6 @@ static int __cam_vfe_bus_process_cmd(void *priv, return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); } -int cam_vfe_bus_dump_wm_data(void *priv, void *cmd_args, uint32_t arg_size) -{ - struct cam_vfe_bus_ver2_priv *bus_priv = - (struct cam_vfe_bus_ver2_priv *) priv; - struct cam_isp_hw_event_info *event_info = - (struct cam_isp_hw_event_info *)cmd_args; - struct cam_isp_resource_node *rsrc_node = NULL; - struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; - struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; - int i, wm_idx; - enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id; - - vfe_out_res_id = cam_vfe_bus_get_out_res_id(event_info->res_id); - rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; - rsrc_data = rsrc_node->res_priv; - for (i = 0; i < rsrc_data->num_wm; i++) { - wm_idx = cam_vfe_bus_get_wm_idx(vfe_out_res_id, i); - if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { - CAM_ERR(CAM_ISP, "Unsupported VFE out %d", - vfe_out_res_id); - return -EINVAL; - } - wm_data = bus_priv->bus_client[wm_idx].res_priv; - CAM_INFO(CAM_ISP, - "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", - wm_data->common_data->core_index, wm_idx, - wm_data->width, - wm_data->height, - wm_data->stride, wm_data->h_init, - wm_data->en_cfg, - wm_data->acquired_width, - wm_data->acquired_height); - } - return 0; -} - static int cam_vfe_bus_process_cmd( struct cam_isp_resource_node *priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -3774,9 +3734,6 @@ static int cam_vfe_bus_process_cmd( case CAM_ISP_HW_CMD_UBWC_UPDATE: rc = cam_vfe_bus_update_ubwc_config(cmd_args); break; - case CAM_ISP_HW_CMD_DUMP_BUS_INFO: - rc = cam_vfe_bus_dump_wm_data(priv, cmd_args, arg_size); - break; case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: rc = cam_vfe_bus_update_ubwc_config_v2(cmd_args); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 1b108e51e5a1..017ad12e9dd7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -128,8 +128,6 @@ struct cam_vfe_bus_ver3_wm_resource_data { uint32_t ubwc_lossy_threshold_1; uint32_t ubwc_offset_lossy_variance; uint32_t ubwc_bandwidth_limit; - uint32_t acquired_width; - uint32_t acquired_height; }; struct cam_vfe_bus_ver3_comp_grp_data { @@ -1132,8 +1130,6 @@ static int cam_vfe_bus_ver3_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; - rsrc_data->acquired_width = out_port_info->width; - rsrc_data->acquired_height = out_port_info->height; rsrc_data->is_dual = is_dual; /* Set WM offset value to default */ rsrc_data->offset = 0; @@ -2448,37 +2444,34 @@ static int cam_vfe_bus_ver3_deinit_vfe_out_resource( return 0; } -static int cam_vfe_bus_ver3_print_dimensions( +static void cam_vfe_bus_ver3_print_dimensions( enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, struct cam_vfe_bus_ver3_priv *bus_priv) { - struct cam_isp_resource_node *rsrc_node = NULL; - struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; - struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; - int i, wm_idx; + struct cam_isp_resource_node *wm_res = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + int wm_idx = 0; - rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; - rsrc_data = rsrc_node->res_priv; - for (i = 0; i < rsrc_data->num_wm; i++) { - wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, i, - bus_priv->common_data.is_lite); - if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { - CAM_ERR(CAM_ISP, "Unsupported VFE out %d", - vfe_out_res_id); - return -EINVAL; - } - wm_data = bus_priv->bus_client[wm_idx].res_priv; - CAM_INFO(CAM_ISP, - "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", - wm_data->common_data->core_index, wm_idx, - wm_data->width, - wm_data->height, - wm_data->stride, wm_data->h_init, - wm_data->en_cfg, - wm_data->acquired_width, - wm_data->acquired_height); + wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, plane, + bus_priv->common_data.is_lite); + + if (wm_idx < 0 || wm_idx >= bus_priv->num_client || plane > PLANE_C) { + CAM_ERR(CAM_ISP, + "Unsupported VFE out_type:0x%X plane:%d wm_idx:%d max_idx:%d", + vfe_out_res_id, plane, wm_idx, + bus_priv->num_client - 1); + return; } - return 0; + + wm_res = &bus_priv->bus_client[wm_idx]; + wm_data = wm_res->res_priv; + + CAM_INFO(CAM_ISP, + "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u", + wm_data->common_data->core_index, wm_idx, wm_data->width, + wm_data->height, wm_data->stride, wm_data->h_init, + wm_data->en_cfg); } static int cam_vfe_bus_ver3_handle_bus_irq(uint32_t evt_id, @@ -2584,6 +2577,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 0 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + PLANE_Y, bus_priv); } @@ -2592,6 +2586,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + PLANE_Y, bus_priv); } @@ -2600,6 +2595,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 2 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + PLANE_Y, bus_priv); } @@ -2608,6 +2604,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 3 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI3, + PLANE_Y, bus_priv); } } @@ -2642,6 +2639,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID Y 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL, + PLANE_Y, bus_priv); } @@ -2649,6 +2647,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID C 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL, + PLANE_C, bus_priv); } @@ -2656,6 +2655,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID YC 4:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS4, + PLANE_Y, bus_priv); } @@ -2663,6 +2663,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID YC 16:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS16, + PLANE_Y, bus_priv); } @@ -2670,6 +2671,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP Y 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + PLANE_Y, bus_priv); } @@ -2677,6 +2679,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP C 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + PLANE_C, bus_priv); } @@ -2684,6 +2687,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP YC 4:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, + PLANE_Y, bus_priv); } @@ -2691,6 +2695,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP YC 16:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, + PLANE_Y, bus_priv); } @@ -2698,6 +2703,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "FD Y image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FD, + PLANE_Y, bus_priv); } @@ -2705,6 +2711,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "FD C image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FD, + PLANE_C, bus_priv); } @@ -2713,6 +2720,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "PIXEL RAW DUMP image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, + PLANE_Y, bus_priv); } @@ -2720,6 +2728,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS HDR BE image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, + PLANE_Y, bus_priv); } @@ -2728,6 +2737,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "STATS HDR BHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, + PLANE_Y, bus_priv); } @@ -2736,6 +2746,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "STATS TINTLESS BG image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, + PLANE_Y, bus_priv); } @@ -2743,6 +2754,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS AWB BG image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, + PLANE_Y, bus_priv); } @@ -2750,6 +2762,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS BHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, + PLANE_Y, bus_priv); } @@ -2757,6 +2770,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS RS image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, + PLANE_Y, bus_priv); } @@ -2764,6 +2778,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS CS image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, + PLANE_Y, bus_priv); } @@ -2771,6 +2786,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS IHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, + PLANE_Y, bus_priv); } @@ -2778,6 +2794,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS BAF image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, + PLANE_Y, bus_priv); } @@ -2785,6 +2802,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "PD image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_2PD, + PLANE_Y, bus_priv); } @@ -2792,6 +2810,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "LCR image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_LCR, + PLANE_Y, bus_priv); } @@ -2799,6 +2818,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 0 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + PLANE_Y, bus_priv); } @@ -2806,6 +2826,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + PLANE_Y, bus_priv); } @@ -2813,6 +2834,7 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 2 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + PLANE_Y, bus_priv); } @@ -3718,19 +3740,6 @@ static int cam_vfe_bus_ver3_process_cmd( bus_priv->error_irq_handle = 0; } break; - case CAM_ISP_HW_CMD_DUMP_BUS_INFO: { - struct cam_isp_hw_event_info *event_info; - enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id; - - event_info = - (struct cam_isp_hw_event_info *)cmd_args; - bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; - vfe_out_res_id = - cam_vfe_bus_ver3_get_out_res_id(event_info->res_id); - rc = cam_vfe_bus_ver3_print_dimensions( - vfe_out_res_id, bus_priv); - break; - } case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: rc = cam_vfe_bus_ver3_update_ubwc_config_v2(cmd_args); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c index e4ff7255df5b..c7380f805938 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -36,7 +36,6 @@ struct cam_vfe_mux_camif_lite_data { evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; struct list_head free_payload_list; spinlock_t spin_lock; - struct timeval error_ts; }; static int cam_vfe_camif_lite_get_evt_payload( @@ -134,12 +133,6 @@ static int cam_vfe_camif_lite_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); - if (error_flag) { - camif_lite_priv->error_ts.tv_sec = - evt_payload->ts.mono_time.tv_sec; - camif_lite_priv->error_ts.tv_usec = - evt_payload->ts.mono_time.tv_usec; - } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -308,9 +301,6 @@ static int cam_vfe_camif_lite_resource_start( } } - rsrc_data->error_ts.tv_sec = 0; - rsrc_data->error_ts.tv_usec = 0; - CAM_DBG(CAM_ISP, "Start Camif Lite IFE %d Done", camif_lite_res->hw_intf->hw_idx); return rc; @@ -415,44 +405,6 @@ static int cam_vfe_camif_lite_handle_irq_top_half(uint32_t evt_id, return rc; } -static int cam_vfe_camif_lite_cpas_fifo_levels_reg_dump( - struct cam_vfe_mux_camif_lite_data *camif_lite_priv) -{ - struct cam_vfe_soc_private *soc_private = - camif_lite_priv->soc_info->soc_private; - uint32_t val; - - if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || - soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); - CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", - val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); - CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", - val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); - CAM_INFO(CAM_ISP, - "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); - - } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x420, true, &val); - CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x820, true, &val); - CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); - } - - return 0; - -} - static int cam_vfe_camif_lite_handle_irq_bottom_half( void *handler_priv, void *evt_payload_priv) @@ -464,9 +416,6 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( struct cam_isp_hw_event_info evt_info; uint32_t irq_status0; uint32_t irq_status1; - struct cam_hw_soc_info *soc_info = NULL; - struct cam_vfe_soc_private *soc_private = NULL; - struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -478,9 +427,6 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( payload = evt_payload_priv; irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; - soc_info = camif_lite_priv->soc_info; - soc_private = - (struct cam_vfe_soc_private *)soc_info->soc_private; evt_info.hw_idx = camif_lite_node->hw_intf->hw_idx; evt_info.res_id = camif_lite_node->res_id; @@ -518,27 +464,11 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE Received ERROR", evt_info.hw_idx); - cam_vfe_camif_lite_cpas_fifo_levels_reg_dump(camif_lite_priv); - - ktime_get_boottime_ts64(&ts); - CAM_INFO(CAM_ISP, - "current monotonic time stamp seconds %lld:%lld", - ts.tv_sec, ts.tv_nsec/1000); - CAM_INFO(CAM_ISP, - "ERROR time %lld:%lld", - camif_lite_priv->error_ts.tv_sec, - camif_lite_priv->error_ts.tv_usec); - CAM_INFO(CAM_ISP, "ife_clk_src:%lld", - soc_private->ife_clk_src); - if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); ret = CAM_VFE_IRQ_STATUS_OVERFLOW; - - cam_cpas_log_votes(); - } cam_vfe_camif_lite_put_evt_payload(camif_lite_priv, &payload); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index b54c43a145bc..1617e84a0ebc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -40,10 +40,6 @@ struct cam_vfe_mux_camif_lite_data { uint32_t camif_debug; struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; - struct timeval sof_ts; - struct timeval epoch_ts; - struct timeval eof_ts; - struct timeval error_ts; }; static int cam_vfe_camif_lite_get_evt_payload( @@ -141,12 +137,6 @@ static int cam_vfe_camif_lite_err_irq_top_half( return rc; cam_isp_hw_get_timestamp(&evt_payload->ts); - if (error_flag) { - camif_lite_priv->error_ts.tv_sec = - evt_payload->ts.mono_time.tv_sec; - camif_lite_priv->error_ts.tv_usec = - evt_payload->ts.mono_time.tv_usec; - } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -303,15 +293,6 @@ static int cam_vfe_camif_lite_resource_start( rsrc_data->mem_base + rsrc_data->camif_lite_reg->lite_epoch_irq); - rsrc_data->error_ts.tv_sec = 0; - rsrc_data->error_ts.tv_usec = 0; - rsrc_data->sof_ts.tv_sec = 0; - rsrc_data->sof_ts.tv_usec = 0; - rsrc_data->epoch_ts.tv_sec = 0; - rsrc_data->epoch_ts.tv_usec = 0; - rsrc_data->eof_ts.tv_sec = 0; - rsrc_data->eof_ts.tv_usec = 0; - skip_core_cfg: camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; @@ -907,7 +888,6 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); - cam_cpas_log_votes(); } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { @@ -1082,8 +1062,6 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( struct cam_vfe_soc_private *soc_private = NULL; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; int i = 0; - uint32_t status_0 = 0; - struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -1119,10 +1097,6 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received SOF", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; - camif_lite_priv->sof_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_lite_priv->sof_ts.tv_usec = - payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, @@ -1134,10 +1108,6 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EPOCH", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; - camif_lite_priv->epoch_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_lite_priv->epoch_ts.tv_usec = - payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, @@ -1149,50 +1119,18 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EOF", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; - camif_lite_priv->eof_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_lite_priv->eof_ts.tv_usec = - payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); } - status_0 = irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] - & camif_lite_priv->reg_data->error_irq_mask0; - if (status_0) { + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_lite_priv->reg_data->error_irq_mask0) { CAM_ERR(CAM_ISP, "VFE:%d Overflow", camif_lite_node->hw_intf->hw_idx); evt_info.err_type = CAM_VFE_IRQ_STATUS_OVERFLOW; - ktime_get_boottime_ts64(&ts); - CAM_INFO(CAM_ISP, - "current monotonic time stamp seconds %lld:%lld", - ts.tv_sec, ts.tv_nsec/1000); - CAM_INFO(CAM_ISP, - "ERROR time %lld:%lld", - camif_lite_priv->error_ts.tv_sec, - camif_lite_priv->error_ts.tv_usec); - - if (camif_lite_node->rdi_only_ctx) - CAM_INFO(CAM_ISP, - "SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", - camif_lite_priv->sof_ts.tv_sec, - camif_lite_priv->sof_ts.tv_usec, - camif_lite_priv->epoch_ts.tv_sec, - camif_lite_priv->epoch_ts.tv_usec, - camif_lite_priv->eof_ts.tv_sec, - camif_lite_priv->eof_ts.tv_usec); - - if (status_0 & 0x8000000) - evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_2; - - if (status_0 & 0x10000000) - evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_1; - - if (status_0 & 0x20000000) - evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_0; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 3f9a94aece9f..23cf5d1642f4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -50,10 +50,6 @@ struct cam_vfe_mux_camif_data { uint32_t camif_debug; uint32_t dual_hw_idx; uint32_t is_dual; - struct timeval sof_ts; - struct timeval epoch_ts; - struct timeval eof_ts; - struct timeval error_ts; }; static int cam_vfe_camif_get_evt_payload( @@ -148,12 +144,6 @@ static int cam_vfe_camif_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); - if (error_flag) { - camif_priv->error_ts.tv_sec = - evt_payload->ts.mono_time.tv_sec; - camif_priv->error_ts.tv_usec = - evt_payload->ts.mono_time.tv_usec; - } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -303,14 +293,6 @@ static int cam_vfe_camif_resource_init( if (rc) CAM_ERR(CAM_ISP, "failed to enable dsp clk"); } - camif_data->sof_ts.tv_sec = 0; - camif_data->sof_ts.tv_usec = 0; - camif_data->epoch_ts.tv_sec = 0; - camif_data->epoch_ts.tv_usec = 0; - camif_data->eof_ts.tv_sec = 0; - camif_data->eof_ts.tv_usec = 0; - camif_data->error_ts.tv_sec = 0; - camif_data->error_ts.tv_usec = 0; return rc; } @@ -644,26 +626,6 @@ static int cam_vfe_camif_sof_irq_debug( return 0; } -int cam_vfe_camif_dump_timestamps( - struct cam_isp_resource_node *rsrc_node, void *cmd_args) -{ - struct cam_vfe_mux_camif_data *camif_priv = - (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; - - CAM_INFO(CAM_ISP, - "CAMIF ERROR time %lld:%lld SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", - camif_priv->error_ts.tv_sec, - camif_priv->error_ts.tv_usec, - camif_priv->sof_ts.tv_sec, - camif_priv->sof_ts.tv_usec, - camif_priv->epoch_ts.tv_sec, - camif_priv->epoch_ts.tv_usec, - camif_priv->eof_ts.tv_sec, - camif_priv->eof_ts.tv_usec); - - return 0; -} - static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -688,9 +650,6 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; camif_priv->camif_debug = *((uint32_t *)cmd_args); break; - case CAM_ISP_HW_CMD_CAMIF_DATA: - rc = cam_vfe_camif_dump_timestamps(rsrc_node, cmd_args); - break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -746,7 +705,6 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, uint32_t irq_status0; uint32_t irq_status1; uint32_t val; - struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -768,10 +726,6 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { CAM_DBG(CAM_ISP, "Received EOF"); - camif_priv->eof_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_priv->eof_ts.tv_usec = - payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -793,13 +747,8 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, false; camif_priv->irq_debug_cnt = 0; } - } else { + } else CAM_DBG(CAM_ISP, "Received SOF"); - camif_priv->sof_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_priv->sof_ts.tv_usec = - payload->ts.mono_time.tv_usec; - } if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -820,10 +769,6 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "Received EPOCH"); - camif_priv->epoch_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_priv->epoch_ts.tv_usec = - payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -835,11 +780,6 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->error_irq_mask0) { CAM_DBG(CAM_ISP, "Received ERROR"); - ktime_get_boottime_ts64(&ts); - CAM_INFO(CAM_ISP, - "current monotonic time stamp seconds %lld:%lld", - ts.tv_sec, ts.tv_nsec/1000); - if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); @@ -855,11 +795,6 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { CAM_DBG(CAM_ISP, "Received ERROR"); - ktime_get_boottime_ts64(&ts); - CAM_INFO(CAM_ISP, - "current monotonic time stamp seconds %lld:%lld", - ts.tv_sec, ts.tv_nsec/1000); - if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index de4299a47034..fd7aaaf27cde 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -55,10 +55,6 @@ struct cam_vfe_mux_camif_ver3_data { uint32_t qcfa_bin; bool is_fe_enabled; bool is_offline; - struct timeval sof_ts; - struct timeval epoch_ts; - struct timeval eof_ts; - struct timeval error_ts; }; static int cam_vfe_camif_ver3_get_evt_payload( @@ -144,12 +140,6 @@ static int cam_vfe_camif_ver3_err_irq_top_half( return rc; cam_isp_hw_get_timestamp(&evt_payload->ts); - if (error_flag) { - camif_priv->error_ts.tv_sec = - evt_payload->ts.mono_time.tv_sec; - camif_priv->error_ts.tv_usec = - evt_payload->ts.mono_time.tv_usec; - } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -306,14 +296,6 @@ static int cam_vfe_camif_ver3_resource_init( CAM_ERR(CAM_ISP, "failed to enable dsp clk, rc = %d", rc); } - camif_data->sof_ts.tv_sec = 0; - camif_data->sof_ts.tv_usec = 0; - camif_data->epoch_ts.tv_sec = 0; - camif_data->epoch_ts.tv_usec = 0; - camif_data->eof_ts.tv_sec = 0; - camif_data->eof_ts.tv_usec = 0; - camif_data->error_ts.tv_sec = 0; - camif_data->error_ts.tv_usec = 0; return rc; } @@ -764,26 +746,6 @@ static int cam_vfe_camif_ver3_sof_irq_debug( return 0; } -int cam_vfe_camif_ver3_dump_timestamps( - struct cam_isp_resource_node *rsrc_node, void *cmd_args) -{ - struct cam_vfe_mux_camif_ver3_data *camif_priv = - (struct cam_vfe_mux_camif_ver3_data *)rsrc_node->res_priv; - - CAM_INFO(CAM_ISP, - "CAMIF ERROR time %lld:%lld SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", - camif_priv->error_ts.tv_sec, - camif_priv->error_ts.tv_usec, - camif_priv->sof_ts.tv_sec, - camif_priv->sof_ts.tv_usec, - camif_priv->epoch_ts.tv_sec, - camif_priv->epoch_ts.tv_usec, - camif_priv->eof_ts.tv_sec, - camif_priv->eof_ts.tv_usec); - - return 0; -} - static int cam_vfe_camif_ver3_process_cmd( struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -820,9 +782,6 @@ static int cam_vfe_camif_ver3_process_cmd( *((struct cam_hw_soc_info **)cmd_args) = camif_priv->soc_info; rc = 0; break; - case CAM_ISP_HW_CMD_CAMIF_DATA: - rc = cam_vfe_camif_ver3_dump_timestamps(rsrc_node, cmd_args); - break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -984,7 +943,6 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); - cam_cpas_log_votes(); return; } @@ -1296,7 +1254,6 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; - struct timespec64 ts; uint32_t val = 0; int i = 0; @@ -1334,14 +1291,9 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, false; camif_priv->irq_debug_cnt = 0; } - } else { + } else CAM_DBG(CAM_ISP, "VFE:%d Received SOF", evt_info.hw_idx); - camif_priv->sof_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_priv->sof_ts.tv_usec = - payload->ts.mono_time.tv_usec; - } if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1354,10 +1306,6 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); evt_info.th_reg_val = payload->th_reg_val; - camif_priv->epoch_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_priv->epoch_ts.tv_usec = - payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1369,10 +1317,6 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->eof_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EOF", evt_info.hw_idx); - camif_priv->eof_ts.tv_sec = - payload->ts.mono_time.tv_sec; - camif_priv->eof_ts.tv_usec = - payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1385,11 +1329,6 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, & camif_priv->reg_data->error_irq_mask0) { CAM_ERR(CAM_ISP, "VFE:%d Overflow", evt_info.hw_idx); - ktime_get_boottime_ts64(&ts); - CAM_INFO(CAM_ISP, - "current monotonic time stamp seconds %lld:%lld", - ts.tv_sec, ts.tv_nsec/1000); - if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); @@ -1414,11 +1353,6 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); - ktime_get_boottime_ts64(&ts); - CAM_INFO(CAM_ISP, - "current monotonic time stamp seconds %lld:%lld", - ts.tv_sec, ts.tv_nsec/1000); - if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index b766c1ee844b..1b6b8ba3e3d6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -21,9 +21,7 @@ struct cam_vfe_mux_rdi_data { struct cam_vfe_top_ver2_reg_offset_common *common_reg; struct cam_vfe_rdi_ver2_reg *rdi_reg; struct cam_vfe_rdi_common_reg_data *rdi_common_reg_data; - struct cam_vfe_rdi_overflow_status *rdi_irq_status; struct cam_vfe_rdi_reg_data *reg_data; - struct cam_hw_soc_info *soc_info; cam_hw_mgr_event_cb_func event_cb; void *priv; @@ -35,8 +33,6 @@ struct cam_vfe_mux_rdi_data { spinlock_t spin_lock; enum cam_isp_hw_sync_mode sync_mode; - struct timeval sof_ts; - struct timeval error_ts; }; static int cam_vfe_rdi_get_evt_payload( @@ -85,44 +81,6 @@ static int cam_vfe_rdi_put_evt_payload( return 0; } -static int cam_vfe_rdi_cpas_reg_dump( -struct cam_vfe_mux_rdi_data *rdi_priv) -{ - struct cam_vfe_soc_private *soc_private = - rdi_priv->soc_info->soc_private; - uint32_t val; - - if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || - soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); - CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", - val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); - CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", - val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); - CAM_INFO(CAM_ISP, - "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); - - } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x420, true, &val); - CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x820, true, &val); - CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); - } - - return 0; - -} - static int cam_vfe_rdi_err_irq_top_half( uint32_t evt_id, struct cam_irq_th_payload *th_payload) @@ -166,12 +124,6 @@ static int cam_vfe_rdi_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); - if (error_flag) { - rdi_priv->error_ts.tv_sec = - evt_payload->ts.mono_time.tv_sec; - rdi_priv->error_ts.tv_usec = - evt_payload->ts.mono_time.tv_usec; - } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -330,11 +282,6 @@ static int cam_vfe_rdi_resource_start( } } - rsrc_data->sof_ts.tv_sec = 0; - rsrc_data->sof_ts.tv_usec = 0; - rsrc_data->error_ts.tv_sec = 0; - rsrc_data->error_ts.tv_usec = 0; - CAM_DBG(CAM_ISP, "Start RDI %d", rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0); end: @@ -445,11 +392,6 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status0; - uint32_t irq_status1; - uint32_t irq_rdi_status; - struct cam_hw_soc_info *soc_info = NULL; - struct cam_vfe_soc_private *soc_private = NULL; - struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -459,12 +401,8 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, rdi_node = handler_priv; rdi_priv = rdi_node->res_priv; payload = evt_payload_priv; - soc_info = rdi_priv->soc_info; - soc_private = - (struct cam_vfe_soc_private *)soc_info->soc_private; irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; - irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; evt_info.hw_idx = rdi_node->hw_intf->hw_idx; evt_info.res_id = rdi_node->res_id; @@ -474,10 +412,7 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & rdi_priv->reg_data->sof_irq_mask) { CAM_DBG(CAM_ISP, "Received SOF"); - rdi_priv->sof_ts.tv_sec = - payload->ts.mono_time.tv_sec; - rdi_priv->sof_ts.tv_usec = - payload->ts.mono_time.tv_usec; + if (rdi_priv->event_cb) rdi_priv->event_cb(rdi_priv->priv, CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); @@ -495,50 +430,6 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_SUCCESS; } - irq_rdi_status = - (irq_status1 & - rdi_priv->rdi_irq_status->rdi_overflow_mask); - if (irq_rdi_status) { - ktime_get_boottime_ts64(&ts); - CAM_INFO(CAM_ISP, - "current monotonic time stamp seconds %lld:%lld", - ts.tv_sec, ts.tv_nsec/1000); - - cam_vfe_rdi_cpas_reg_dump(rdi_priv); - - CAM_INFO(CAM_ISP, "ife_clk_src:%lld", - soc_private->ife_clk_src); - CAM_INFO(CAM_ISP, - "ERROR time %lld:%lld SOF %lld:%lld", - rdi_priv->error_ts.tv_sec, - rdi_priv->error_ts.tv_usec, - rdi_priv->sof_ts.tv_sec, - rdi_priv->sof_ts.tv_usec); - - if (irq_rdi_status & - rdi_priv->rdi_irq_status->rdi0_overflow_mask) { - evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_0; - } - else if (irq_rdi_status & - rdi_priv->rdi_irq_status->rdi1_overflow_mask) { - evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_1; - } - else if (irq_rdi_status & - rdi_priv->rdi_irq_status->rdi2_overflow_mask) { - evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_2; - } - else if (irq_rdi_status & - rdi_priv->rdi_irq_status->rdi3_overflow_mask) { - evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_3; - } - - if (rdi_priv->event_cb) - rdi_priv->event_cb(rdi_priv->priv, - CAM_ISP_HW_EVENT_ERROR, - (void *)&evt_info); - cam_cpas_log_votes(); - } - cam_vfe_rdi_put_evt_payload(rdi_priv, &payload); CAM_DBG(CAM_ISP, "returing status = %d", ret); return ret; @@ -570,8 +461,6 @@ int cam_vfe_rdi_ver2_init( rdi_priv->rdi_reg = rdi_info->rdi_reg; rdi_priv->vfe_irq_controller = vfe_irq_controller; rdi_priv->rdi_common_reg_data = rdi_info->common_reg_data; - rdi_priv->soc_info = soc_info; - rdi_priv->rdi_irq_status = rdi_info->rdi_irq_status; switch (rdi_node->res_id) { case CAM_ISP_HW_VFE_IN_RDI0: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h index 70a2cb756cea..f002b3218ab4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h @@ -17,14 +17,6 @@ struct cam_vfe_rdi_ver2_reg { uint32_t reg_update_cmd; }; -struct cam_vfe_rdi_overflow_status { - uint32_t rdi0_overflow_mask; - uint32_t rdi1_overflow_mask; - uint32_t rdi2_overflow_mask; - uint32_t rdi3_overflow_mask; - uint32_t rdi_overflow_mask; -}; - struct cam_vfe_rdi_common_reg_data { uint32_t subscribe_irq_mask0; uint32_t subscribe_irq_mask1; @@ -43,7 +35,6 @@ struct cam_vfe_rdi_ver2_hw_info { struct cam_vfe_top_ver2_reg_offset_common *common_reg; struct cam_vfe_rdi_ver2_reg *rdi_reg; struct cam_vfe_rdi_common_reg_data *common_reg_data; - struct cam_vfe_rdi_overflow_status *rdi_irq_status; struct cam_vfe_rdi_reg_data *reg_data[CAM_VFE_RDI_VER2_MAX]; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 50a343290cc5..332332cfccc0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -83,11 +83,8 @@ static int cam_vfe_top_set_hw_clk_rate( struct cam_hw_soc_info *soc_info = NULL; int i, rc = 0; unsigned long max_clk_rate = 0; - struct cam_vfe_soc_private *soc_private = NULL; soc_info = top_priv->common_data.soc_info; - soc_private = - (struct cam_vfe_soc_private *)soc_info->soc_private; for (i = 0; i < top_priv->top_common.num_mux; i++) { if (top_priv->req_clk_rate[i] > max_clk_rate) @@ -99,7 +96,7 @@ static int cam_vfe_top_set_hw_clk_rate( CAM_DBG(CAM_PERF, "VFE: Clock name=%s idx=%d clk=%llu", soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); - soc_private->ife_clk_src = max_clk_rate; + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); if (!rc) @@ -182,19 +179,6 @@ static int cam_vfe_top_mux_get_reg_update( return -EINVAL; } -static int cam_vfe_top_get_data( - struct cam_vfe_top_ver2_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_isp_resource_node *res = cmd_args; - - if (res->process_cmd) - return res->process_cmd(res, - CAM_ISP_HW_CMD_CAMIF_DATA, cmd_args, arg_size); - - return -EINVAL; -} - int cam_vfe_top_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -559,8 +543,6 @@ int cam_vfe_top_stop(void *device_priv, struct cam_vfe_top_ver2_priv *top_priv; struct cam_isp_resource_node *mux_res; struct cam_hw_info *hw_info = NULL; - struct cam_hw_soc_info *soc_info = NULL; - struct cam_vfe_soc_private *soc_private = NULL; int i, rc = 0; if (!device_priv || !stop_args) { @@ -571,8 +553,6 @@ int cam_vfe_top_stop(void *device_priv, top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; mux_res = (struct cam_isp_resource_node *)stop_args; hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; - soc_info = top_priv->common_data.soc_info; - soc_private = soc_info->soc_private; if ((mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || (mux_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) || @@ -603,7 +583,7 @@ int cam_vfe_top_stop(void *device_priv, } } } - soc_private->ife_clk_src = 0; + return rc; } @@ -647,10 +627,6 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args, arg_size); break; - case CAM_ISP_HW_CMD_CAMIF_DATA: - rc = cam_vfe_top_get_data(top_priv, cmd_args, - arg_size); - break; case CAM_ISP_HW_CMD_CLOCK_UPDATE: rc = cam_vfe_top_clock_update(top_priv, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index dd22109c1d67..dc15cab5e2f4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -212,19 +212,6 @@ static int cam_vfe_top_ver3_mux_get_reg_update( return -EINVAL; } -static int cam_vfe_top_ver3_get_data( - struct cam_vfe_top_ver3_priv *top_priv, - void *cmd_args, uint32_t arg_size) -{ - struct cam_isp_resource_node *res = cmd_args; - - if (res->process_cmd) - return res->process_cmd(res, - CAM_ISP_HW_CMD_CAMIF_DATA, cmd_args, arg_size); - - return -EINVAL; -} - int cam_vfe_top_ver3_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -551,10 +538,6 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_ver3_mux_get_reg_update(top_priv, cmd_args, arg_size); break; - case CAM_ISP_HW_CMD_CAMIF_DATA: - rc = cam_vfe_top_ver3_get_data(top_priv, cmd_args, - arg_size); - break; case CAM_ISP_HW_CMD_CLOCK_UPDATE: rc = cam_vfe_top_ver3_clock_update(top_priv, cmd_args, arg_size); -- GitLab From 5f81e5f17fb34300bcd431aa6ba32d267fa61aa4 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Thu, 2 Apr 2020 03:01:15 +0530 Subject: [PATCH 270/410] msm: camera: ife: validate the ife bw num paths If ife bandwidth number of paths configuration is zero then do not proceed. Number of bandwidth paths should be minimum one and should not be greater than max value. CRs-Fixed: 2602752 Change-Id: I1f28e2c2558ace983c12957b0610e6cd5755c17f Signed-off-by: Wyes Karny --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index a37dee5ccce9..2f02d60be67e 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -5448,7 +5448,8 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, bw_config = (struct cam_isp_bw_config_v2 *)blob_data; - if (bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES) { + if ((bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES) || + !bw_config->num_paths) { CAM_ERR(CAM_ISP, "Invalid num paths %d", bw_config->num_paths); return -EINVAL; -- GitLab From c674a44d613d1d53a656a54e5ed48d4034824d87 Mon Sep 17 00:00:00 2001 From: Rishabh Jain Date: Mon, 6 Apr 2020 13:41:26 +0530 Subject: [PATCH 271/410] msm: camera: cpas: Add mandatory bw option for axi ports clocks Bw voting is mandatory to enable rt_axi and nrt_axi clocks. Adding support for the same. Change-Id: I236b3940faea3925e668e0e5ddbf61e8e569b2f7 CRs-Fixed: 2585073 Signed-off-by: Gaurav Jindal Signed-off-by: Rishabh Jain --- drivers/cam_cpas/cam_cpas_hw.c | 73 ++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 05cf0416ea1e..fa840f944757 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -955,6 +955,70 @@ static int cam_cpas_util_apply_client_axi_vote( return rc; } +static int cam_cpas_util_apply_default_axi_vote( + struct cam_hw_info *cpas_hw, bool enable) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_axi_port *axi_port = NULL; + uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0; + uint64_t camnoc_ab_bw = 0, camnoc_ib_bw = 0; + int rc = 0, i = 0; + + mutex_lock(&cpas_core->tree_lock); + for (i = 0; i < cpas_core->num_axi_ports; i++) { + if (!cpas_core->axi_port[i].ab_bw || + !cpas_core->axi_port[i].ib_bw) + axi_port = &cpas_core->axi_port[i]; + else + continue; + + if (enable) + mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + mnoc_ib_bw = 0; + + CAM_DBG(CAM_CPAS, "Port=[%s] :ab[%llu] ib[%llu]", + axi_port->axi_port_name, mnoc_ab_bw, mnoc_ib_bw); + + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, + mnoc_ab_bw, mnoc_ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", + mnoc_ab_bw, mnoc_ib_bw, rc); + goto unlock_tree; + } + } + + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + if (!cpas_core->camnoc_axi_port[i].ab_bw || + !cpas_core->camnoc_axi_port[i].ib_bw) + axi_port = &cpas_core->camnoc_axi_port[i]; + else + continue; + + if (enable) + camnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + camnoc_ib_bw = 0; + + CAM_DBG(CAM_CPAS, "Port=[%s] :ab[%llu] ib[%llu]", + axi_port->axi_port_name, camnoc_ab_bw, camnoc_ib_bw); + + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, + camnoc_ab_bw, camnoc_ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in camnoc vote ab[%llu] ib[%llu] rc=%d", + camnoc_ab_bw, camnoc_ib_bw, rc); + goto unlock_tree; + } + } +unlock_tree: + mutex_unlock(&cpas_core->tree_lock); + return rc; +} + static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, uint32_t client_handle, struct cam_axi_vote *client_axi_vote) { @@ -1334,6 +1398,10 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, goto remove_ahb_vote; if (cpas_core->streamon_clients == 0) { + rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, true); + if (rc) + goto remove_ahb_vote; + atomic_set(&cpas_core->irq_count, 1); rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, applied_level); @@ -1513,6 +1581,11 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); + if (rc) + goto done; + + if (cpas_core->streamon_clients == 0) + rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, false); done: mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); -- GitLab From bba4a91237b48edba2868412129a43dfe575a0ec Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Tue, 24 Dec 2019 16:54:55 +0530 Subject: [PATCH 272/410] msm: camera: isp: Ignore other csid irq errors during csid top reset During global reset, csi rx irq bits are set since sensor/phy was not reset properly in last closure and sending some data. This can lead to csid fatal or non-fatal errors. To avoid this condition, ignore other csid irq errors during csid top reset. CRs-Fixed: 2585726 Change-Id: I5e09caf3b374407ece8ff1b871c2cf7e0f1837ac Signed-off-by: Chandan Kumar Jha Signed-off-by: Depeng Shao --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 12 ++++++++++++ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index b78f5dee2837..615beb48b126 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -3292,6 +3292,8 @@ static int cam_ife_csid_reset_regs( spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + csid_hw->is_resetting = true; + /* clear the top interrupt first */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); @@ -3355,6 +3357,7 @@ static int cam_ife_csid_reset_regs( rem_jiffies); end: + csid_hw->is_resetting = false; return rc; } @@ -4055,6 +4058,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (irq_status_top & CSID_TOP_IRQ_DONE) { CAM_DBG(CAM_ISP, "csid top reset complete"); complete(&csid_hw->csid_top_complete); + csid_hw->is_resetting = false; + return IRQ_HANDLED; + } + + if (csid_hw->is_resetting) { + CAM_DBG(CAM_ISP, "CSID:%d is resetting, IRQ Handling exit", + csid_hw->hw_intf->hw_idx); + return IRQ_HANDLED; } if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { @@ -4436,6 +4447,7 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->device_enabled = 0; + ife_csid_hw->is_resetting = false; ife_csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; mutex_init(&ife_csid_hw->hw_info->hw_mutex); spin_lock_init(&ife_csid_hw->hw_info->hw_lock); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 885cd07b6ff7..01035c7c2fe6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -549,6 +549,7 @@ struct cam_ife_csid_path_cfg { * @clk_rate Clock rate * @sof_irq_triggered: Flag is set on receiving event to enable sof irq * incase of SOF freeze. + * @is_resetting: informs whether reset is started or not. * @irq_debug_cnt: Counter to track sof irq's when above flag is set. * @error_irq_count Error IRQ count, if continuous error irq comes * need to stop the CSID and mask interrupts. @@ -582,6 +583,7 @@ struct cam_ife_csid_hw { uint64_t csid_debug; uint64_t clk_rate; bool sof_irq_triggered; + bool is_resetting; uint32_t irq_debug_cnt; uint32_t error_irq_count; uint32_t device_enabled; -- GitLab From 365821a1ae080e7e55f0d20b8e91c90b6e70fdb9 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Thu, 19 Mar 2020 19:10:12 +0530 Subject: [PATCH 273/410] msm: camera: isp: Adds stats DMI and cfg dump info Adds dmi and stats cfg register info for lagoon target. This info is used to dump debug data on stats violation. CRs-Fixed: 2654573 Change-Id: I5eb0c93daacd4a514e5e4af8d7283e256443d211 Signed-off-by: Trishansh Bhardwaj --- .../isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 163 ++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 279 ++++++++++-------- 2 files changed, 325 insertions(+), 117 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h index 4c34411a793d..fab29ff17eab 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -105,6 +105,169 @@ struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_150_reg = { .enable = 0x0000004C, }; +/*Check offsets and values*/ +static struct cam_vfe_bus_ver2_stats_cfg_info stats_170_150_info = { + .dmi_offset_info = { + .auto_increment = 0x00000100, + .cfg_offset = 0x00000C24, + .addr_offset = 0x00000C28, + .data_hi_offset = 0x00000C2C, + .data_lo_offset = 0x00000C30, + }, + .stats_cfg_offset = { + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI0 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI1 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI2 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI3 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FD */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_PDAF */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .cfg_offset = 0x00000AB8, + .num_cfg = 0x00000ABC, + .cfg_size = 0x00000AC0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST */ + { + .res_index = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .cfg_offset = 0x00000AD4, + .num_cfg = 0x00000AD8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x36, + .bank_1 = 0x37, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .cfg_offset = 0x00000AE4, + .num_cfg = 0x00000000, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x40, + .bank_1 = 0x41, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .cfg_offset = 0x00000BC8, + .num_cfg = 0x00000BCC, + .cfg_size = 0x00000BD0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .cfg_offset = 0x00000BE4, + .num_cfg = 0x00000BE8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3A, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .cfg_offset = 0x00000BEC, + .num_cfg = 0x00000BF0, + .cfg_size = 0x00000BF4, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .cfg_offset = 0x00000BF8, + .num_cfg = 0x00000BFC, + .cfg_size = 0x00000C00, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .cfg_offset = 0x00000C04, + .num_cfg = 0x00000C08, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3B, + .bank_1 = 0x3C, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_2PD */ + { + }, + }, +}; + static struct cam_vfe_top_ver2_reg_offset_common vfe170_150_top_common_reg = { .hw_version = 0x00000000, .hw_capability = 0x00000004, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 231ad336e54d..0b6569027b7e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1411,8 +1411,8 @@ static int cam_vfe_bus_err_bottom_half(void *handler_priv, struct cam_vfe_bus_ver2_priv *bus_priv = handler_priv; struct cam_vfe_bus_ver2_common_data *common_data; struct cam_isp_hw_event_info evt_info; - struct cam_vfe_bus_ver2_stats_cfg_offset *stats_cfg; - struct cam_vfe_bus_ver2_dmi_offset_common dmi_cfg; + struct cam_vfe_bus_ver2_stats_cfg_offset *stats_cfg = NULL; + struct cam_vfe_bus_ver2_dmi_offset_common dmi_cfg = {0}; uint32_t val = 0; if (!handler_priv || !evt_payload_priv) @@ -1421,8 +1421,13 @@ static int cam_vfe_bus_err_bottom_half(void *handler_priv, evt_payload = evt_payload_priv; common_data = &bus_priv->common_data; - stats_cfg = common_data->stats_data->stats_cfg_offset; - dmi_cfg = common_data->stats_data->dmi_offset_info; + if (common_data && common_data->stats_data) { + stats_cfg = common_data->stats_data->stats_cfg_offset; + dmi_cfg = common_data->stats_data->dmi_offset_info; + } else { + CAM_INFO(CAM_ISP, "Stats debug dump cfg not available"); + } + val = evt_payload->debug_status_0; CAM_ERR(CAM_ISP, "Bus Violation: debug_status_0 = 0x%x", val); @@ -1458,59 +1463,75 @@ static int cam_vfe_bus_err_bottom_half(void *handler_priv, if (val & 0x0400) { CAM_INFO(CAM_ISP, "PDAF violation"); - cam_vfe_bus_dump_dmi_reg(common_data->mem_base, - CAM_VFE_BUS_LUT_WORD_SIZE_64, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.size, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.bank_0, - dmi_cfg); - CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + if (stats_cfg) { + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.bank_0, + dmi_cfg); + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_PDAF].cfg_offset)); + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].cfg_offset)); + } } if (val & 0x0800) { - CAM_INFO(CAM_ISP, "STATs HDR BE vltn RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE].cfg_offset)); + CAM_INFO(CAM_ISP, "STATs HDR BE violation"); + if (stats_cfg) { + CAM_INFO(CAM_ISP, + "STATs HDR BE vltn RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE]. + cfg_offset)); - CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE].num_cfg)); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE]. + num_cfg)); + } } if (val & 0x01000) { CAM_INFO(CAM_ISP, "STATs HDR BHIST violation"); - cam_vfe_bus_dump_dmi_reg(common_data->mem_base, - CAM_VFE_BUS_LUT_WORD_SIZE_64, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.size, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.bank_0, - dmi_cfg); - - cam_vfe_bus_dump_dmi_reg(common_data->mem_base, - CAM_VFE_BUS_LUT_WORD_SIZE_64, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.size, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.bank_1, - dmi_cfg); - - CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].cfg_offset)); - - CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].num_cfg)); + if (stats_cfg) { + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST]. + lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST]. + lut.bank_0, + dmi_cfg); + + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST]. + lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST]. + lut.bank_1, + dmi_cfg); + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST]. + cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST]. + num_cfg)); + } } if (val & 0x02000) @@ -1518,95 +1539,119 @@ static int cam_vfe_bus_err_bottom_half(void *handler_priv, if (val & 0x04000) { CAM_INFO(CAM_ISP, "STATs BF violation"); - cam_vfe_bus_dump_dmi_reg(common_data->mem_base, - CAM_VFE_BUS_LUT_WORD_SIZE_64, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_0, - dmi_cfg); - - cam_vfe_bus_dump_dmi_reg(common_data->mem_base, - CAM_VFE_BUS_LUT_WORD_SIZE_64, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_1, - dmi_cfg); - - CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].cfg_offset)); + if (stats_cfg) { + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_0, + dmi_cfg); + + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_1, + dmi_cfg); + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].cfg_offset)); + } } if (val & 0x08000) { - CAM_INFO(CAM_ISP, "STATs AWB BG UBWC vltn RGN ofst cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG].cfg_offset)); + CAM_INFO(CAM_ISP, "STATs AWB BG UBWC violation"); + if (stats_cfg) { + CAM_INFO(CAM_ISP, + "STATs AWB BG UBWC vltn RGN ofst cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG]. + cfg_offset)); - CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG].num_cfg)); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG]. + num_cfg)); + } } if (val & 0x010000) { CAM_INFO(CAM_ISP, "STATs BHIST violation"); - cam_vfe_bus_dump_dmi_reg(common_data->mem_base, - CAM_VFE_BUS_LUT_WORD_SIZE_64, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].lut.size, - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].lut.bank_0, - dmi_cfg); - - CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].cfg_offset)); + if (stats_cfg) { + cam_vfe_bus_dump_dmi_reg(common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST]. + lut.bank_0, dmi_cfg); + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST]. + cfg_offset)); - CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].num_cfg)); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].num_cfg)); + } } if (val & 0x020000) { - CAM_INFO(CAM_ISP, "STATs RS violation RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].cfg_offset)); + CAM_INFO(CAM_ISP, "STATs RS violation"); + if (stats_cfg) { + CAM_INFO(CAM_ISP, + "STATs RS violation RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].cfg_offset)); - CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].num_cfg)); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].num_cfg)); + } } if (val & 0x040000) { - CAM_INFO(CAM_ISP, "STATs CS violation RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].cfg_offset)); + CAM_INFO(CAM_ISP, "STATs CS violation"); + if (stats_cfg) { + CAM_INFO(CAM_ISP, + "STATs CS violation RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].cfg_offset)); - CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].num_cfg)); + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].num_cfg)); + } } if (val & 0x080000) { - CAM_INFO(CAM_ISP, "STATs IHIST vltn RGN offset cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST].cfg_offset)); - - CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", - cam_io_r_mb(common_data->mem_base + - stats_cfg[ - CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST].num_cfg)); + CAM_INFO(CAM_ISP, "STATs IHIST violation"); + if (stats_cfg) { + CAM_INFO(CAM_ISP, + "STATs IHIST vltn RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST]. + cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST].num_cfg)); + } } if (val & 0x0100000) -- GitLab From 6bef91bbc8f4252f4382c54df337ae17f23416b7 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 26 Mar 2020 13:24:42 +0530 Subject: [PATCH 274/410] msm: camera: isp: validate in_port before accessing in_port information we are getting from the UMD and accessing it directly without validation which might lead to corruption and device failure. CRs-Fixed: 2629969 Change-Id: I0a1c57db9b94f9657427872ae6797635c6aed668 Signed-off-by: Tejas Prajapati --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 50 ++++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index a37dee5ccce9..699d9de109ac 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1995,18 +1995,36 @@ static int cam_ife_hw_mgr_acquire_res_root( static int cam_ife_mgr_check_and_update_fe_v0( struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_acquire_hw_info *acquire_hw_info) + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t acquire_info_size) { int i; struct cam_isp_in_port_info *in_port = NULL; uint32_t in_port_length = 0; uint32_t total_in_port_length = 0; + if (acquire_hw_info->input_info_offset >= + acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, + "Invalid size offset 0x%x is greater then size 0x%x", + acquire_hw_info->input_info_offset, + acquire_hw_info->input_info_size); + return -EINVAL; + } + in_port = (struct cam_isp_in_port_info *) ((uint8_t *)&acquire_hw_info->data + acquire_hw_info->input_info_offset); for (i = 0; i < acquire_hw_info->num_inputs; i++) { + if (((uint8_t *)in_port + + sizeof(struct cam_isp_in_port_info)) > + ((uint8_t *)acquire_hw_info + + acquire_info_size)) { + CAM_ERR(CAM_ISP, "Invalid size"); + return -EINVAL; + } + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || (in_port->num_out_res <= 0)) { CAM_ERR(CAM_ISP, "Invalid num output res %u", @@ -2040,18 +2058,36 @@ static int cam_ife_mgr_check_and_update_fe_v0( static int cam_ife_mgr_check_and_update_fe_v2( struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_acquire_hw_info *acquire_hw_info) + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t acquire_info_size) { int i; struct cam_isp_in_port_info_v2 *in_port = NULL; uint32_t in_port_length = 0; uint32_t total_in_port_length = 0; + if (acquire_hw_info->input_info_offset >= + acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, + "Invalid size offset 0x%x is greater then size 0x%x", + acquire_hw_info->input_info_offset, + acquire_hw_info->input_info_size); + return -EINVAL; + } + in_port = (struct cam_isp_in_port_info_v2 *) ((uint8_t *)&acquire_hw_info->data + acquire_hw_info->input_info_offset); for (i = 0; i < acquire_hw_info->num_inputs; i++) { + if (((uint8_t *)in_port + + sizeof(struct cam_isp_in_port_info)) > + ((uint8_t *)acquire_hw_info + + acquire_info_size)) { + CAM_ERR(CAM_ISP, "Invalid size"); + return -EINVAL; + } + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || (in_port->num_out_res <= 0)) { CAM_ERR(CAM_ISP, "Invalid num output res %u", @@ -2088,7 +2124,8 @@ static int cam_ife_mgr_check_and_update_fe_v2( static int cam_ife_mgr_check_and_update_fe( struct cam_ife_hw_mgr_ctx *ife_ctx, - struct cam_isp_acquire_hw_info *acquire_hw_info) + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t acquire_info_size) { uint32_t major_ver = 0, minor_ver = 0; @@ -2101,10 +2138,10 @@ static int cam_ife_mgr_check_and_update_fe( switch (major_ver) { case 1: return cam_ife_mgr_check_and_update_fe_v0( - ife_ctx, acquire_hw_info); + ife_ctx, acquire_hw_info, acquire_info_size); case 2: return cam_ife_mgr_check_and_update_fe_v2( - ife_ctx, acquire_hw_info); + ife_ctx, acquire_hw_info, acquire_info_size); break; default: CAM_ERR(CAM_ISP, "Invalid ver of common info from user"); @@ -2902,7 +2939,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_hw_info = (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; - rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info); + rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info, + acquire_args->acquire_info_size); if (rc) { CAM_ERR(CAM_ISP, "buffer size is not enough"); goto free_cdm; -- GitLab From d2b6523c0b6e94cd5f945bf3f2d1888fece795e9 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Wed, 8 Apr 2020 10:56:21 +0530 Subject: [PATCH 275/410] msm: camera: isp: Change EPOCH line config to 50 percent Change EPOCH line configuration from 20 lines to 50 percent for lagoon camera. CRs-Fixed: 2659882 Change-Id: Ie261f0f7033ccc83cae6b4083fa9268bdfbd5401 Signed-off-by: Wyes Karny --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 23cf5d1642f4..86e0716d7b05 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -396,7 +396,6 @@ static int cam_vfe_camif_resource_start( case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: - case CAM_CPAS_TITAN_170_V200: cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, rsrc_data->mem_base + rsrc_data->camif_reg->epoch_irq); -- GitLab From 5e1a73f8f0f205da703dad3f1ee55f87390d89f4 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Thu, 9 Apr 2020 14:42:44 +0530 Subject: [PATCH 276/410] msm: camera: core: Delete request from pending list in case of error While preparing hw for request, there is a possiblity of receiving invalid sync object. In this case, we need to return error. By this time, the request is already in pending list. While returning error, request is moved back to free list. But deleting from the pending list was missed. This commit deleted the request from the pending list if the sync object received is invalid. CRs-Fixed: 2660625 Change-Id: Id619452889476b0c2811c8560361205b0d89bcb9 Signed-off-by: Gaurav Jindal --- drivers/cam_core/cam_context_utils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index ed091b6a0e7c..480d66e60606 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -462,6 +462,9 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, rc = cam_sync_check_valid( req->in_map_entries[j].sync_id); if (rc) { + spin_lock(&ctx->lock); + list_del_init(&req->list); + spin_unlock(&ctx->lock); CAM_ERR(CAM_CTXT, "invalid in map sync object %d", req->in_map_entries[j].sync_id); -- GitLab From 4eb5c9bb014d94932a46fef51e827c72a8e46691 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Tue, 7 Apr 2020 14:20:35 +0530 Subject: [PATCH 277/410] msm: camera: isp: Fixing KW errors Fixing KW errors for ISP. CRs-Fixed: 2571273 Change-Id: I715d12984fb23353de378dc843cd44222d79d705 Signed-off-by: Chandan Kumar Jha --- drivers/cam_isp/cam_isp_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index ac4128e1f3b5..15cfe70e70f8 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -3369,7 +3369,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( struct cam_isp_context *ctx_isp, void *evt_data) { - struct cam_ctx_request *req; + struct cam_ctx_request *req = NULL; struct cam_context *ctx = ctx_isp->base; struct cam_isp_ctx_req *req_isp; struct cam_req_mgr_trigger_notify notify; -- GitLab From b4b2ab4a4c16b03bd9255e8fb7954b7e735c0009 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 18 Feb 2020 14:00:53 +0530 Subject: [PATCH 278/410] msm: camera: icp: Reset current clock in power collapse ICP driver is not resetting curr_clk variable on power collapse. During the next session if base_clk is equal to curr_clk then clock is not updated. CRs-Fixed: 2661166 Change-Id: I9d86bf33fdf576a91b6e33c5b5db542c22c4b36e Signed-off-by: Trishansh Bhardwaj --- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 ++ 1 file changed, 2 insertions(+) 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 4f331b6b0d42..cc8b516e0d64 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 @@ -1741,6 +1741,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, bps_dev_intf->hw_ops.deinit (bps_dev_intf->hw_priv, NULL, 0); hw_mgr->bps_clk_state = false; + hw_mgr->clk_info[ICP_CLK_HW_BPS].curr_clk = 0; } } else { CAM_DBG(CAM_PERF, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt); @@ -1776,6 +1777,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, } hw_mgr->ipe_clk_state = false; + hw_mgr->clk_info[ICP_CLK_HW_IPE].curr_clk = 0; } end: -- GitLab From a7fa49bcae18e2b6decbf181e668bcc9c97343e3 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Mon, 13 Apr 2020 15:01:42 +0530 Subject: [PATCH 279/410] msm: camera: tfe: Add tfe, ope header files Support is added to tfe, ope header files. CRs-Fixed: 2662872 Change-Id: I3ea8dd80f4fdb4560250d610603292c400342770 Signed-off-by: Shravya Samala --- include/uapi/media/cam_isp_tfe.h | 35 +++ include/uapi/media/cam_ope.h | 335 ++++++++++++++++++++++++++ include/uapi/media/cam_tfe.h | 396 +++++++++++++++++++++++++++++++ 3 files changed, 766 insertions(+) create mode 100644 include/uapi/media/cam_isp_tfe.h create mode 100644 include/uapi/media/cam_ope.h create mode 100644 include/uapi/media/cam_tfe.h diff --git a/include/uapi/media/cam_isp_tfe.h b/include/uapi/media/cam_isp_tfe.h new file mode 100644 index 000000000000..407124644bcc --- /dev/null +++ b/include/uapi/media/cam_isp_tfe.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_TFE_H__ +#define __UAPI_CAM_ISP_TFE_H__ + +/* TFE output port resource id number */ +#define CAM_ISP_TFE_OUT_RES_BASE 0x1 + +#define CAM_ISP_TFE_OUT_RES_FULL (CAM_ISP_TFE_OUT_RES_BASE + 0) +#define CAM_ISP_TFE_OUT_RES_RAW_DUMP (CAM_ISP_TFE_OUT_RES_BASE + 1) +#define CAM_ISP_TFE_OUT_RES_PDAF (CAM_ISP_TFE_OUT_RES_BASE + 2) +#define CAM_ISP_TFE_OUT_RES_RDI_0 (CAM_ISP_TFE_OUT_RES_BASE + 3) +#define CAM_ISP_TFE_OUT_RES_RDI_1 (CAM_ISP_TFE_OUT_RES_BASE + 4) +#define CAM_ISP_TFE_OUT_RES_RDI_2 (CAM_ISP_TFE_OUT_RES_BASE + 5) +#define CAM_ISP_TFE_OUT_RES_STATS_HDR_BE (CAM_ISP_TFE_OUT_RES_BASE + 6) +#define CAM_ISP_TFE_OUT_RES_STATS_HDR_BHIST (CAM_ISP_TFE_OUT_RES_BASE + 7) +#define CAM_ISP_TFE_OUT_RES_STATS_TL_BG (CAM_ISP_TFE_OUT_RES_BASE + 8) +#define CAM_ISP_TFE_OUT_RES_STATS_BF (CAM_ISP_TFE_OUT_RES_BASE + 9) +#define CAM_ISP_TFE_OUT_RES_STATS_AWB_BG (CAM_ISP_TFE_OUT_RES_BASE + 10) +#define CAM_ISP_TFE_OUT_RES_MAX (CAM_ISP_TFE_OUT_RES_BASE + 11) + + +/* TFE input port resource type */ +#define CAM_ISP_TFE_IN_RES_BASE 0x1 + +#define CAM_ISP_TFE_IN_RES_TPG (CAM_ISP_TFE_IN_RES_BASE + 0) +#define CAM_ISP_TFE_IN_RES_PHY_0 (CAM_ISP_TFE_IN_RES_BASE + 1) +#define CAM_ISP_TFE_IN_RES_PHY_1 (CAM_ISP_TFE_IN_RES_BASE + 2) +#define CAM_ISP_TFE_IN_RES_PHY_2 (CAM_ISP_TFE_IN_RES_BASE + 3) +#define CAM_ISP_TFE_IN_RES_MAX (CAM_ISP_TFE_IN_RES_BASE + 4) + +#endif /* __UAPI_CAM_ISP_TFE_H__ */ diff --git a/include/uapi/media/cam_ope.h b/include/uapi/media/cam_ope.h new file mode 100644 index 000000000000..812212f3170b --- /dev/null +++ b/include/uapi/media/cam_ope.h @@ -0,0 +1,335 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_OPE_H__ +#define __UAPI_OPE_H__ + +#include "cam_defs.h" +#include "cam_cpas.h" + +#define OPE_DEV_NAME_SIZE 128 + +/* OPE HW TYPE */ +#define OPE_HW_TYPE_OPE 0x1 +#define OPE_HW_TYPE_OPE_CDM 0x2 +#define OPE_HW_TYPE_MAX 0x3 + +/* OPE Device type */ +#define OPE_DEV_TYPE_OPE_RT 0x1 +#define OPE_DEV_TYPE_OPE_NRT 0x2 +#define OPE_DEV_TYPE_OPE_SEMI_RT 0x3 +#define OPE_DEV_TYPE_MAX 0x4 + +/* OPE Input Res Ports */ +#define OPE_IN_RES_FULL 0x1 +#define OPE_IN_RES_MAX OPE_IN_RES_FULL + +/* OPE Output Res Ports */ +#define OPE_OUT_RES_VIDEO 0x1 +#define OPE_OUT_RES_DISP 0x2 +#define OPE_OUT_RES_ARGB 0x3 +#define OPE_OUT_RES_STATS_RS 0x4 +#define OPE_OUT_RES_STATS_IHIST 0x5 +#define OPE_OUT_RES_STATS_LTM 0x6 +#define OPE_OUT_RES_MAX OPE_OUT_RES_STATS_LTM + +/* OPE packet opcodes */ +#define OPE_OPCODE_CONFIG 0x1 + +/* OPE Command Buffer Scope */ +#define OPE_CMD_BUF_SCOPE_BATCH 0x1 +#define OPE_CMD_BUF_SCOPE_FRAME 0x2 +#define OPE_CMD_BUF_SCOPE_PASS 0x3 +#define OPE_CMD_BUF_SCOPE_STRIPE 0x4 + +/* OPE Command Buffer Types */ +#define OPE_CMD_BUF_TYPE_DIRECT 0x1 +#define OPE_CMD_BUF_TYPE_INDIRECT 0x2 + +/* OPE Command Buffer Usage */ +#define OPE_CMD_BUF_UMD 0x1 +#define OPE_CMD_BUF_KMD 0x2 +#define OPE_CMD_BUF_DEBUG 0x3 + +/* OPE Single/Double Buffered */ +#define OPE_CMD_BUF_SINGLE_BUFFERED 0x1 +#define OPE_CMD_BUF_DOUBLE_BUFFERED 0x2 + +/* Command meta types */ +#define OPE_CMD_META_GENERIC_BLOB 0x1 + +/* Generic blob types */ +#define OPE_CMD_GENERIC_BLOB_CLK_V2 0x1 + +/* Stripe location */ +#define OPE_STRIPE_FULL 0x0 +#define OPE_STRIPE_LEFT 0x1 +#define OPE_STRIPE_RIGHT 0x2 +#define OPE_STRIPE_MIDDLE 0x3 + +#define OPE_MAX_CMD_BUFS 64 +#define OPE_MAX_IO_BUFS (OPE_OUT_RES_MAX + OPE_IN_RES_MAX) +#define OPE_MAX_PASS 1 +#define OPE_MAX_PLANES 2 +#define OPE_MAX_STRIPES 48 +#define OPE_MAX_BATCH_SIZE 16 + +/** + * struct ope_stripe_info - OPE stripe Info + * + * @offset: Offset in Bytes + * @x_init: X_init + * @stripe_location: Stripe location (OPE_STRIPE_XXX) + * @width: Width of a stripe + * @height: Height of a stripe + * @disable_bus: Flag to disable BUS master + * @reserved: Reserved + * + */ +struct ope_stripe_info { + uint32_t offset; + uint32_t x_init; + uint32_t stripe_location; + uint32_t width; + uint32_t height; + uint32_t disable_bus; + uint32_t reserved; +}; + +/** + * struct ope_io_buf_info - OPE IO buffers meta + * + * @direction: Direction of a buffer of a port(Input/Output) + * @resource_type: Port type + * @num_planes: Number of planes for a port + * @reserved: Reserved + * @num_stripes: Stripes per plane + * @mem_handle: Memhandles of each Input/Output Port + * @plane_offset: Offsets of planes + * @length: Length of a plane buffer + * @plane_stride: Plane stride + * @height: Height of a plane buffer + * @format: Format + * @fence: Fence of a Port + * @stripe_info: Stripe Info + * + */ +struct ope_io_buf_info { + uint32_t direction; + uint32_t resource_type; + uint32_t num_planes; + uint32_t reserved; + uint32_t num_stripes[OPE_MAX_PLANES]; + uint32_t mem_handle[OPE_MAX_PLANES]; + uint32_t plane_offset[OPE_MAX_PLANES]; + uint32_t length[OPE_MAX_PLANES]; + uint32_t plane_stride[OPE_MAX_PLANES]; + uint32_t height[OPE_MAX_PLANES]; + uint32_t format; + uint32_t fence; + struct ope_stripe_info stripe_info[OPE_MAX_PLANES][OPE_MAX_STRIPES]; +}; + +/** + * struct ope_frame_set - OPE frameset + * + * @num_io_bufs: Number of I/O buffers + * @reserved: Reserved + * @io_buf: IO buffer info for all Input and Output ports + * + */ +struct ope_frame_set { + uint32_t num_io_bufs; + uint32_t reserved; + struct ope_io_buf_info io_buf[OPE_MAX_IO_BUFS]; +}; + +/** + * struct ope_cmd_buf_info - OPE command buffer meta + * + * @mem_handle: Memory handle for command buffer + * @offset: Offset of a command buffer + * @size: Size of command buffer + * @length: Length of a command buffer + * @cmd_buf_scope : Scope of a command buffer (OPE_CMD_BUF_SCOPE_XXX) + * @type: Command buffer type (OPE_CMD_BUF_TYPE_XXX) + * @cmd_buf_usage: Usage of command buffer ( OPE_CMD_BUF_USAGE_XXX) + * @stripe_idx: Stripe index in a req, It is valid for SCOPE_STRIPE + * @cmd_buf_pass_idx: Pass index + * @prefetch_disable: Prefecth disable flag + * + */ + +struct ope_cmd_buf_info { + uint32_t mem_handle; + uint32_t offset; + uint32_t size; + uint32_t length; + uint32_t cmd_buf_scope; + uint32_t type; + uint32_t cmd_buf_usage; + uint32_t cmd_buf_buffered; + uint32_t stripe_idx; + uint32_t cmd_buf_pass_idx; + uint32_t prefetch_disable; +}; + +/** + * struct ope_packet_payload - payload for a request + * + * @num_cmd_bufs: Number of command buffers + * @batch_size: Batch size in HFR mode + * @ope_cmd_buf_info: Command buffer meta data + * @ope_io_buf_info: Io buffer Info + * + */ +struct ope_frame_process { + uint32_t num_cmd_bufs[OPE_MAX_BATCH_SIZE]; + uint32_t batch_size; + struct ope_cmd_buf_info cmd_buf[OPE_MAX_BATCH_SIZE][OPE_MAX_CMD_BUFS]; + struct ope_frame_set frame_set[OPE_MAX_BATCH_SIZE]; +}; + +/** + * struct ope_clk_bw_request_v2 - clock and bandwidth for a request + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @reserved: For memory alignment + * @axi_path: Per path vote info for OPE + * + */ +struct ope_clk_bw_request_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t reserved; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +}; + +/** + * struct ope_hw_ver - Device information for OPE + * + * This is used to get device version info of + * OPE, CDM and use this info in CAM_QUERY_CAP IOCTL + * + * @hw_type: Hardware type for the cap info(OPE_HW_TYPE_XXX) + * @reserved: Reserved field + * @hw_ver: Major, minor and incr values of a hardware version + * + */ +struct ope_hw_ver { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_ver; +}; + +/** + * struct ope_query_cap_cmd - OPE query device capability payload + * + * @dev_iommu_handle: OPE iommu handles for secure/non secure modes + * @cdm_iommu_handle: CDM iommu handles for secure/non secure modes + * @num_ope: Number of OPEs + * @reserved: Reserved Parameter + * @hw_ver: Hardware capability array + */ +struct ope_query_cap_cmd { + struct cam_iommu_handle dev_iommu_handle; + struct cam_iommu_handle cdm_iommu_handle; + uint32_t num_ope; + uint32_t reserved; + struct ope_hw_ver hw_ver[OPE_DEV_TYPE_MAX]; +}; + +/** + * struct ope_out_res_info - OPE Output resource info + * + * @res_id: Resource ID + * @format: Output resource format + * @width: Output width + * @height: Output Height + * @alignment: Alignment + * @packer_format: Packer format + * @subsample_period: Subsample period in HFR + * @subsample_pattern: Subsample pattern in HFR + * @pixel_pattern: Pixel pattern + * @reserved: Reserved Parameter + * + */ +struct ope_out_res_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t alignment; + uint32_t packer_format; + uint32_t subsample_period; + uint32_t subsample_pattern; + uint32_t pixel_pattern; + uint32_t reserved; +}; + +/** + * struct ope_in_res_info - OPE Input resource info + * + * @res_id: Resource ID + * @format: Input resource format + * @width: Input width + * @height: Input Height + * @pixel_pattern: Pixel pattern + * @alignment: Alignment + * @unpacker_format: Unpacker format + * @max_stripe_size: Max stripe size supported for this instance configuration + * @fps: Frames per second + * @reserved: Reserved Parameter + * + */ +struct ope_in_res_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t pixel_pattern; + uint32_t alignment; + uint32_t unpacker_format; + uint32_t max_stripe_size; + uint32_t fps; + uint32_t reserved; +}; + +/** + * struct ope_acquire_dev_info - OPE Acquire Info + * + * @hw_type: OPE HW Types (OPE) + * @dev_type: Nature of Device Instance (RT/NRT) + * @dev_name: Name of Device Instance + * @nrt_stripes_for_arb: Program num stripes in OPE CDM for NRT device + * before setting ARB bit + * @secure_mode: Mode of Device operation (Secure or Non Secure) + * @batch_size: Batch size + * @num_in_res: Number of input resources (OPE_IN_RES_XXX) + * @in_res: Input resource info + * @num_out_res: Number of output resources (OPE_OUT_RES_XXX) + * @reserved: Reserved Parameter + * @out_res: Output resource info + * + */ +struct ope_acquire_dev_info { + uint32_t hw_type; + uint32_t dev_type; + char dev_name[OPE_DEV_NAME_SIZE]; + uint32_t nrt_stripes_for_arb; + uint32_t secure_mode; + uint32_t batch_size; + uint32_t num_in_res; + struct ope_in_res_info in_res[OPE_IN_RES_MAX]; + uint32_t num_out_res; + uint32_t reserved; + struct ope_out_res_info out_res[OPE_OUT_RES_MAX]; +} __attribute__((__packed__)); + +#endif /* __UAPI_OPE_H__ */ diff --git a/include/uapi/media/cam_tfe.h b/include/uapi/media/cam_tfe.h new file mode 100644 index 000000000000..7da5493466b0 --- /dev/null +++ b/include/uapi/media/cam_tfe.h @@ -0,0 +1,396 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_TFE_H__ +#define __UAPI_CAM_TFE_H__ + +#include "cam_defs.h" +#include "cam_isp_tfe.h" +#include "cam_cpas.h" + + +/* ISP TFE driver name */ +#define CAM_ISP_TFE_DEV_NAME "cam-isp" + +/* HW type */ +#define CAM_ISP_TFE_HW_BASE 0 +#define CAM_ISP_TFE_HW_CSID 1 +#define CAM_ISP_TFE_HW_TFE 2 +#define CAM_ISP_TFE_HW_MAX 3 + +/* Color Pattern */ +#define CAM_ISP_TFE_PATTERN_BAYER_RGRGRG 0 +#define CAM_ISP_TFE_PATTERN_BAYER_GRGRGR 1 +#define CAM_ISP_TFE_PATTERN_BAYER_BGBGBG 2 +#define CAM_ISP_TFE_PATTERN_BAYER_GBGBGB 3 +#define CAM_ISP_TFE_PATTERN_YUV_YCBYCR 4 +#define CAM_ISP_TFE_PATTERN_YUV_YCRYCB 5 +#define CAM_ISP_TFE_PATTERN_YUV_CBYCRY 6 +#define CAM_ISP_TFE_PATTERN_YUV_CRYCBY 7 +#define CAM_ISP_TFE_PATTERN_MAX 8 + +/* Usage Type */ +#define CAM_ISP_TFE_IN_RES_USAGE_SINGLE 0 +#define CAM_ISP_TFE_IN_RES_USAGE_DUAL 1 +#define CAM_ISP_TFE_IN_RES_USAGE_MAX 2 + +/* Resource ID */ +#define CAM_ISP_TFE_RES_ID_PORT 0 +#define CAM_ISP_TFE_RES_ID_MAX 1 + +/* Resource Type - Type of resource for the resource id + * defined in cam_isp_tfe.h + */ + +/* Lane Type in input resource for Port */ +#define CAM_ISP_TFE_IN_LANE_TYPE_DPHY 0 +#define CAM_ISP_TFE_IN_LANE_TYPE_CPHY 1 +#define CAM_ISP_TFE_IN_LANE_TYPE_MAX 2 + +/* ISP TFE packet opcode */ +#define CAM_ISP_TFE_PACKET_OP_BASE 0 +#define CAM_ISP_TFE_PACKET_INIT_DEV 1 +#define CAM_ISP_TFE_PACKET_CONFIG_DEV 2 +#define CAM_ISP_TFE_PACKET_OP_MAX 3 + +/* ISP TFE packet meta_data type for command buffer */ +#define CAM_ISP_TFE_PACKET_META_BASE 0 +#define CAM_ISP_TFE_PACKET_META_LEFT 1 +#define CAM_ISP_TFE_PACKET_META_RIGHT 2 +#define CAM_ISP_TFE_PACKET_META_COMMON 3 +#define CAM_ISP_TFE_PACKET_META_DUAL_CONFIG 4 +#define CAM_ISP_TFE_PACKET_META_GENERIC_BLOB_COMMON 5 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_PER_REQUEST 6 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH 7 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR 8 + +/* ISP TFE Generic Cmd Buffer Blob types */ +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_BW_CONFIG_V2 2 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 3 + +/* DSP mode */ +#define CAM_ISP_TFE_DSP_MODE_NONE 0 +#define CAM_ISP_TFE_DSP_MODE_ONE_WAY 1 +#define CAM_ISP_TFE_DSP_MODE_ROUND 2 + +/* Per Path Usage Data */ +#define CAM_ISP_TFE_USAGE_INVALID 0 +#define CAM_ISP_TFE_USAGE_LEFT_PX 1 +#define CAM_ISP_TFE_USAGE_RIGHT_PX 2 +#define CAM_ISP_TFE_USAGE_RDI 3 + +/* Bus write master modes */ +#define CAM_ISP_TFE_WM_FRAME_BASED_MODE 0 +#define CAM_ISP_TFE_WM_LINE_BASED_MODE 1 +#define CAM_ISP_TFE_WM_INDEX_BASED_MODE 2 + +/* Query devices */ +/** + * struct cam_isp_tfe_dev_cap_info - A cap info for particular hw type + * + * @hw_type: Hardware type for the cap info + * @reserved: reserved field for alignment + * @hw_version: Hardware version + * + */ +struct cam_isp_tfe_dev_cap_info { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_version; +}; + +/** + * struct cam_isp_tfe_query_cap_cmd - ISP TFE query device + * capability payload + * + * @device_iommu: returned iommu handles for device + * @cdm_iommu: returned iommu handles for cdm + * @num_dev: returned number of device capabilities + * @reserved: reserved field for alignment + * @dev_caps: returned device capability array + * + */ +struct cam_isp_tfe_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + int32_t num_dev; + uint32_t reserved; + struct cam_isp_tfe_dev_cap_info dev_caps[CAM_ISP_TFE_HW_MAX]; +}; + +/* Acquire Device */ +/** + * struct cam_isp_tfe_out_port_info - An output port resource info + * + * @res_id: output resource id defined in file + * cam_isp_tfe.h + * @format: output format of the resource + * @width: output width in pixels + * @height: output height in lines + * @stride: output stride + * @comp_grp_id: composite group id for the resource. + * @secure_mode: flag to tell if output should be run in secure + * mode or not. See cam_defs.h for definition + * @wm_mode: wm mode + * @reserved: reserved field for alignment + * + */ +struct cam_isp_tfe_out_port_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t comp_grp_id; + uint32_t secure_mode; + uint32_t wm_mode; + uint32_t reserved; +}; + +/** + * struct cam_isp_tfe_in_port_info - An input port resource info + * + * @res_id: input resource id CAM_ISP_TFE_IN_RES_XXX + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @format: input format + * @pix_pattern: pixel pattern + * @usage_type: whether dual tfe is required + * @left_start: left input start offset in pixels + * @left_end: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * Only for Dual TFE + * @right_end: right input stop offset in + * pixels. Only for Dual TFE + * @right_width: right input width in pixels. + * Only for dual TFE + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @batch_size: batch size for HFR mode + * @dsp_mode: DSP stream mode(Defines as + * CAM_ISP_TFE_DSP_MODE_*) + * @sensor_width: sensor width + * @sensor_height: sensor height + * @hbi_value: sensor HBI value + * @vbi_value: sensor VBI value + * @sensor_fps: sensor fps + * @init_frame_drop init frame drop value. + * @num_out_res: number of the output resource associated + * @data: payload that contains the output resources, + * array of cam_isp_tfe_out_port_info data + * + */ +struct cam_isp_tfe_in_port_info { + uint32_t res_id; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc; + uint32_t dt; + uint32_t format; + uint32_t pix_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_end; + uint32_t left_width; + uint32_t right_start; + uint32_t right_end; + uint32_t right_width; + uint32_t line_start; + uint32_t line_end; + uint32_t height; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t sensor_width; + uint32_t sensor_height; + uint32_t sensor_hbi; + uint32_t sensor_vbi; + uint32_t sensor_fps; + uint32_t init_frame_drop; + uint32_t num_out_res; + struct cam_isp_tfe_out_port_info data[1]; +}; + +/** + * struct cam_isp_tfe_resource - A resource bundle + * + * @resoruce_id: resource id for the resource bundle + * @length: length of the while resource blob + * @handle_type: type of the resource handle + * @reserved: reserved field for alignment + * @res_hdl: resource handle that points to the + * resource array + * + */ +struct cam_isp_tfe_resource { + uint32_t resource_id; + uint32_t length; + uint32_t handle_type; + uint32_t reserved; + uint64_t res_hdl; +}; + +/** + * struct cam_isp_tfe_port_hfr_config - HFR configuration for + * this port + * + * @resource_type: Resource type + * @subsample_pattern: Subsample pattern. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @subsample_period: Subsample period. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @framedrop_pattern: Framedrop pattern + * @framedrop_period: Framedrop period + * @reserved: Reserved for alignment + */ +struct cam_isp_tfe_port_hfr_config { + uint32_t resource_type; + uint32_t subsample_pattern; + uint32_t subsample_period; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_resource_hfr_config - Resource HFR + * configuration + * + * @num_ports: Number of ports + * @reserved: Reserved for alignment + * @port_hfr_config: HFR configuration for each IO port + */ +struct cam_isp_tfe_resource_hfr_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_tfe_port_hfr_config port_hfr_config[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_dual_stripe_config - stripe config per bus + * client + * + * @offset: Start horizontal offset relative to + * output buffer + * @width: Width of the stripe in pixels + * @port_id: Port id of ISP TFE output + * @reserved: Reserved for alignment + * + */ +struct cam_isp_tfe_dual_stripe_config { + uint32_t offset; + uint32_t width; + uint32_t port_id; + uint32_t reserved; +}; + +/** + * struct cam_isp_tfe_dual_config - dual isp configuration + * + * @num_ports Number of isp output ports + * @reserved Reserved field for alignment + * @stripes: Stripe information + * + */ +struct cam_isp_tfe_dual_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_tfe_dual_stripe_config stripes[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_clock_config - Clock configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_hz: Pixel Clock for Left ISP + * @right_pix_hz: Pixel Clock for Right ISP + * valid only if Dual + * @rdi_hz: RDI Clock. ISP TFE clock will be + * max of RDI and PIX clocks. For a + * particular context which ISP TFE + * HW the RDI is allocated to is + * not known to UMD. Hence pass the + * clock and let KMD decide. + */ +struct cam_isp_tfe_clock_config { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_hz; + uint64_t right_pix_hz; + uint64_t rdi_hz[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_csid_clock_config - CSID clock + * configuration + * + * @csid_clock CSID clock + * @csi_phy_clock Phy clock valid if tpg is selected + */ +struct cam_isp_tfe_csid_clock_config { + uint64_t csid_clock; + uint64_t phy_clock; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_bw_config_v2 - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_paths: Number of axi data paths + * @axi_path Per path vote info + */ +struct cam_isp_tfe_bw_config_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_acquire_hw_info - ISP TFE acquire HW params + * + * @common_info_version : Version of common info struct used + * @common_info_size : Size of common info struct used + * @common_info_offset : Offset of common info from start of data + * @num_inputs : Number of inputs + * @input_info_version : Version of input info struct used + * @input_info_size : Size of input info struct used + * @input_info_offset : Offset of input info from start of data + * @data : Data pointer to point the cam_isp_tfe_in_port_info + * structure + */ +struct cam_isp_tfe_acquire_hw_info { + uint16_t common_info_version; + uint16_t common_info_size; + uint32_t common_info_offset; + uint32_t num_inputs; + uint32_t input_info_version; + uint32_t input_info_size; + uint32_t input_info_offset; + uint64_t data; +}; + +#define CAM_TFE_ACQUIRE_COMMON_VER0 0x1000 + +#define CAM_TFE_ACQUIRE_COMMON_SIZE_VER0 0x0 + +#define CAM_TFE_ACQUIRE_INPUT_VER0 0x2000 + +#define CAM_TFE_ACQUIRE_INPUT_SIZE_VER0 sizeof(struct cam_isp_tfe_in_port_info) + +#define CAM_TFE_ACQUIRE_OUT_VER0 0x3000 + +#define CAM_TFE_ACQUIRE_OUT_SIZE_VER0 sizeof(struct cam_isp_tfe_out_port_info) + +#endif /* __UAPI_CAM_TFE_H__ */ -- GitLab From 5edad40f8b37db68069ca4254940189874fb27e9 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 10 Mar 2020 15:37:33 -0700 Subject: [PATCH 280/410] msm: camera: smmu: Enhance debug capability for camera memmgr Improve debugging infrastructure and logging for memory related issues. There are scenarios where the fd returned after ion_alloc exists in camera smmu table as being mapped [stale entry]. On such scenarios, this change will return a specific error code to userspace. The change also propagates the mapped size back to user space. CRs-Fixed: 2663114 Change-Id: Ia797b65d1e8ded58dec5b01df07d73262c4cfa95 Signed-off-by: Karthik Anantha Ram --- drivers/cam_req_mgr/cam_mem_mgr.c | 64 +++++++++++++++++++++++++++---- drivers/cam_req_mgr/cam_mem_mgr.h | 4 +- drivers/cam_smmu/cam_smmu_api.c | 62 ++++++++++++++++++++++++------ include/uapi/media/cam_req_mgr.h | 4 +- 4 files changed, 111 insertions(+), 23 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index ae0f167e189f..b1d213577875 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -22,6 +22,39 @@ static struct cam_mem_table tbl; static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); +static void cam_mem_mgr_print_tbl(void) +{ + int i; + uint64_t ms, tmp, hrs, min, sec; + struct timespec64 *ts = NULL; + struct timespec64 current_ts; + + ktime_get_real_ts64(&(current_ts)); + tmp = current_ts.tv_sec; + ms = (current_ts.tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); + + CAM_INFO(CAM_MEM, "***%llu:%llu:%llu:%llu Mem mgr table dump***", + hrs, min, sec, ms); + for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { + if (tbl.bufq[i].active) { + ts = &tbl.bufq[i].timestamp; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); + CAM_INFO(CAM_MEM, + "%llu:%llu:%llu:%llu idx %d fd %d size %llu", + hrs, min, sec, ms, i, tbl.bufq[i].fd, + tbl.bufq[i].len); + } + } + +} + static int cam_mem_util_get_dma_dir(uint32_t flags) { int rc = -EINVAL; @@ -185,6 +218,7 @@ static int32_t cam_mem_get_slot(void) set_bit(idx, tbl.bitmap); tbl.bufq[idx].active = true; + ktime_get_real_ts64(&(tbl.bufq[idx].timestamp)); mutex_init(&tbl.bufq[idx].q_lock); mutex_unlock(&tbl.m_lock); @@ -196,6 +230,7 @@ static void cam_mem_put_slot(int32_t idx) mutex_lock(&tbl.m_lock); mutex_lock(&tbl.bufq[idx].q_lock); tbl.bufq[idx].active = false; + memset(&tbl.bufq[idx].timestamp, 0, sizeof(struct timespec64)); mutex_unlock(&tbl.bufq[idx].q_lock); mutex_destroy(&tbl.bufq[idx].q_lock); clear_bit(idx, tbl.bitmap); @@ -643,6 +678,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) CAM_ERR(CAM_MEM, "Ion Alloc failed, len=%llu, align=%llu, flags=0x%x, num_hdl=%d", cmd->len, cmd->align, cmd->flags, cmd->num_hdl); + cam_mem_mgr_print_tbl(); return rc; } @@ -679,9 +715,14 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) if (rc) { CAM_ERR(CAM_MEM, - "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", - cmd->len, cmd->flags, fd, region, - cmd->num_hdl, rc); + "Failed in map_hw_va, [Size cmdlen=%llu dma %llu smmu %llu], flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->len, dmabuf->size, len, cmd->flags, + fd, region, cmd->num_hdl, rc); + if (rc == -EALREADY) { + if ((size_t)dmabuf->size != len) + rc = -EBADR; + cam_mem_mgr_print_tbl(); + } goto map_hw_fail; } } @@ -780,9 +821,15 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) CAM_SMMU_REGION_IO); if (rc) { CAM_ERR(CAM_MEM, - "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", - cmd->flags, cmd->fd, CAM_SMMU_REGION_IO, - cmd->num_hdl, rc); + "Failed in map_hw_va, flags=0x%x, fd=%d, [Size smmu %llu dma %llu], region=%d, num_hdl=%d, rc=%d", + cmd->flags, cmd->fd, len, dmabuf->size, + CAM_SMMU_REGION_IO, cmd->num_hdl, rc); + if (rc == -EALREADY) { + if ((size_t)dmabuf->size != len) { + rc = -EBADR; + cam_mem_mgr_print_tbl(); + } + } goto map_fail; } } @@ -817,7 +864,7 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) cmd->out.buf_handle = tbl.bufq[idx].buf_handle; cmd->out.vaddr = 0; - + cmd->out.size = (uint32_t)len; CAM_DBG(CAM_MEM, "fd=%d, flags=0x%x, num_hdl=%d, idx=%d, buf handle=%x, len=%zu", cmd->fd, cmd->flags, cmd->num_hdl, idx, cmd->out.buf_handle, @@ -1037,6 +1084,7 @@ static int cam_mem_util_unmap(int32_t idx, tbl.bufq[idx].len = 0; tbl.bufq[idx].num_hdl = 0; tbl.bufq[idx].active = false; + memset(&tbl.bufq[idx].timestamp, 0, sizeof(struct timespec64)); mutex_unlock(&tbl.bufq[idx].q_lock); mutex_destroy(&tbl.bufq[idx].q_lock); clear_bit(idx, tbl.bitmap); diff --git a/drivers/cam_req_mgr/cam_mem_mgr.h b/drivers/cam_req_mgr/cam_mem_mgr.h index 415639a67172..ca791d2ded3a 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/cam_req_mgr/cam_mem_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_MEM_MGR_H_ @@ -41,6 +41,7 @@ enum cam_smmu_mapping_client { * @kmdvaddr: Kernel virtual address * @active: state of the buffer * @is_imported: Flag indicating if buffer is imported from an FD in user space + * @timestamp: Timestamp at which this entry in tbl was made */ struct cam_mem_buf_queue { struct dma_buf *dma_buf; @@ -56,6 +57,7 @@ struct cam_mem_buf_queue { uintptr_t kmdvaddr; bool active; bool is_imported; + struct timespec64 timestamp; }; /** diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index b249182af954..d1fd808cda19 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -196,6 +196,7 @@ struct cam_dma_buff_info { int ion_fd; size_t len; size_t phys_len; + struct timespec64 ts; }; struct cam_sec_buff_info { @@ -401,6 +402,9 @@ static void cam_smmu_dump_cb_info(int idx) size_t shared_reg_len = 0, io_reg_len = 0; size_t shared_free_len = 0, io_free_len = 0; uint32_t i = 0; + uint64_t ms, tmp, hrs, min, sec; + struct timespec64 *ts = NULL; + struct timespec64 current_ts; struct cam_context_bank_info *cb_info = &iommu_cb_set.cb_info[idx]; @@ -414,9 +418,15 @@ static void cam_smmu_dump_cb_info(int idx) io_free_len = io_reg_len - cb_info->io_mapping_size; } + ktime_get_real_ts64(&(current_ts)); + tmp = current_ts.tv_sec; + ms = (current_ts.tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); CAM_ERR(CAM_SMMU, - "********** Context bank dump for %s **********", - cb_info->name); + "********** %llu:%llu:%llu:%llu Context bank dump for %s **********", + hrs, min, sec, ms, cb_info->name); CAM_ERR(CAM_SMMU, "Usage: shared_usage=%u io_usage=%u shared_free=%u io_free=%u", (unsigned int)cb_info->shared_mapping_size, @@ -428,9 +438,16 @@ static void cam_smmu_dump_cb_info(int idx) list_for_each_entry_safe(mapping, mapping_temp, &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { i++; + ts = &mapping->ts; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); CAM_ERR(CAM_SMMU, - "%u. ion_fd=%d start=0x%x end=0x%x len=%u region=%d", - i, mapping->ion_fd, (void *)mapping->paddr, + "%llu:%llu:%llu:%llu: %u ion_fd=%d start=0x%x end=0x%x len=%u region=%d", + hrs, min, sec, ms, i, mapping->ion_fd, + (void *)mapping->paddr, ((uint64_t)mapping->paddr + (uint64_t)mapping->len), (unsigned int)mapping->len, @@ -1999,6 +2016,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, } mapping_info->ion_fd = ion_fd; + ktime_get_real_ts64(&mapping_info->ts); /* add to the list */ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); @@ -2026,7 +2044,7 @@ static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, } mapping_info->ion_fd = -1; - + ktime_get_real_ts64(&mapping_info->ts); /* add to the list */ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list); @@ -2124,15 +2142,28 @@ static int cam_smmu_unmap_buf_and_remove_from_list( } static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx, - int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) + int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr, size_t *dma_buf_len) { struct cam_dma_buff_info *mapping; + struct timespec64 *ts = NULL; + uint64_t ms, tmp, hrs, min, sec; list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { if (mapping->ion_fd == ion_fd) { *paddr_ptr = mapping->paddr; *len_ptr = mapping->len; + *dma_buf_len = mapping->buf->size; + ts = &mapping->ts; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); + CAM_WARN(CAM_SMMU, + "Mapping found ts %llu:%llu:%llu:%llu paddr 0x%p len %llu dma_len %llu", + hrs, min, sec, ms, (void *)mapping->paddr, + mapping->len, *dma_buf_len); return CAM_SMMU_BUFF_EXIST; } } @@ -2863,6 +2894,7 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, size_t *len_ptr, enum cam_smmu_region_id region_id) { int idx, rc = 0; + size_t dma_len = 0; enum cam_smmu_buf_state buf_state; enum dma_data_direction dma_dir; @@ -2900,11 +2932,14 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, goto get_addr_end; } - buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, + len_ptr, &dma_len); if (buf_state == CAM_SMMU_BUFF_EXIST) { CAM_ERR(CAM_SMMU, - "fd:%d already in list idx:%d, handle=%d, give same addr back", - ion_fd, idx, handle); + "fd:%d already in list cb:%s idx:%d handle=%d len=%llu dma_len=%llu, give same addr back", + ion_fd, iommu_cb_set.cb_info[idx].name, + idx, handle, *len_ptr, dma_len); + *len_ptr = dma_len; rc = -EALREADY; goto get_addr_end; } @@ -2913,8 +2948,9 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, dis_delayed_unmap, dma_dir, paddr_ptr, len_ptr, region_id); if (rc < 0) { CAM_ERR(CAM_SMMU, - "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d", - idx, ion_fd, region_id, rc); + "mapping or add list fail cb:%s idx=%d, fd=%d, region=%d, rc=%d", + iommu_cb_set.cb_info[idx].name, idx, + ion_fd, region_id, rc); cam_smmu_dump_cb_info(idx); } @@ -2988,6 +3024,7 @@ int cam_smmu_get_iova(int handle, int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) { int idx, rc = 0; + size_t dma_buf_size = 0; enum cam_smmu_buf_state buf_state; if (!paddr_ptr || !len_ptr) { @@ -3027,7 +3064,8 @@ int cam_smmu_get_iova(int handle, int ion_fd, goto get_addr_end; } - buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, + len_ptr, &dma_buf_size); if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); rc = -EINVAL; diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 56223e99d8be..e5aa83358df2 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -341,12 +341,12 @@ struct cam_mem_alloc_out_params { /** * struct cam_mem_map_out_params * @buf_handle: buffer handle - * @reserved: reserved for future + * @size: size of the buffer being mapped * @vaddr: virtual address pointer */ struct cam_mem_map_out_params { uint32_t buf_handle; - uint32_t reserved; + uint32_t size; uint64_t vaddr; }; -- GitLab From 7ff37150289534dd8939da6764cf211b89aab0ce Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Fri, 28 Feb 2020 14:32:54 +0530 Subject: [PATCH 281/410] msm: camera: isp: Added CSID recovery mechanism CSID is not able to recover from the fatal errors like lane overflows, continuous unbound frames and ESD errors. To recover from such errors, it is necessary to restart the sensor as just starting the ISP hw do not make any change as the sensor can still be in bad state. This commit implements tasklet based CSID recovery mechanism. On detecting an error in CSID interrupt, tasklet is scheduled which in turn will call the ISP hw manager to notify the ISP context, from here a notification is sent to CRM to send a message to trigger full recovery. This full recovery includes the sensor release and start. This feature is debugfs based. Based on need this can be turned on. CRs-Fixed: 2642216 Change-Id: Iecf9916d3672d71a1367886cc934b5a2b148f918 Signed-off-by: Gaurav Jindal --- drivers/cam_isp/cam_isp_context.c | 10 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 53 ++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 3 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 1 + .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 474 ++++++++++++++---- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 48 ++ .../isp_hw/include/cam_ife_csid_hw_intf.h | 4 + 7 files changed, 497 insertions(+), 96 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index ac4128e1f3b5..a38c93c88ec6 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1947,8 +1947,14 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, if (notify.error == CRM_KMD_ERR_FATAL) { req_msg.session_hdl = ctx_isp->base->session_hdl; req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; - req_msg.u.err_msg.error_type = - CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + + if (error_type == CAM_ISP_HW_ERROR_CSID_FATAL) + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY; + else + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl; req_msg.u.err_msg.request_id = error_request_id; req_msg.u.err_msg.resource_size = 0x0; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index d5770c421501..433939d77a8c 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1787,6 +1787,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( csid_acquire.in_port = in_port; csid_acquire.out_port = in_port->data; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_ife_hw_mgr_event_handler; + csid_acquire.priv = ife_ctx; csid_acquire.crop_enable = crop_enable; csid_acquire.drop_enable = false; @@ -1916,6 +1918,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( csid_acquire.in_port = in_port; csid_acquire.out_port = out_port; csid_acquire.node_res = NULL; + csid_acquire.event_cb = cam_ife_hw_mgr_event_handler; + csid_acquire.priv = ife_ctx; /* * Enable RDI pixel drop by default. CSID will enable only for @@ -6793,6 +6797,12 @@ static int cam_ife_hw_mgr_find_affected_ctx( affected_core, CAM_IFE_HW_NUM_MAX)) continue; + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) { + CAM_INFO(CAM_ISP, "CTX:%d already error reported", + ife_hwr_mgr_ctx->ctx_index); + continue; + } + atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1); notify_err_cb = ife_hwr_mgr_ctx->common.event_cb[event_type]; @@ -6822,6 +6832,33 @@ static int cam_ife_hw_mgr_find_affected_ctx( return 0; } +static int cam_ife_hw_mgr_handle_csid_event( + struct cam_isp_hw_event_info *event_info) +{ + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_hw_event_recovery_data recovery_data = {0}; + + /* this can be extended based on the types of error + * received from CSID + */ + switch (event_info->err_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: { + + if (!g_ife_hw_mgr.debug_cfg.enable_csid_recovery) + break; + + error_event_data.error_type = event_info->err_type; + cam_ife_hw_mgr_find_affected_ctx(&error_event_data, + event_info->hw_idx, + &recovery_data); + break; + } + default: + break; + } + return 0; +} + static int cam_ife_hw_mgr_handle_hw_err( void *evt_info) { @@ -6838,6 +6875,13 @@ static int cam_ife_hw_mgr_handle_hw_err( else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + spin_lock(&g_ife_hw_mgr.ctx_lock); + if (event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) { + rc = cam_ife_hw_mgr_handle_csid_event(event_info); + spin_unlock(&g_ife_hw_mgr.ctx_lock); + return rc; + } + core_idx = event_info->hw_idx; if (g_ife_hw_mgr.debug_cfg.enable_recovery) @@ -6855,6 +6899,7 @@ static int cam_ife_hw_mgr_handle_hw_err( recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; cam_ife_hw_mgr_do_error_recovery(&recovery_data); + spin_unlock(&g_ife_hw_mgr.ctx_lock); return rc; } @@ -7318,6 +7363,14 @@ static int cam_ife_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_u32("enable_csid_recovery", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_csid_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_csid_recovery"); + goto err; + } + if (!debugfs_create_bool("enable_req_dump", 0644, g_ife_hw_mgr.debug_cfg.dentry, diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 6f1eeafc85d3..7e81bc4bde1e 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -81,6 +81,7 @@ struct ctx_base_info { * @dentry: Debugfs entry * @csid_debug: csid debug information * @enable_recovery: enable recovery + * @enable_csid_recovery: enable csid recovery * @enable_diag_sensor_status: enable sensor diagnosis status * @enable_req_dump: Enable request dump on HW errors * @per_req_reg_dump: Enable per request reg dump @@ -90,6 +91,7 @@ struct cam_ife_hw_mgr_debug { struct dentry *dentry; uint64_t csid_debug; uint32_t enable_recovery; + uint32_t enable_csid_recovery; uint32_t camif_debug; bool enable_req_dump; bool per_req_reg_dump; @@ -231,6 +233,7 @@ struct cam_ife_hw_mgr { struct cam_vfe_hw_get_hw_cap ife_dev_caps[CAM_IFE_HW_NUM_MAX]; struct cam_req_mgr_core_workq *workq; struct cam_ife_hw_mgr_debug debug_cfg; + spinlock_t ctx_lock; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index c67b50fedfad..a1868fcc599a 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -44,6 +44,7 @@ enum cam_isp_hw_err_type { CAM_ISP_HW_ERROR_P2I_ERROR, CAM_ISP_HW_ERROR_VIOLATION, CAM_ISP_HW_ERROR_BUSIF_OVERFLOW, + CAM_ISP_HW_ERROR_CSID_FATAL, CAM_ISP_HW_ERROR_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index e6fc46d1724f..51606e726a6c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -10,12 +10,14 @@ #include +#include "cam_isp_hw_mgr_intf.h" #include "cam_ife_csid_core.h" #include "cam_isp_hw.h" #include "cam_soc_util.h" #include "cam_io_util.h" #include "cam_debug_util.h" #include "cam_cpas_api.h" +#include "cam_tasklet_util.h" /* Timeout value in msec */ #define IFE_CSID_TIMEOUT 1000 @@ -1205,6 +1207,8 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->hw_intf->hw_idx, reserve->res_id, path_data->width, path_data->height); reserve->node_res = res; + csid_hw->event_cb = reserve->event_cb; + csid_hw->priv = reserve->priv; end: return rc; @@ -1303,8 +1307,10 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->fatal_err_detected = false; csid_hw->device_enabled = 1; spin_unlock_irqrestore(&csid_hw->lock_state, flags); + cam_tasklet_start(csid_hw->tasklet); return 0; @@ -1357,6 +1363,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", csid_hw->hw_intf->hw_idx); + cam_tasklet_stop(csid_hw->tasklet); spin_lock_irqsave(&csid_hw->lock_state, flags); csid_hw->device_enabled = 0; spin_unlock_irqrestore(&csid_hw->lock_state, flags); @@ -3293,6 +3300,8 @@ int cam_ife_csid_release(void *hw_priv, res = (struct cam_isp_resource_node *)release_args; mutex_lock(&csid_hw->hw_info->hw_mutex); + csid_hw->event_cb = NULL; + csid_hw->priv = NULL; if ((res->res_type == CAM_ISP_RESOURCE_CID && res->res_id >= CAM_IFE_CSID_CID_MAX) || (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && @@ -4087,16 +4096,208 @@ static int cam_ife_csid_process_cmd(void *hw_priv, } +static int cam_csid_get_evt_payload( + struct cam_ife_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + + spin_lock(&csid_hw->lock_state); + + if (list_empty(&csid_hw->free_payload_list)) { + *evt_payload = NULL; + spin_unlock(&csid_hw->lock_state); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return -ENOMEM; + } + + *evt_payload = list_first_entry(&csid_hw->free_payload_list, + struct cam_csid_evt_payload, list); + list_del_init(&(*evt_payload)->list); + spin_unlock(&csid_hw->lock_state); + + return 0; +} + +static int cam_csid_put_evt_payload( + struct cam_ife_csid_hw *csid_hw, + struct cam_csid_evt_payload **evt_payload) +{ + unsigned long flags; + + if (*evt_payload == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid payload core %d", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + spin_lock_irqsave(&csid_hw->lock_state, flags); + list_add_tail(&(*evt_payload)->list, + &csid_hw->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + + return 0; +} +static char *cam_csid_status_to_str(uint32_t status) +{ + switch (status) { + case CAM_IFE_CSID_IRQ_REG_TOP: + return "TOP"; + case CAM_IFE_CSID_IRQ_REG_RX: + return "RX"; + case CAM_IFE_CSID_IRQ_REG_IPP: + return "IPP"; + case CAM_IFE_CSID_IRQ_REG_PPP: + return "PPP"; + case CAM_IFE_CSID_IRQ_REG_RDI_0: + return "RDI0"; + case CAM_IFE_CSID_IRQ_REG_RDI_1: + return "RDI1"; + case CAM_IFE_CSID_IRQ_REG_RDI_2: + return "RDI2"; + case CAM_IFE_CSID_IRQ_REG_RDI_3: + return "RDI3"; + case CAM_IFE_CSID_IRQ_REG_UDI_0: + return "UDI0"; + case CAM_IFE_CSID_IRQ_REG_UDI_1: + return "UDI1"; + case CAM_IFE_CSID_IRQ_REG_UDI_2: + return "UDI2"; + default: + return "Invalid IRQ"; + } +} + +static int cam_csid_evt_bottom_half_handler( + void *handler_priv, + void *evt_payload_priv) +{ + struct cam_ife_csid_hw *csid_hw; + struct cam_csid_evt_payload *evt_payload; + int i; + int rc = 0; + struct cam_isp_hw_event_info event_info; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid Param handler_priv %pK evt_payload_priv %pK", + handler_priv, evt_payload_priv); + return 0; + } + + csid_hw = (struct cam_ife_csid_hw *)handler_priv; + evt_payload = (struct cam_csid_evt_payload *)evt_payload_priv; + + if (!csid_hw->event_cb || !csid_hw->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d Invalid args %pK %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->event_cb, + csid_hw->priv); + goto end; + } + + if (csid_hw->priv != evt_payload->priv) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "hw_idx %d priv mismatch %pK, %pK", + csid_hw->hw_intf->hw_idx, + csid_hw->priv, + evt_payload->priv); + goto end; + } + + CAM_ERR_RATE_LIMIT(CAM_ISP, "idx %d err %d phy %d cnt %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type, + csid_hw->csi2_rx_cfg.phy_sel, + csid_hw->csi2_cfg_cnt); + + for (i = 0; i < CAM_IFE_CSID_IRQ_REG_MAX; i++) + CAM_ERR_RATE_LIMIT(CAM_ISP, "status %s: %x", + cam_csid_status_to_str(i), + evt_payload->irq_status[i]); + + /* this hunk can be extended to handle more cases + * which we want to offload to bottom half from + * irq handlers + */ + event_info.err_type = evt_payload->evt_type; + event_info.hw_idx = evt_payload->hw_idx; + + switch (evt_payload->evt_type) { + case CAM_ISP_HW_ERROR_CSID_FATAL: + if (csid_hw->fatal_err_detected) + break; + csid_hw->fatal_err_detected = true; + rc = csid_hw->event_cb(NULL, + CAM_ISP_HW_EVENT_ERROR, (void *)&event_info); + break; + + default: + CAM_DBG(CAM_ISP, "CSID[%d] invalid error type %d", + csid_hw->hw_intf->hw_idx, + evt_payload->evt_type); + break; + } +end: + cam_csid_put_evt_payload(csid_hw, &evt_payload); + return 0; +} + +static int cam_csid_handle_hw_err_irq( + struct cam_ife_csid_hw *csid_hw, + int evt_type, + uint32_t *irq_status) +{ + int rc = 0; + int i; + void *bh_cmd = NULL; + struct cam_csid_evt_payload *evt_payload; + + CAM_DBG(CAM_ISP, "CSID[%d] error %d", + csid_hw->hw_intf->hw_idx, evt_type); + + rc = cam_csid_get_evt_payload(csid_hw, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No free payload core %d", + csid_hw->hw_intf->hw_idx); + return rc; + } + + rc = tasklet_bh_api.get_bh_payload_func(csid_hw->tasklet, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID[%d] Can not get cmd for tasklet, evt_type %d", + csid_hw->hw_intf->hw_idx, + evt_type); + return rc; + } + + evt_payload->evt_type = evt_type; + evt_payload->priv = csid_hw->priv; + evt_payload->hw_idx = csid_hw->hw_intf->hw_idx; + + for (i = 0; i < CAM_IFE_CSID_IRQ_REG_MAX; i++) + evt_payload->irq_status[i] = irq_status[i]; + + tasklet_bh_api.bottom_half_enqueue_func(csid_hw->tasklet, + bh_cmd, + csid_hw, + evt_payload, + cam_csid_evt_bottom_half_handler); + + return rc; +} + irqreturn_t cam_ife_csid_irq(int irq_num, void *data) { struct cam_ife_csid_hw *csid_hw; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; - uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; - uint32_t irq_status_rdi[CAM_IFE_CSID_RDI_MAX] = {0, 0, 0, 0}; - uint32_t irq_status_udi[CAM_IFE_CSID_UDI_MAX] = {0, 0, 0}; - uint32_t val, val2, irq_status_ppp = 0; + uint32_t i, val, val2; + uint32_t irq_status[CAM_IFE_CSID_IRQ_REG_MAX] = {0}; bool fatal_err_detected = false; uint32_t sof_irq_debug_en = 0; unsigned long flags; @@ -4115,23 +4316,27 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csi2_reg = csid_reg->csi2_reg; /* read */ - irq_status_top = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_TOP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_status_addr); - irq_status_rx = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_RX] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_status_addr); if (csid_reg->cmn_reg->num_pix) - irq_status_ipp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_IPP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_irq_status_addr); if (csid_reg->cmn_reg->num_ppp) - irq_status_ppp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + irq_status[CAM_IFE_CSID_IRQ_REG_PPP] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_status_addr); if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - irq_status_rdi[i] = + irq_status[i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); } @@ -4139,7 +4344,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - irq_status_udi[i] = + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->udi_reg[i]->csid_udi_irq_status_addr); } @@ -4147,22 +4352,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); /* clear */ - cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_TOP], + soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); - cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_RX], + soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) - cam_io_w_mb(irq_status_ipp, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_IPP], + soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); if (csid_reg->cmn_reg->num_ppp) - cam_io_w_mb(irq_status_ppp, soc_info->reg_map[0].mem_base + + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_PPP], + soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - cam_io_w_mb(irq_status_rdi[i], + cam_io_w_mb(irq_status[i], soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); } @@ -4170,7 +4379,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - cam_io_w_mb(irq_status_udi[i], + cam_io_w_mb(irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i], soc_info->reg_map[0].mem_base + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); } @@ -4181,91 +4390,116 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); - CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); - CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); - CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); - CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_TOP]); + CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_RX]); + CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_IPP]); + CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", + irq_status[CAM_IFE_CSID_IRQ_REG_PPP]); CAM_DBG(CAM_ISP, "irq_status_rdi0= 0x%x irq_status_rdi1= 0x%x irq_status_rdi2= 0x%x", - irq_status_rdi[0], irq_status_rdi[1], irq_status_rdi[2]); + irq_status[0], irq_status[1], irq_status[2]); CAM_DBG(CAM_ISP, "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", - irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0], + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_1], + irq_status[CAM_IFE_CSID_IRQ_REG_UDI_2]); - if (irq_status_top & CSID_TOP_IRQ_DONE) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_TOP] & CSID_TOP_IRQ_DONE) { CAM_DBG(CAM_ISP, "csid top reset complete"); complete(&csid_hw->csid_top_complete); } - if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); } spin_lock_irqsave(&csid_hw->lock_state, flags); if (csid_hw->device_enabled == 1) { - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + goto handle_fatal_error; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_SOT_RECEPTION", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_ECC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } - if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", - csid_hw->hw_intf->hw_idx); + csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } } @@ -4277,26 +4511,35 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->error_irq_count = 0; } - if (fatal_err_detected) +handle_fatal_error: + + if (fatal_err_detected) { cam_ife_csid_halt_csi2(csid_hw); + cam_csid_handle_hw_err_irq(csid_hw, + CAM_ISP_HW_ERROR_CSID_FATAL, irq_status); + } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL0_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL1_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL2_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL3_EOT_CAPTURED", csid_hw->hw_intf->hw_idx); @@ -4304,22 +4547,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) { - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL0_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL1_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL2_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); } - if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PHY_DL3_SOT_CAPTURED", csid_hw->hw_intf->hw_idx); @@ -4327,7 +4574,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d LONG_PKT_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4347,7 +4596,9 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->hw_intf->hw_idx, (val >> 16), (val & 0xFFFF)); } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d SHORT_PKT_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4363,7 +4614,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) && - (irq_status_rx & CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { + (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & + CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PKT_HDR_CAPTURED", csid_hw->hw_intf->hw_idx); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + @@ -4377,13 +4629,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /*read the IPP errors */ if (csid_reg->cmn_reg->num_pix) { /* IPP reset done bit */ - if (irq_status_ipp & + if (irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID IPP reset complete"); complete(&csid_hw->csid_ipp_complete); } - if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP SOF received", csid_hw->hw_intf->hw_idx); @@ -4391,22 +4644,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP CCIF violation", csid_hw->hw_intf->hw_idx); - if ((irq_status_ipp & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP Overflow due to back pressure", csid_hw->hw_intf->hw_idx); - if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d IPP fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4416,14 +4673,17 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_reg->ipp_reg->csid_pxl_ctrl_addr); } - if ((irq_status_ipp & CSID_PATH_ERROR_PIX_COUNT) || - (irq_status_ipp & CSID_PATH_ERROR_LINE_COUNT)) { + if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_PIX_COUNT) || + (irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & + CSID_PATH_ERROR_LINE_COUNT)) { val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ipp_reg->csid_pxl_format_measure0_addr); CAM_ERR(CAM_ISP, "CSID:%d irq_status_ipp:0x%x", - csid_hw->hw_intf->hw_idx, irq_status_ipp); + csid_hw->hw_intf->hw_idx, + irq_status[CAM_IFE_CSID_IRQ_REG_IPP]); CAM_ERR(CAM_ISP, "Expected:: h: 0x%x w: 0x%x actual:: h: 0x%x w: 0x%x", csid_hw->ipp_path_config.height, @@ -4439,13 +4699,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) /*read PPP errors */ if (csid_reg->cmn_reg->num_ppp) { /* PPP reset done bit */ - if (irq_status_ppp & + if (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID PPP reset complete"); complete(&csid_hw->csid_ppp_complete); } - if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP SOF received", csid_hw->hw_intf->hw_idx); @@ -4453,22 +4714,26 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", csid_hw->hw_intf->hw_idx); - if ((irq_status_ppp & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP CCIF violation", csid_hw->hw_intf->hw_idx); - if ((irq_status_ppp & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP Overflow due to back pressure", csid_hw->hw_intf->hw_idx); - if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d PPP fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4478,14 +4743,17 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_reg->ppp_reg->csid_pxl_ctrl_addr); } - if ((irq_status_ppp & CSID_PATH_ERROR_PIX_COUNT) || - (irq_status_ppp & CSID_PATH_ERROR_LINE_COUNT)) { + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_PIX_COUNT) || + (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_ERROR_LINE_COUNT)) { val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->ppp_reg->csid_pxl_format_measure0_addr); CAM_ERR(CAM_ISP, "CSID:%d irq_status_ppp:0x%x", - csid_hw->hw_intf->hw_idx, irq_status_ppp); + csid_hw->hw_intf->hw_idx, + irq_status[CAM_IFE_CSID_IRQ_REG_PPP]); CAM_ERR(CAM_ISP, "Expected:: h: 0x%x w: 0x%x actual:: h: 0x%x w: 0x%x", csid_hw->ppp_path_config.height, @@ -4499,13 +4767,13 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { - if (irq_status_rdi[i] & + if (irq_status[i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); complete(&csid_hw->csid_rdin_complete[i]); } - if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[i] & CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d SOF received", i); @@ -4513,21 +4781,21 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d EOF received", i); - if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI :%d CCIF violation", i); - if ((irq_status_rdi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[i] & CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI :%d Overflow due to back pressure", i); - if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d RDI fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4537,16 +4805,16 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_reg->rdi_reg[i]->csid_rdi_ctrl_addr); } - if ((irq_status_rdi[i] & CSID_PATH_ERROR_PIX_COUNT) || - (irq_status_rdi[i] & CSID_PATH_ERROR_LINE_COUNT)) { + if ((irq_status[i] & CSID_PATH_ERROR_PIX_COUNT) || + (irq_status[i] & CSID_PATH_ERROR_LINE_COUNT)) { val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_format_measure0_addr); val2 = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_format_measure_cfg1_addr ); CAM_ERR(CAM_ISP, - "CSID:%d irq_status_rdi[%d]:0x%x", - csid_hw->hw_intf->hw_idx, i, irq_status_rdi[i]); + "CSID:%d irq_status[%d]:0x%x", + csid_hw->hw_intf->hw_idx, i, irq_status[i]); CAM_ERR(CAM_ISP, "Expected:: h: 0x%x w: 0x%x actual:: h: 0x%x w: 0x%x", ((val2 >> @@ -4563,13 +4831,14 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) } for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { - if (irq_status_udi[i] & + if (irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "CSID UDI%d reset complete", i); complete(&csid_hw->csid_udin_complete[i]); } - if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_SOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID UDI:%d SOF received", i); @@ -4577,21 +4846,25 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->irq_debug_cnt++; } - if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_EOF) && + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID UDI:%d EOF received", i); - if ((irq_status_udi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_WARN_RATE_LIMIT(CAM_ISP, "CSID UDI :%d CCIF violation", i); - if ((irq_status_udi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_OVERFLOW_RECOVERY)) CAM_WARN_RATE_LIMIT(CAM_ISP, "CSID UDI :%d Overflow due to back pressure", i); - if (irq_status_udi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + if (irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & + CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UDI fifo over flow", csid_hw->hw_intf->hw_idx); @@ -4769,6 +5042,19 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->udi_res[i].res_priv = path_data; } + rc = cam_tasklet_init(&ife_csid_hw->tasklet, ife_csid_hw, csid_idx); + if (rc) { + CAM_ERR(CAM_ISP, "Unable to create CSID tasklet rc %d", rc); + goto err; + } + + INIT_LIST_HEAD(&ife_csid_hw->free_payload_list); + for (i = 0; i < CAM_CSID_EVT_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&ife_csid_hw->evt_payload[i].list); + list_add_tail(&ife_csid_hw->evt_payload[i].list, + &ife_csid_hw->free_payload_list); + } + ife_csid_hw->csid_debug = 0; ife_csid_hw->error_irq_count = 0; ife_csid_hw->ipp_path_config.measure_enabled = 0; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 472f827ae49d..161a08d08095 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -72,6 +72,8 @@ #define CSID_DEBUG_ENABLE_HBI_VBI_INFO BIT(7) #define CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) +#define CAM_CSID_EVT_PAYLOAD_MAX 10 + /* enum cam_csid_path_halt_mode select the path halt mode control */ enum cam_csid_path_halt_mode { CSID_HALT_MODE_INTERNAL, @@ -91,6 +93,24 @@ enum cam_csid_path_timestamp_stb_sel { CSID_TIMESTAMP_STB_MAX, }; +/** + * enum cam_ife_pix_path_res_id - Specify the csid patch + */ +enum cam_ife_csid_irq_reg { + CAM_IFE_CSID_IRQ_REG_RDI_0, + CAM_IFE_CSID_IRQ_REG_RDI_1, + CAM_IFE_CSID_IRQ_REG_RDI_2, + CAM_IFE_CSID_IRQ_REG_RDI_3, + CAM_IFE_CSID_IRQ_REG_TOP, + CAM_IFE_CSID_IRQ_REG_RX, + CAM_IFE_CSID_IRQ_REG_IPP, + CAM_IFE_CSID_IRQ_REG_PPP, + CAM_IFE_CSID_IRQ_REG_UDI_0, + CAM_IFE_CSID_IRQ_REG_UDI_1, + CAM_IFE_CSID_IRQ_REG_UDI_2, + CAM_IFE_CSID_IRQ_REG_MAX, +}; + struct cam_ife_csid_pxl_reg_offset { /* Pxl path register offsets*/ uint32_t csid_pxl_irq_status_addr; @@ -525,12 +545,32 @@ struct cam_ife_csid_path_cfg { uint32_t num_bytes_out; }; +/** + * struct cam_csid_evt_payload- payload for csid hw event + * @list : list head + * @evt_type : Event type from CSID + * @irq_status : IRQ Status register + * @hw_idx : Hw index + * @priv : Private data of payload + */ +struct cam_csid_evt_payload { + struct list_head list; + uint32_t evt_type; + uint32_t irq_status[CAM_IFE_CSID_IRQ_REG_MAX]; + uint32_t hw_idx; + void *priv; +}; + /** * struct cam_ife_csid_hw- csid hw device resources data * * @hw_intf: contain the csid hw interface information * @hw_info: csid hw device information * @csid_info: csid hw specific information + * @tasklet: tasklet to handle csid errors + * @priv: private data to be sent with callback + * @free_payload_list: list head for payload + * @evt_payload: Event payload to be passed to tasklet * @res_type: CSID in resource type * @csi2_rx_cfg: Csi2 rx decoder configuration for csid * @tpg_cfg: TPG configuration @@ -561,11 +601,17 @@ struct cam_ife_csid_path_cfg { * @first_sof_ts first bootime stamp at the start * @prev_qtimer_ts stores csid timestamp * @epd_supported Flag is set if sensor supports EPD + * @fatal_err_detected flag to indicate fatal errror is reported + * @event_cb Callback to hw manager if CSID event reported */ struct cam_ife_csid_hw { struct cam_hw_intf *hw_intf; struct cam_hw_info *hw_info; struct cam_ife_csid_hw_info *csid_info; + void *tasklet; + void *priv; + struct list_head free_payload_list; + struct cam_csid_evt_payload evt_payload[CAM_CSID_EVT_PAYLOAD_MAX]; uint32_t res_type; struct cam_ife_csid_csi2_rx_cfg csi2_rx_cfg; struct cam_ife_csid_tpg_cfg tpg_cfg; @@ -600,6 +646,8 @@ struct cam_ife_csid_hw { uint64_t prev_boot_timestamp; uint64_t prev_qtimer_ts; uint32_t epd_supported; + bool fatal_err_detected; + cam_hw_mgr_event_cb_func event_cb; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 1998f19b7918..5afc0b7c377b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -124,6 +124,8 @@ struct cam_isp_in_port_generic_info { * @node_res : Reserved resource structure pointer * @crop_enable : Flag to indicate CSID crop enable * @drop_enable : Flag to indicate CSID drop enable + * @priv: private data to be sent in callback + * @event_cb: CSID event callback to hw manager * */ struct cam_csid_hw_reserve_resource_args { @@ -137,6 +139,8 @@ struct cam_csid_hw_reserve_resource_args { struct cam_isp_resource_node *node_res; bool crop_enable; bool drop_enable; + void *priv; + cam_hw_mgr_event_cb_func event_cb; }; /** -- GitLab From c3f1957472e632fd31ab3056e7441d7b2e00e129 Mon Sep 17 00:00:00 2001 From: Tony Lijo Jose Date: Tue, 17 Mar 2020 17:02:01 +0530 Subject: [PATCH 282/410] msm: camera: csiphy: Clear secure phy flags on release Issue: Phy flags are set on CONFIG_DEV and are cleared on STOP_DEV. If release is called without stop dev, next session will be opened with incorrect phy configuration based on the previous stale secure mode flags. Fix: Clear the phy secure mode flags on RELEASE_DEV. CRs-Fixed: 2635529 Change-Id: Ib22bbdaa99ca29419200f0d9eb20792f34aaec0c Signed-off-by: Tony Lijo Jose --- .../cam_csiphy/cam_csiphy_core.c | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 9d5976d86f26..65e571f036f3 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -45,6 +45,11 @@ static int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed"); return -EINVAL; } + CAM_INFO(CAM_CSIPHY, "PHY : %d offset: %d SEC: %d Mask: %d", + csiphy_dev->soc_info.index, + offset, + protect, + csiphy_dev->csiphy_cpas_cp_reg_mask[offset]); return 0; } @@ -819,6 +824,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, } break; case CAM_RELEASE_DEV: { + int32_t offset; struct cam_release_dev_cmd release; if (!csiphy_dev->acquire_count) { @@ -834,6 +840,23 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } + offset = cam_csiphy_get_instance_offset(csiphy_dev, + release.dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode[offset]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0x0; + rc = cam_destroy_device_hdl(release.dev_handle); if (rc < 0) CAM_ERR(CAM_CSIPHY, "destroying the device hdl"); -- GitLab From cd7ea465a38e746d1044483cbffeaf3490bc5899 Mon Sep 17 00:00:00 2001 From: Lei Wang Date: Mon, 23 Mar 2020 14:16:47 +0800 Subject: [PATCH 283/410] msm: camera: flash: Add GPIO flash torch support Add GPIO hardware support for flash driver CRs-Fixed: 2640249 Change-Id: I2e0e27acbad8f16fbd658348545af52876bb8328 Signed-off-by: Lei Wang --- .../cam_flash/cam_flash_core.c | 79 ++++++++++++++++--- .../cam_flash/cam_flash_dev.c | 31 ++++++-- .../cam_flash/cam_flash_dev.h | 14 ++-- drivers/cam_utils/cam_soc_util.c | 47 +++++++++++ drivers/cam_utils/cam_soc_util.h | 4 + 5 files changed, 154 insertions(+), 21 deletions(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index 8216e5a83b79..b4109073aa24 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -11,6 +11,41 @@ #include "cam_common_util.h" #include "cam_packet_util.h" +static int cam_flash_set_gpio(struct cam_flash_ctrl *fctrl, + bool enable) +{ + int i; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_soc_gpio_data *gpio_conf = NULL; + uint8_t size = 0; + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash node is NULL"); + return -EINVAL; + } + + soc_info = &fctrl->soc_info; + gpio_conf = soc_info->gpio_data; + + if (gpio_conf == NULL) { + CAM_ERR(CAM_FLASH, "GPIO DATA NULL"); + return -EINVAL; + } + + size = gpio_conf->gpio_delay_tbl_size; + + for (i = 0; i < size; i++) { + CAM_DBG(CAM_FLASH, "flash %s gpio %d", + (enable ? "ENABLE" : "DISABLE"), + gpio_conf->cam_gpio_req_tbl[i].gpio); + cam_res_mgr_gpio_set_value(gpio_conf->cam_gpio_req_tbl[i].gpio, + (enable ? 1 : 0)); + usleep_range(gpio_conf->gpio_delay_tbl[i] * 1000, + gpio_conf->gpio_delay_tbl[i] * 1000 + 10); + } + return 0; +} + static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, bool regulator_enable) { @@ -84,7 +119,8 @@ static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, return rc; } -static int cam_flash_pmic_flush_nrt(struct cam_flash_ctrl *fctrl) +static int cam_flash_pmic_gpio_flush_nrt( + struct cam_flash_ctrl *fctrl) { int j = 0; struct cam_flash_frame_setting *nrt_settings; @@ -180,11 +216,18 @@ static int cam_flash_construct_default_power_setting( return rc; } -int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, +int cam_flash_pmic_gpio_power_ops( + struct cam_flash_ctrl *fctrl, bool regulator_enable) { int rc = 0; + /* Gpio flash do not need to power on and off */ + if (fctrl->soc_info.gpio_data) { + CAM_DBG(CAM_FLASH, "gpio based flash not need power"); + return rc; + } + if (!(fctrl->switch_trigger)) { CAM_ERR(CAM_FLASH, "Invalid argument"); return -EINVAL; @@ -281,7 +324,8 @@ int cam_flash_i2c_power_ops(struct cam_flash_ctrl *fctrl, return rc; } -int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, +int cam_flash_pmic_gpio_flush_request( + struct cam_flash_ctrl *fctrl, enum cam_flash_flush_type type, uint64_t req_id) { int rc = 0; @@ -318,7 +362,7 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, flash_data->led_current_ma[j] = 0; } - cam_flash_pmic_flush_nrt(fctrl); + cam_flash_pmic_gpio_flush_nrt(fctrl); } else if ((type == FLUSH_REQ) && (req_id != 0)) { /* flush request with req_id*/ frame_offset = req_id % MAX_PER_FRAME_ARRAY; @@ -341,7 +385,7 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, flash_data->led_current_ma[i] = 0; } else if ((type == FLUSH_REQ) && (req_id == 0)) { /* Handels NonRealTime usecase */ - cam_flash_pmic_flush_nrt(fctrl); + cam_flash_pmic_gpio_flush_nrt(fctrl); } else { CAM_ERR(CAM_FLASH, "Invalid arguments"); return -EINVAL; @@ -456,6 +500,11 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, flash_ctrl->soc_info.soc_private; if (op == CAMERA_SENSOR_FLASH_OP_FIRELOW) { + /* Turn On Gpio Flash */ + if (flash_ctrl->soc_info.gpio_data) { + cam_flash_set_gpio(flash_ctrl, true); + return 0; + } for (i = 0; i < flash_ctrl->torch_num_sources; i++) { if (flash_ctrl->torch_trigger[i]) { max_current = soc_private->torch_max_current[i]; @@ -471,6 +520,11 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, flash_ctrl->torch_trigger[i], curr); } } else if (op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { + /* Turn On Gpio Flash */ + if (flash_ctrl->soc_info.gpio_data) { + cam_flash_set_gpio(flash_ctrl, true); + return 0; + } for (i = 0; i < flash_ctrl->flash_num_sources; i++) { if (flash_ctrl->flash_trigger[i]) { max_current = soc_private->flash_max_current[i]; @@ -509,6 +563,10 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, (enum led_brightness)LED_SWITCH_OFF); + /* Turn Off Gpio Flash */ + if (flash_ctrl->soc_info.gpio_data) + cam_flash_set_gpio(flash_ctrl, false); + flash_ctrl->flash_state = CAM_FLASH_STATE_START; return 0; } @@ -602,7 +660,8 @@ static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, return 0; } -static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, +static int cam_flash_pmic_gpio_delete_req( + struct cam_flash_ctrl *fctrl, uint64_t req_id) { int i = 0; @@ -758,7 +817,8 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, return rc; } -int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl, +int cam_flash_pmic_gpio_apply_setting( + struct cam_flash_ctrl *fctrl, uint64_t req_id) { int rc = 0, i = 0; @@ -935,7 +995,7 @@ int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl, } nrt_del_req: - cam_flash_pmic_delete_req(fctrl, req_id); + cam_flash_pmic_gpio_delete_req(fctrl, req_id); apply_setting_err: return rc; } @@ -1288,7 +1348,8 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) return rc; } -int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) +int cam_flash_pmic_gpio_pkt_parser( + struct cam_flash_ctrl *fctrl, void *arg) { int rc = 0, i = 0; uintptr_t generic_ptr, cmd_buf_ptr; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index 5eccfd8aa11b..cbcaeefa59d0 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -477,11 +477,26 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) fctrl->func_tbl.power_ops = cam_flash_i2c_power_ops; fctrl->func_tbl.flush_req = cam_flash_i2c_flush_request; } else { - /* PMIC Flash */ - fctrl->func_tbl.parser = cam_flash_pmic_pkt_parser; - fctrl->func_tbl.apply_setting = cam_flash_pmic_apply_setting; - fctrl->func_tbl.power_ops = cam_flash_pmic_power_ops; - fctrl->func_tbl.flush_req = cam_flash_pmic_flush_request; + if (fctrl->soc_info.gpio_data) { + rc = cam_sensor_util_request_gpio_table( + &fctrl->soc_info, + true); + if (rc) { + CAM_ERR(CAM_FLASH, + "GPIO table request failed: rc: %d", + rc); + goto free_gpio_resource; + } + } + /* PMIC GPIO Flash */ + fctrl->func_tbl.parser = + cam_flash_pmic_gpio_pkt_parser; + fctrl->func_tbl.apply_setting = + cam_flash_pmic_gpio_apply_setting; + fctrl->func_tbl.power_ops = + cam_flash_pmic_gpio_power_ops; + fctrl->func_tbl.flush_req = + cam_flash_pmic_gpio_flush_request; } rc = cam_flash_init_subdev(fctrl); @@ -509,6 +524,10 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) free_cci_resource: kfree(fctrl->io_master_info.cci_client); fctrl->io_master_info.cci_client = NULL; +free_gpio_resource: + cam_sensor_util_request_gpio_table(&fctrl->soc_info, false); + kfree(fctrl->soc_info.gpio_data); + fctrl->soc_info.gpio_data = NULL; free_resource: kfree(fctrl->i2c_data.per_frame); kfree(fctrl->soc_info.soc_private); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index 29e352e47ce9..3c3e83e32047 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FLASH_DEV_H_ @@ -115,7 +115,7 @@ struct cam_flash_frame_setting { uint16_t num_iterations; uint16_t led_on_delay_ms; uint16_t led_off_delay_ms; - int8_t opcode; + uint8_t opcode; uint32_t led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS]; }; @@ -209,18 +209,20 @@ struct cam_flash_ctrl { uint32_t last_flush_req; }; -int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); +int cam_flash_pmic_gpio_pkt_parser( + struct cam_flash_ctrl *fctrl, void *arg); int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); -int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl, uint64_t req_id); +int cam_flash_pmic_gpio_apply_setting( + struct cam_flash_ctrl *fctrl, uint64_t req_id); int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, uint64_t req_id); int cam_flash_off(struct cam_flash_ctrl *fctrl); -int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, +int cam_flash_pmic_gpio_power_ops(struct cam_flash_ctrl *fctrl, bool regulator_enable); int cam_flash_i2c_power_ops(struct cam_flash_ctrl *fctrl, bool regulator_enable); int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, enum cam_flash_flush_type type, uint64_t req_id); -int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, +int cam_flash_pmic_gpio_flush_request(struct cam_flash_ctrl *fctrl, enum cam_flash_flush_type, uint64_t req_id); void cam_flash_shutdown(struct cam_flash_ctrl *fctrl); int cam_flash_release_dev(struct cam_flash_ctrl *fctrl); diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 32d185fd3dc2..01eba5544c6f 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -1029,6 +1029,53 @@ static int cam_soc_util_get_dt_gpio_req_tbl(struct device_node *of_node, gconf->cam_gpio_req_tbl[i].label); } + if (!of_get_property(of_node, "gpio-req-tbl-delay", &count)) { + CAM_DBG(CAM_UTIL, "no gpio-req-tbl-delay"); + kfree(val_array); + return rc; + } + + count /= sizeof(uint32_t); + if (!count) { + CAM_ERR(CAM_UTIL, "Invalid gpio count for gpio-req-tbl-delay"); + kfree(val_array); + return rc; + } + + if (count != gconf->cam_gpio_req_tbl_size) { + CAM_ERR(CAM_UTIL, + "Invalid number of gpio-req-tbl-delay entries: %d", + count); + goto free_val_array; + } + + gconf->gpio_delay_tbl = kcalloc(count, sizeof(uint32_t), + GFP_KERNEL); + if (!gconf->gpio_delay_tbl) { + CAM_ERR(CAM_UTIL, + "Failed to allocate memory for gpio_delay_tbl"); + rc = -ENOMEM; + goto free_val_array; + } + + gconf->gpio_delay_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "gpio-req-tbl-delay", + val_array, count); + if (rc) { + CAM_ERR(CAM_UTIL, "Failed to read gpio-req-tbl-delay entry"); + kfree(gconf->gpio_delay_tbl); + gconf->gpio_delay_tbl_size = 0; + kfree(val_array); + return rc; + } + + for (i = 0; i < count; i++) { + gconf->gpio_delay_tbl[i] = val_array[i]; + CAM_DBG(CAM_UTIL, "gpio_delay_tbl[%d] = %ld", i, + gconf->gpio_delay_tbl[i]); + } + kfree(val_array); return rc; diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 92e057b5587f..69f748b80661 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -108,12 +108,16 @@ struct cam_soc_pinctrl_info { * gpios node in DTSI * @cam_gpio_req_tbl It is list of al the requesetd gpios * @cam_gpio_req_tbl_size: It is size of requested gpios + * @gpio_delay_tbl: It is list of al requested gpios delay + * @gpio_delay_tbl_size: It is size of requested gpios delay **/ struct cam_soc_gpio_data { struct gpio *cam_gpio_common_tbl; uint8_t cam_gpio_common_tbl_size; struct gpio *cam_gpio_req_tbl; uint8_t cam_gpio_req_tbl_size; + uint32_t *gpio_delay_tbl; + uint8_t gpio_delay_tbl_size; }; /** -- GitLab From 748e578df467776b4d864fae1628c7ea2c2ce92b Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Mon, 6 Apr 2020 09:07:11 +0530 Subject: [PATCH 284/410] msm: camera: csiphy: Update PHY settings for csiphy v1.2.3 Update the PHY (CPHY, DPHY, DPHY combo) sequences for csiphy v1.2.3 to align with HPG revision W. CRs-Fixed: 2664431 Change-Id: Iab0020447ebe7efe265bb2fd1f4e35b199f3c3ed Signed-off-by: Shravan Nevatia --- .../include/cam_csiphy_1_2_3_hwreg.h | 108 ++++++------------ 1 file changed, 37 insertions(+), 71 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h index 37995e31bf67..01bc307bccff 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -14,8 +14,8 @@ struct csiphy_reg_parms_t csiphy_v1_2_3 = { .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 24, - .csiphy_3ph_config_array_size = 38, + .csiphy_2ph_config_array_size = 23, + .csiphy_3ph_config_array_size = 30, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -60,7 +60,6 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -72,12 +71,12 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -86,7 +85,6 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -101,9 +99,9 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0760, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -112,7 +110,6 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -124,12 +121,12 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -138,7 +135,6 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -150,12 +146,12 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -164,7 +160,6 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -176,12 +171,12 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; @@ -194,24 +189,23 @@ struct csiphy_reg_t {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -220,7 +214,6 @@ struct csiphy_reg_t {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -235,9 +228,9 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0760, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x075C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -246,24 +239,23 @@ struct csiphy_reg_t {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -272,24 +264,23 @@ struct csiphy_reg_t {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x0A, 0x00, CSIPHY_DNP_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -298,7 +289,6 @@ struct csiphy_reg_t {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -313,9 +303,9 @@ struct csiphy_reg_t {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -323,9 +313,6 @@ struct csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -351,21 +338,13 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -391,21 +370,13 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -431,12 +402,7 @@ csiphy_reg_t csiphy_3ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, -- GitLab From 2bd721fd5b0fa0e453134615be77139bd5fb8238 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Wed, 22 Apr 2020 15:58:26 +0530 Subject: [PATCH 285/410] msm: camera: isp: Add null check for event callback function This change is to handle race condition in which tasklet delayed and continue execution after release context. CRs-Fixed: 2667524 Change-Id: If52dbb72bbd85d83fe6eed2279c63072ae262d1b Signed-off-by: Ayush Kumar --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 33 ++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index fd7bf4baf348..1e4d213057fd 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -870,6 +870,10 @@ static int cam_ife_hw_mgr_release_hw_for_ctx( struct cam_ife_hw_mgr_res *hw_mgr_res; struct cam_ife_hw_mgr_res *hw_mgr_res_temp; + /* clean up the callback function */ + ife_ctx->common.cb_priv = NULL; + memset(ife_ctx->common.event_cb, 0, sizeof(ife_ctx->common.event_cb)); + /* ife leaf resource */ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_out[i]); @@ -906,10 +910,6 @@ static int cam_ife_hw_mgr_release_hw_for_ctx( if (ife_ctx->res_list_ife_in.res_type != CAM_IFE_HW_MGR_RES_UNINIT) cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_in); - /* clean up the callback function */ - ife_ctx->common.cb_priv = NULL; - memset(ife_ctx->common.event_cb, 0, sizeof(ife_ctx->common.event_cb)); - CAM_DBG(CAM_ISP, "release context completed ctx id:%d", ife_ctx->ctx_index); @@ -6777,6 +6777,11 @@ static int cam_ife_hw_mgr_handle_hw_rup( cam_hw_event_cb_func ife_hwr_irq_rup_cb; struct cam_isp_hw_reg_update_event_data rup_event_data; + if (!ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE]) { + CAM_ERR(CAM_ISP, "event_cb[HW_EVENT_REG_UPDATE] is null"); + return 0; + } + ife_hwr_irq_rup_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE]; @@ -6888,6 +6893,11 @@ static int cam_ife_hw_mgr_handle_hw_epoch( struct cam_isp_hw_epoch_event_data epoch_done_event_data; int rc = 0; + if (!ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH]) { + CAM_ERR(CAM_ISP, "event_cb[CAM_ISP_HW_EVENT_EPOCH] is null"); + return 0; + } + ife_hw_irq_epoch_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH]; @@ -6937,6 +6947,11 @@ static int cam_ife_hw_mgr_handle_hw_sof( struct cam_isp_hw_sof_event_data sof_done_event_data; int rc = 0; + if (!ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF]) { + CAM_ERR(CAM_ISP, "event_cb[CAM_ISP_HW_EVENT_SOF] is null"); + return 0; + } + memset(&sof_done_event_data, 0, sizeof(sof_done_event_data)); ife_hw_irq_sof_cb = @@ -7012,6 +7027,11 @@ static int cam_ife_hw_mgr_handle_hw_eof( struct cam_isp_hw_eof_event_data eof_done_event_data; int rc = 0; + if (!ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF]) { + CAM_ERR(CAM_ISP, "event_cb[CAM_ISP_HW_EVENT_EOF] is null"); + return 0; + } + ife_hw_irq_eof_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF]; @@ -7057,6 +7077,11 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( struct cam_isp_hw_done_event_data buf_done_event_data = {0}; struct cam_isp_hw_event_info *event_info = evt_info; + if (!ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE]) { + CAM_ERR(CAM_ISP, "event_cb[CAM_ISP_HW_EVENT_DONE] is null"); + return 0; + } + ife_hwr_irq_wm_done_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE]; -- GitLab From 1e731569e19cd45987396d8e59f93920d84cf6be Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 27 Apr 2020 11:14:05 +0530 Subject: [PATCH 286/410] msm: camera: isp: Unlock spinlock in fatal error for CSID While handling CSID fatal error, spin lock is not getting released. Release the lock before handling the error. Change-Id: I6e72206cadb3a979c8734d25c7bf1c1e020a5dc9 CRs-fixed: 2672737 Signed-off-by: Gaurav Jindal --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 7647f44736ea..3eef8f1a5c83 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -3353,7 +3353,8 @@ int cam_ife_csid_release(void *hw_priv, csid_hw->ipp_path_config.measure_enabled = 0; else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) csid_hw->ppp_path_config.measure_enabled = 0; - else + else if (res->res_id >= CAM_IFE_PIX_PATH_RES_RDI_0 && + res->res_id <= CAM_IFE_PIX_PATH_RES_RDI_3) csid_hw->rdi_path_config[res->res_id].measure_enabled = 0; break; @@ -4514,6 +4515,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->error_irq_count++; } } + +handle_fatal_error: spin_unlock_irqrestore(&csid_hw->lock_state, flags); if (csid_hw->error_irq_count > @@ -4522,8 +4525,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_hw->error_irq_count = 0; } -handle_fatal_error: - if (fatal_err_detected) { cam_ife_csid_halt_csi2(csid_hw); cam_csid_handle_hw_err_irq(csid_hw, -- GitLab From c8d4eb551c6939c302ab964be2da26ff361827cb Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Wed, 26 Feb 2020 12:06:33 +0530 Subject: [PATCH 287/410] msm: camera: csiphy: Fix CSID overflow errors Fix: Update PHY settings and BU reset sequence as per latest PHY HPG to avoid possible CSID overflow errors. CRs-Fixed: 2567045 Change-Id: I7a508cb8ef31b642b2afbeb1adb1508b1d8ee205 Signed-off-by: ANIL KUMAR KANAKANTI --- .../include/cam_csiphy_1_2_1_hwreg.h | 157 +++++++----------- 1 file changed, 64 insertions(+), 93 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index 32fbf47eabd9..c9fb93f7e9bd 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_2_1_HWREG_H_ @@ -12,10 +12,10 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 6, + .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 20, - .csiphy_3ph_config_array_size = 34, + .csiphy_3ph_config_array_size = 33, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -25,6 +25,7 @@ struct csiphy_reg_t csiphy_common_reg_1_2_1[] = { {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, }; @@ -33,7 +34,7 @@ struct csiphy_reg_t csiphy_reset_reg_1_2_1[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; @@ -58,7 +59,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0904, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -80,7 +81,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C84, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -102,7 +103,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -124,7 +125,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -146,7 +147,7 @@ csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -288,10 +289,11 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0xAF, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -306,28 +308,27 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09AC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -342,16 +343,14 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -360,10 +359,11 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0xAF, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -378,16 +378,14 @@ csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BAC, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -397,82 +395,55 @@ struct data_rate_settings_t data_rate_delta_table_1_2_1 = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 12, + .data_rate_reg_array_size = 9, .csiphy_data_rate_regs = { - {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { /* (3.5 * 10**3 * 2.28) rounded value */ .bandwidth = 7980000000, - .data_rate_reg_array_size = 24, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { - {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, }, }, { /* (4.5 * 10**3 * 2.28) rounded value */ .bandwidth = 10260000000, - .data_rate_reg_array_size = 24, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { - {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x01, CSIPHY_DEFAULT_PARAMS}, }, } } -- GitLab From c8a42818735eda5a3ea73832881ae131158b4ecd Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Fri, 17 Apr 2020 22:52:58 +0530 Subject: [PATCH 288/410] msm: camera: sensor: Turn off the flash while flushing Turn off the flash while flushing if the flushed request is flash off and removed flush request ID validation in flush_all scenario. CRs-Fixed: 2667472 Change-Id: Iaf123f2f56117d7b7d1ef6d2291b0cde8c232d44 Signed-off-by: Anil Kumar Kanakanti --- drivers/cam_sensor_module/cam_flash/cam_flash_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index 8216e5a83b79..d583bad35df2 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -303,7 +303,6 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) && (flash_data->cmn_attr.request_id > 0) && - (flash_data->cmn_attr.request_id <= req_id) && flash_data->cmn_attr.is_settings_valid) { is_off_needed = true; CAM_DBG(CAM_FLASH, @@ -504,7 +503,7 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) CAM_ERR(CAM_FLASH, "Flash control Null"); return -EINVAL; } - + CAM_DBG(CAM_FLASH, "Flash OFF Triggered"); if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, (enum led_brightness)LED_SWITCH_OFF); @@ -1552,6 +1551,8 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) flash_data->led_current_ma[i] = flash_operation_info->led_current_ma[i]; + CAM_DBG(CAM_FLASH, + "FLASH_CMD_TYPE op:%d", flash_data->opcode); if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) add_req.skip_before_applying |= SKIP_NEXT_FRAME; } -- GitLab From a171a95ad47acb1309f328bb64caa4d8c468ef62 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Thu, 30 Apr 2020 13:21:51 +0530 Subject: [PATCH 289/410] msm: camera: common: Change parameters to find time difference Change the earlier and later parameters to calculate the time differene. Change-Id: I744838b18be80ec5ac7f7211709854bbfceb99a1 CRs-Fixed: 2672724 Signed-off-by: Gaurav Jindal --- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 2 +- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 +- drivers/cam_isp/cam_isp_context.c | 5 ++--- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 2 +- drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 6a422038f5a5..626558e802ba 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1587,7 +1587,7 @@ static int cam_fd_mgr_hw_dump( return rc; hw_dump: cur_time = ktime_get(); - diff = ktime_us_delta(frame_req->submit_timestamp, cur_time); + diff = ktime_us_delta(cur_time, frame_req->submit_timestamp); cur_ts = ktime_to_timespec64(cur_time); req_ts = ktime_to_timespec64(frame_req->submit_timestamp); if (diff < CAM_FD_RESPONSE_TIME_THRESHOLD) { 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 cc8b516e0d64..1db763bbddda 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 @@ -5225,7 +5225,7 @@ static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args) return 0; hw_dump: cur_time = ktime_get(); - diff = ktime_us_delta(frm_process->submit_timestamp[i], cur_time); + diff = ktime_us_delta(cur_time, frm_process->submit_timestamp[i]); cur_ts = ktime_to_timespec64(cur_time); req_ts = ktime_to_timespec64(frm_process->submit_timestamp[i]); diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 63cd569c18b4..17414c7c8552 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -2748,9 +2748,8 @@ static int __cam_isp_ctx_dump_in_top_state( ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; req_isp = (struct cam_isp_ctx_req *) req->req_priv; cur_time = ktime_get(); - diff = ktime_us_delta( - req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY], - cur_time); + diff = ktime_us_delta(cur_time, + req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]); if (diff < CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD) { CAM_INFO(CAM_ISP, "req %lld found no error", req->request_id); diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index ac2612356448..4bec1984bf75 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1543,7 +1543,7 @@ static int cam_jpeg_mgr_hw_dump(void *hw_mgr_priv, void *dump_hw_args) hw_dump: cur_time = ktime_get(); - diff = ktime_us_delta(p_cfg_req->submit_timestamp, cur_time); + diff = ktime_us_delta(cur_time, p_cfg_req->submit_timestamp); cur_ts = ktime_to_timespec64(cur_time); req_ts = ktime_to_timespec64(p_cfg_req->submit_timestamp); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index 551191376af8..64eee9326938 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -115,7 +115,7 @@ static int cam_lrme_hw_dump( } cur_time = ktime_get(); - diff = ktime_us_delta(req->submit_timestamp, cur_time); + diff = ktime_us_delta(cur_time, req->submit_timestamp); cur_ts = ktime_to_timespec64(cur_time); req_ts = ktime_to_timespec64(req->submit_timestamp); -- GitLab From c6958be0538429a6b3decbee11b0af54d9c90e57 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Wed, 29 Apr 2020 18:03:16 +0530 Subject: [PATCH 290/410] msm: camera: smmu: Revert Enhance debug capability for camera memmgr This reverts commit 5edad40f8b37db68069ca4254940189874fb27e9. Change-Id: I56f0fa48e2d7d49f79909942deeebb8fbf6d325a CRs-Fixed: 2663114 Signed-off-by: Gaurav Jindal --- drivers/cam_req_mgr/cam_mem_mgr.c | 62 ++++--------------------------- drivers/cam_req_mgr/cam_mem_mgr.h | 2 - drivers/cam_smmu/cam_smmu_api.c | 62 ++++++------------------------- include/uapi/media/cam_req_mgr.h | 4 +- 4 files changed, 21 insertions(+), 109 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index b1d213577875..a389eae1526a 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -22,39 +22,6 @@ static struct cam_mem_table tbl; static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); -static void cam_mem_mgr_print_tbl(void) -{ - int i; - uint64_t ms, tmp, hrs, min, sec; - struct timespec64 *ts = NULL; - struct timespec64 current_ts; - - ktime_get_real_ts64(&(current_ts)); - tmp = current_ts.tv_sec; - ms = (current_ts.tv_nsec) / 1000000; - sec = do_div(tmp, 60); - min = do_div(tmp, 60); - hrs = do_div(tmp, 24); - - CAM_INFO(CAM_MEM, "***%llu:%llu:%llu:%llu Mem mgr table dump***", - hrs, min, sec, ms); - for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { - if (tbl.bufq[i].active) { - ts = &tbl.bufq[i].timestamp; - tmp = ts->tv_sec; - ms = (ts->tv_nsec) / 1000000; - sec = do_div(tmp, 60); - min = do_div(tmp, 60); - hrs = do_div(tmp, 24); - CAM_INFO(CAM_MEM, - "%llu:%llu:%llu:%llu idx %d fd %d size %llu", - hrs, min, sec, ms, i, tbl.bufq[i].fd, - tbl.bufq[i].len); - } - } - -} - static int cam_mem_util_get_dma_dir(uint32_t flags) { int rc = -EINVAL; @@ -218,7 +185,6 @@ static int32_t cam_mem_get_slot(void) set_bit(idx, tbl.bitmap); tbl.bufq[idx].active = true; - ktime_get_real_ts64(&(tbl.bufq[idx].timestamp)); mutex_init(&tbl.bufq[idx].q_lock); mutex_unlock(&tbl.m_lock); @@ -230,7 +196,6 @@ static void cam_mem_put_slot(int32_t idx) mutex_lock(&tbl.m_lock); mutex_lock(&tbl.bufq[idx].q_lock); tbl.bufq[idx].active = false; - memset(&tbl.bufq[idx].timestamp, 0, sizeof(struct timespec64)); mutex_unlock(&tbl.bufq[idx].q_lock); mutex_destroy(&tbl.bufq[idx].q_lock); clear_bit(idx, tbl.bitmap); @@ -678,7 +643,6 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) CAM_ERR(CAM_MEM, "Ion Alloc failed, len=%llu, align=%llu, flags=0x%x, num_hdl=%d", cmd->len, cmd->align, cmd->flags, cmd->num_hdl); - cam_mem_mgr_print_tbl(); return rc; } @@ -715,14 +679,9 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) if (rc) { CAM_ERR(CAM_MEM, - "Failed in map_hw_va, [Size cmdlen=%llu dma %llu smmu %llu], flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", - cmd->len, dmabuf->size, len, cmd->flags, - fd, region, cmd->num_hdl, rc); - if (rc == -EALREADY) { - if ((size_t)dmabuf->size != len) - rc = -EBADR; - cam_mem_mgr_print_tbl(); - } + "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->len, cmd->flags, fd, region, + cmd->num_hdl, rc); goto map_hw_fail; } } @@ -821,15 +780,9 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) CAM_SMMU_REGION_IO); if (rc) { CAM_ERR(CAM_MEM, - "Failed in map_hw_va, flags=0x%x, fd=%d, [Size smmu %llu dma %llu], region=%d, num_hdl=%d, rc=%d", - cmd->flags, cmd->fd, len, dmabuf->size, - CAM_SMMU_REGION_IO, cmd->num_hdl, rc); - if (rc == -EALREADY) { - if ((size_t)dmabuf->size != len) { - rc = -EBADR; - cam_mem_mgr_print_tbl(); - } - } + "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->flags, cmd->fd, CAM_SMMU_REGION_IO, + cmd->num_hdl, rc); goto map_fail; } } @@ -864,7 +817,7 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) cmd->out.buf_handle = tbl.bufq[idx].buf_handle; cmd->out.vaddr = 0; - cmd->out.size = (uint32_t)len; + CAM_DBG(CAM_MEM, "fd=%d, flags=0x%x, num_hdl=%d, idx=%d, buf handle=%x, len=%zu", cmd->fd, cmd->flags, cmd->num_hdl, idx, cmd->out.buf_handle, @@ -1084,7 +1037,6 @@ static int cam_mem_util_unmap(int32_t idx, tbl.bufq[idx].len = 0; tbl.bufq[idx].num_hdl = 0; tbl.bufq[idx].active = false; - memset(&tbl.bufq[idx].timestamp, 0, sizeof(struct timespec64)); mutex_unlock(&tbl.bufq[idx].q_lock); mutex_destroy(&tbl.bufq[idx].q_lock); clear_bit(idx, tbl.bitmap); diff --git a/drivers/cam_req_mgr/cam_mem_mgr.h b/drivers/cam_req_mgr/cam_mem_mgr.h index ca791d2ded3a..b9e42b62d52f 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/cam_req_mgr/cam_mem_mgr.h @@ -41,7 +41,6 @@ enum cam_smmu_mapping_client { * @kmdvaddr: Kernel virtual address * @active: state of the buffer * @is_imported: Flag indicating if buffer is imported from an FD in user space - * @timestamp: Timestamp at which this entry in tbl was made */ struct cam_mem_buf_queue { struct dma_buf *dma_buf; @@ -57,7 +56,6 @@ struct cam_mem_buf_queue { uintptr_t kmdvaddr; bool active; bool is_imported; - struct timespec64 timestamp; }; /** diff --git a/drivers/cam_smmu/cam_smmu_api.c b/drivers/cam_smmu/cam_smmu_api.c index d1fd808cda19..b249182af954 100644 --- a/drivers/cam_smmu/cam_smmu_api.c +++ b/drivers/cam_smmu/cam_smmu_api.c @@ -196,7 +196,6 @@ struct cam_dma_buff_info { int ion_fd; size_t len; size_t phys_len; - struct timespec64 ts; }; struct cam_sec_buff_info { @@ -402,9 +401,6 @@ static void cam_smmu_dump_cb_info(int idx) size_t shared_reg_len = 0, io_reg_len = 0; size_t shared_free_len = 0, io_free_len = 0; uint32_t i = 0; - uint64_t ms, tmp, hrs, min, sec; - struct timespec64 *ts = NULL; - struct timespec64 current_ts; struct cam_context_bank_info *cb_info = &iommu_cb_set.cb_info[idx]; @@ -418,15 +414,9 @@ static void cam_smmu_dump_cb_info(int idx) io_free_len = io_reg_len - cb_info->io_mapping_size; } - ktime_get_real_ts64(&(current_ts)); - tmp = current_ts.tv_sec; - ms = (current_ts.tv_nsec) / 1000000; - sec = do_div(tmp, 60); - min = do_div(tmp, 60); - hrs = do_div(tmp, 24); CAM_ERR(CAM_SMMU, - "********** %llu:%llu:%llu:%llu Context bank dump for %s **********", - hrs, min, sec, ms, cb_info->name); + "********** Context bank dump for %s **********", + cb_info->name); CAM_ERR(CAM_SMMU, "Usage: shared_usage=%u io_usage=%u shared_free=%u io_free=%u", (unsigned int)cb_info->shared_mapping_size, @@ -438,16 +428,9 @@ static void cam_smmu_dump_cb_info(int idx) list_for_each_entry_safe(mapping, mapping_temp, &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { i++; - ts = &mapping->ts; - tmp = ts->tv_sec; - ms = (ts->tv_nsec) / 1000000; - sec = do_div(tmp, 60); - min = do_div(tmp, 60); - hrs = do_div(tmp, 24); CAM_ERR(CAM_SMMU, - "%llu:%llu:%llu:%llu: %u ion_fd=%d start=0x%x end=0x%x len=%u region=%d", - hrs, min, sec, ms, i, mapping->ion_fd, - (void *)mapping->paddr, + "%u. ion_fd=%d start=0x%x end=0x%x len=%u region=%d", + i, mapping->ion_fd, (void *)mapping->paddr, ((uint64_t)mapping->paddr + (uint64_t)mapping->len), (unsigned int)mapping->len, @@ -2016,7 +1999,6 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, } mapping_info->ion_fd = ion_fd; - ktime_get_real_ts64(&mapping_info->ts); /* add to the list */ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); @@ -2044,7 +2026,7 @@ static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, } mapping_info->ion_fd = -1; - ktime_get_real_ts64(&mapping_info->ts); + /* add to the list */ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list); @@ -2142,28 +2124,15 @@ static int cam_smmu_unmap_buf_and_remove_from_list( } static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx, - int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr, size_t *dma_buf_len) + int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) { struct cam_dma_buff_info *mapping; - struct timespec64 *ts = NULL; - uint64_t ms, tmp, hrs, min, sec; list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { if (mapping->ion_fd == ion_fd) { *paddr_ptr = mapping->paddr; *len_ptr = mapping->len; - *dma_buf_len = mapping->buf->size; - ts = &mapping->ts; - tmp = ts->tv_sec; - ms = (ts->tv_nsec) / 1000000; - sec = do_div(tmp, 60); - min = do_div(tmp, 60); - hrs = do_div(tmp, 24); - CAM_WARN(CAM_SMMU, - "Mapping found ts %llu:%llu:%llu:%llu paddr 0x%p len %llu dma_len %llu", - hrs, min, sec, ms, (void *)mapping->paddr, - mapping->len, *dma_buf_len); return CAM_SMMU_BUFF_EXIST; } } @@ -2894,7 +2863,6 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, size_t *len_ptr, enum cam_smmu_region_id region_id) { int idx, rc = 0; - size_t dma_len = 0; enum cam_smmu_buf_state buf_state; enum dma_data_direction dma_dir; @@ -2932,14 +2900,11 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, goto get_addr_end; } - buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, - len_ptr, &dma_len); + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); if (buf_state == CAM_SMMU_BUFF_EXIST) { CAM_ERR(CAM_SMMU, - "fd:%d already in list cb:%s idx:%d handle=%d len=%llu dma_len=%llu, give same addr back", - ion_fd, iommu_cb_set.cb_info[idx].name, - idx, handle, *len_ptr, dma_len); - *len_ptr = dma_len; + "fd:%d already in list idx:%d, handle=%d, give same addr back", + ion_fd, idx, handle); rc = -EALREADY; goto get_addr_end; } @@ -2948,9 +2913,8 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, dis_delayed_unmap, dma_dir, paddr_ptr, len_ptr, region_id); if (rc < 0) { CAM_ERR(CAM_SMMU, - "mapping or add list fail cb:%s idx=%d, fd=%d, region=%d, rc=%d", - iommu_cb_set.cb_info[idx].name, idx, - ion_fd, region_id, rc); + "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d", + idx, ion_fd, region_id, rc); cam_smmu_dump_cb_info(idx); } @@ -3024,7 +2988,6 @@ int cam_smmu_get_iova(int handle, int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) { int idx, rc = 0; - size_t dma_buf_size = 0; enum cam_smmu_buf_state buf_state; if (!paddr_ptr || !len_ptr) { @@ -3064,8 +3027,7 @@ int cam_smmu_get_iova(int handle, int ion_fd, goto get_addr_end; } - buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, - len_ptr, &dma_buf_size); + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); rc = -EINVAL; diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index e5aa83358df2..56223e99d8be 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -341,12 +341,12 @@ struct cam_mem_alloc_out_params { /** * struct cam_mem_map_out_params * @buf_handle: buffer handle - * @size: size of the buffer being mapped + * @reserved: reserved for future * @vaddr: virtual address pointer */ struct cam_mem_map_out_params { uint32_t buf_handle; - uint32_t size; + uint32_t reserved; uint64_t vaddr; }; -- GitLab From 6b530bb27960d3d0ad34658af6d4d7c80ca0b262 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 16 Apr 2020 15:49:42 +0530 Subject: [PATCH 291/410] msm: camera: isp: Change csid stop sequence during flush This change takes care of a race which we see when we halt master csid immediately and slave csid halt to follow. In some scenarios after master csid halt, slave gives violation errors. With this change we are first changing the mode of slave to master then issue halt commands to both master and slave. CRs-Fixed: 2662825 Change-Id: Id5cd7e1bdf469f43da23af151b99c9f481830cfa Signed-off-by: Vikram Sharma --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 55 ++++++++++- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 96 +++++++++++++++++++ .../isp_hw/include/cam_ife_csid_hw_intf.h | 27 ++++++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + 4 files changed, 178 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 4846c2809842..be7db2bf34f0 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -824,6 +824,47 @@ static void cam_ife_hw_mgr_dump_acq_data( } } +static int cam_ife_mgr_csid_change_halt_mode(struct list_head *halt_list, + uint32_t base_idx, enum cam_ife_csid_halt_mode halt_mode) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *isp_res; + struct cam_csid_hw_halt_args halt; + struct cam_hw_intf *hw_intf; + uint32_t i; + int rc = 0; + + list_for_each_entry(hw_mgr_res, halt_list, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i] || + (hw_mgr_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING)) + continue; + + isp_res = hw_mgr_res->hw_res[i]; + if (isp_res->hw_intf->hw_idx != base_idx) + continue; + + if ((isp_res->res_type == CAM_ISP_RESOURCE_PIX_PATH) && + (isp_res->res_id == CAM_IFE_PIX_PATH_RES_IPP)) { + hw_intf = isp_res->hw_intf; + halt.node_res = isp_res; + halt.halt_mode = halt_mode; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, + &halt, + sizeof(struct cam_csid_hw_halt_args)); + if (rc) + CAM_ERR(CAM_ISP, "Halt update failed"); + break; + } + } + } + + return rc; +} + static int cam_ife_mgr_csid_stop_hw( struct cam_ife_hw_mgr_ctx *ctx, struct list_head *stop_list, uint32_t base_idx, uint32_t stop_cmd) @@ -3864,6 +3905,19 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) */ if (i == ctx->num_base) master_base_idx = ctx->base[0].idx; + + /*Change slave mode*/ + if (csid_halt_type == CAM_CSID_HALT_IMMEDIATELY) { + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == master_base_idx) + continue; + cam_ife_mgr_csid_change_halt_mode( + &ctx->res_list_ife_csid, + ctx->base[i].idx, + CAM_CSID_HALT_MODE_INTERNAL); + } + } + CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx); /* Stop the master CSID path first */ @@ -6954,7 +7008,6 @@ static int cam_ife_hw_mgr_handle_hw_rup( CAM_DBG(CAM_ISP, "RUP done for VFE:%d source %d", event_info->hw_idx, event_info->res_id); - return 0; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 3eef8f1a5c83..d80a8a08ed05 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -2127,6 +2127,64 @@ static int cam_ife_csid_enable_pxl_path( return 0; } + +static void cam_ife_csid_change_pxl_halt_mode( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_ife_csid_halt_mode halt_mode) +{ + uint32_t val = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg; + bool is_ipp; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + goto end; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, res->res_state); + goto end; + } + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + goto end; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "CSID:%d %s path Res:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id, res->res_state); + goto end; + } + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + /* configure Halt for slave */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0xC; + val |= (halt_mode << 2); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); +end: + return; +} + static int cam_ife_csid_disable_pxl_path( struct cam_ife_csid_hw *csid_hw, struct cam_isp_resource_node *res, @@ -3692,6 +3750,41 @@ int cam_ife_csid_start(void *hw_priv, void *start_args, return rc; } +int cam_ife_csid_halt(struct cam_ife_csid_hw *csid_hw, + void *halt_args) +{ + struct cam_isp_resource_node *res; + struct cam_csid_hw_halt_args *csid_halt; + + if (!csid_hw || !halt_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_halt = (struct cam_csid_hw_halt_args *)halt_args; + + /* Change the halt mode */ + res = csid_halt->node_res; + CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); + + switch (res->res_type) { + case CAM_ISP_RESOURCE_PIX_PATH: + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) + cam_ife_csid_change_pxl_halt_mode(csid_hw, res, + csid_halt->halt_mode); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + + return 0; +} + int cam_ife_csid_stop(void *hw_priv, void *stop_args, uint32_t arg_size) { @@ -4089,6 +4182,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG: rc = cam_ife_csid_set_sensor_dimension(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE: + rc = cam_ife_csid_halt(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 5afc0b7c377b..498854b90f92 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -153,6 +153,33 @@ enum cam_ife_csid_halt_cmd { CAM_CSID_HALT_MAX, }; +/** + * enum cam_ife_csid_halt_mode_cmd - Specify the halt command type + */ +enum cam_ife_csid_halt_mode { + CAM_CSID_HALT_MODE_INTERNAL, + CAM_CSID_HALT_MODE_GLOBAL, + CAM_CSID_HALT_MODE_MASTER, + CAM_CSID_HALT_MODE_SLAVE, + CAM_CSID_HALT_MODE_MAX, +}; + +/** + * struct cam_csid_hw_halt_args + * @halt_mode : Applicable only for PATH resources + * 0 Internal : The CSID responds to the HALT_CMD + * 1 Global : The CSID responds to the GLOBAL_HALT_CMD + * 2 Master : The CSID responds to the HALT_CMD + * 3 Slave : The CSID responds to the external halt command + * and not the HALT_CMD register + * @node_res : reource pointer array( ie cid or CSID) + * + */ +struct cam_csid_hw_halt_args { + enum cam_ife_csid_halt_mode halt_mode; + struct cam_isp_resource_node *node_res; +}; + /** * struct cam_csid_hw_stop- stop all resources * @stop_cmd : Applicable only for PATH resources diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index fc6951b2fa1e..59e2e2f5b60f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -106,6 +106,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, CAM_ISP_HW_CMD_DUMP_HW, CAM_ISP_HW_CMD_FE_TRIGGER_CMD, + CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, CAM_ISP_HW_CMD_MAX, }; -- GitLab From 0ca1c247bf8956e938c9e4ebefa854aa6d4413ee Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 30 Apr 2020 17:11:45 +0530 Subject: [PATCH 292/410] msm: camera: isp: Recover only once in case of error handling When there is CAMIF or BUS error on both the VFE hardware. We should recover only once. CRs-Fixed: 2667524 Change-Id: Idfba2d0617d4f7460b0c48d1432180c8487312ff Signed-off-by: Vikram Sharma --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index be7db2bf34f0..2315656c2f44 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6873,8 +6873,13 @@ static int cam_ife_hw_mgr_find_affected_ctx( * In the call back function corresponding ISP context * will update CRM about fatal Error */ - notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, - CAM_ISP_HW_EVENT_ERROR, error_event_data); + if (notify_err_cb) { + notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_ERROR, error_event_data); + } else { + CAM_WARN(CAM_ISP, "Error call back is not set"); + goto end; + } } /* fill the affected_core in recovery data */ @@ -6883,7 +6888,7 @@ static int cam_ife_hw_mgr_find_affected_ctx( CAM_DBG(CAM_ISP, "Vfe core %d is affected (%d)", i, recovery_data->affected_core[i]); } - +end: return 0; } @@ -6947,6 +6952,8 @@ static int cam_ife_hw_mgr_handle_hw_err( rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, core_idx, &recovery_data); + if ((rc != 0) || !(recovery_data.no_of_context)) + goto end; if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; @@ -6954,8 +6961,8 @@ static int cam_ife_hw_mgr_handle_hw_err( recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; cam_ife_hw_mgr_do_error_recovery(&recovery_data); +end: spin_unlock(&g_ife_hw_mgr.ctx_lock); - return rc; } -- GitLab From 370b0928bd56e8ad831c66db262097b4c398a8a1 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Wed, 29 Apr 2020 22:23:34 +0530 Subject: [PATCH 293/410] msm: camera: ife: check cdm hang in the ife config timeout IFE driver submit the config packet to cdm and wait for call back. If call back has not received with in 30ms, then ife return failure which cause ife stream on failure. Some time cdm call back is not coming due to cdm worker thread execution delay. So add mechanism to check if cdm worker thread delay happened then wait for some more time and check it again. CRs-Fixed: 2672759 Change-Id: Ic28299517e563d39151d56b01943930b541176da Signed-off-by: Chandan Kumar Jha --- drivers/cam_cdm/cam_cdm.h | 4 ++- drivers/cam_cdm/cam_cdm_core_common.c | 27 ++++++++++++++++++- drivers/cam_cdm/cam_cdm_core_common.h | 3 ++- drivers/cam_cdm/cam_cdm_hw_core.c | 28 +++++++++++++++++++- drivers/cam_cdm/cam_cdm_intf.c | 29 ++++++++++++++++++++- drivers/cam_cdm/cam_cdm_intf_api.h | 11 +++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 27 +++++++++++++++++-- 7 files changed, 121 insertions(+), 8 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm.h b/drivers/cam_cdm/cam_cdm.h index ab12ab52f293..3e4950720df3 100644 --- a/drivers/cam_cdm/cam_cdm.h +++ b/drivers/cam_cdm/cam_cdm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_H_ @@ -52,6 +52,7 @@ enum cam_cdm_hw_process_intf_cmd { CAM_CDM_HW_INTF_CMD_RELEASE, CAM_CDM_HW_INTF_CMD_SUBMIT_BL, CAM_CDM_HW_INTF_CMD_RESET_HW, + CAM_CDM_HW_INTF_CMD_HANG_DETECT, CAM_CDM_HW_INTF_CMD_INVALID, }; @@ -217,6 +218,7 @@ struct cam_cdm { atomic_t bl_done; struct cam_cdm_hw_mem gen_irq; uint32_t cpas_handle; + atomic_t work_record; }; /* struct cam_cdm_private_dt_data - CDM hw custom dt data */ diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index e903dc805ed0..ee9f4942950f 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -579,6 +579,31 @@ int cam_cdm_process_cmd(void *hw_priv, *((uint32_t *)cmd_args)); break; } + case CAM_CDM_HW_INTF_CMD_HANG_DETECT: { + uint32_t *handle = cmd_args; + int idx; + struct cam_cdm_client *client; + + if (sizeof(uint32_t) != arg_size) { + CAM_ERR(CAM_CDM, + "Invalid CDM cmd %d size=%x for handle=%x", + cmd, arg_size, *handle); + return -EINVAL; + } + + idx = CAM_CDM_GET_CLIENT_IDX(*handle); + mutex_lock(&cdm_hw->hw_mutex); + client = core->clients[idx]; + if ((!client) || (*handle != client->handle)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", + client, *handle); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + rc = cam_hw_cdm_hang_detect(cdm_hw, *handle); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } default: CAM_ERR(CAM_CDM, "CDM HW intf command not valid =%d", cmd); break; diff --git a/drivers/cam_cdm/cam_cdm_core_common.h b/drivers/cam_cdm/cam_cdm_core_common.h index 8dcbe8ed1971..64dc52dd597d 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.h +++ b/drivers/cam_cdm/cam_cdm_core_common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_CORE_COMMON_H_ @@ -37,6 +37,7 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, struct cam_cdm_hw_intf_cmd_submit_bl *req, struct cam_cdm_client *client); +int cam_hw_cdm_hang_detect(struct cam_hw_info *cdm_hw, uint32_t handle); struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( uint32_t tag, struct list_head *bl_list); void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 4b908dc173d3..e215bea9d984 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -563,6 +563,10 @@ static void cam_hw_cdm_work(struct work_struct *work) CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", payload->irq_data); mutex_lock(&cdm_hw->hw_mutex); + + if (atomic_read(&core->work_record)) + atomic_dec(&core->work_record); + list_for_each_entry_safe(node, tnode, &core->bl_request_list, entry) { if (node->request_type == @@ -689,6 +693,9 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) payload->hw = cdm_hw; INIT_WORK((struct work_struct *)&payload->work, cam_hw_cdm_work); + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) + atomic_inc(&cdm_core->work_record); work_status = queue_work(cdm_core->work_queue, &payload->work); if (work_status == false) { CAM_ERR(CAM_CDM, "Failed to queue work for irq=0x%x", @@ -700,6 +707,22 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) return IRQ_HANDLED; } +int cam_hw_cdm_hang_detect(struct cam_hw_info *cdm_hw, uint32_t handle) +{ + struct cam_cdm *cdm_core = NULL; + int rc = -1; + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + if (atomic_read(&cdm_core->work_record)) { + CAM_WARN(CAM_CDM, + "workqueue got delayed, work_record :%u", + atomic_read(&cdm_core->work_record)); + rc = 0; + } + return rc; +} + int cam_hw_cdm_alloc_genirq_mem(void *hw_priv) { struct cam_hw_info *cdm_hw = hw_priv; @@ -775,6 +798,7 @@ int cam_hw_cdm_init(void *hw_priv, CAM_DBG(CAM_CDM, "Enable soc done"); /* Before triggering the reset to HW, clear the reset complete */ + atomic_set(&cdm_core->work_record, 0); atomic_set(&cdm_core->error, 0); atomic_set(&cdm_core->bl_done, 0); reinit_completion(&cdm_core->reset_complete); @@ -824,6 +848,7 @@ int cam_hw_cdm_deinit(void *hw_priv, soc_info = &cdm_hw->soc_info; cdm_core = cdm_hw->core_info; + atomic_set(&cdm_core->work_record, 0); rc = cam_soc_util_disable_platform_resource(soc_info, true, true); if (rc) { CAM_ERR(CAM_CDM, "disable platform failed"); @@ -888,6 +913,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) cdm_core->flags = CAM_CDM_FLAG_PRIVATE_CDM; cdm_core->bl_tag = 0; + atomic_set(&cdm_core->work_record, 0); cdm_core->id = cam_hw_cdm_get_id_by_name(cdm_core->name); if (cdm_core->id >= CAM_CDM_MAX) { CAM_ERR(CAM_CDM, "Failed to get CDM HW name for %s", diff --git a/drivers/cam_cdm/cam_cdm_intf.c b/drivers/cam_cdm/cam_cdm_intf.c index 94e2f36d0544..9b6a4e9a67d5 100644 --- a/drivers/cam_cdm/cam_cdm_intf.c +++ b/drivers/cam_cdm/cam_cdm_intf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -379,6 +379,33 @@ int cam_cdm_reset_hw(uint32_t handle) } EXPORT_SYMBOL(cam_cdm_reset_hw); +int cam_cdm_detect_hang_error(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_HANG_DETECT, + &handle, + sizeof(handle)); + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_detect_hang_error); + int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, uint32_t *index) diff --git a/drivers/cam_cdm/cam_cdm_intf_api.h b/drivers/cam_cdm/cam_cdm_intf_api.h index 3e89b22b1b18..466ead30c358 100644 --- a/drivers/cam_cdm/cam_cdm_intf_api.h +++ b/drivers/cam_cdm/cam_cdm_intf_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CDM_API_H_ @@ -199,4 +199,13 @@ int cam_cdm_stream_off(uint32_t handle); */ int cam_cdm_reset_hw(uint32_t handle); +/** + * @brief : API to detect hang in previously acquired CDM, + * this should be only performed only if the CDM is private. + * + * @handle : Input handle of the CDM to detect hang + * + * @return 0 on success + */ +int cam_cdm_detect_hang_error(uint32_t handle); #endif /* _CAM_CDM_API_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 4846c2809842..808ef85b2c5c 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -25,6 +25,7 @@ #include "cam_common_util.h" #define CAM_IFE_HW_ENTRIES_MAX 20 +#define CAM_IFE_HW_CONFIG_WAIT_MAX_TRY 3 #define TZ_SVC_SMMU_PROGRAM 0x15 #define TZ_SAFE_SYSCALL_ID 0x3 @@ -3658,23 +3659,45 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, return rc; } - if (cfg->init_packet) { + if (!cfg->init_packet) + goto end; + + for (i = 0; i < CAM_IFE_HW_CONFIG_WAIT_MAX_TRY; i++) { rem_jiffies = wait_for_completion_timeout( &ctx->config_done_complete, msecs_to_jiffies(30)); if (rem_jiffies == 0) { + if (!cam_cdm_detect_hang_error( + ctx->cdm_handle)) { + CAM_INFO(CAM_ISP, + "CDM workqueue delay detected, wait for some more time req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, + ctx->ctx_index); + continue; + } CAM_ERR(CAM_ISP, "config done completion timeout for req_id=%llu ctx_index %d", cfg->request_id, ctx->ctx_index); rc = -ETIMEDOUT; - } else + goto end; + } else { + rc = 0; CAM_DBG(CAM_ISP, "config done Success for req_id=%llu ctx_index %d", cfg->request_id, ctx->ctx_index); + break; + } + } + if ((i == CAM_IFE_HW_CONFIG_WAIT_MAX_TRY) && (rc == 0)) { + CAM_ERR(CAM_ISP, + "config done completion timeout for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); + rc = -ETIMEDOUT; } } else { CAM_ERR(CAM_ISP, "No commands to config"); } +end: CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id); return rc; -- GitLab From 6a62506693af4c528a1c25e5bc8866adce5bb9a8 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Thu, 2 Apr 2020 02:03:58 +0530 Subject: [PATCH 294/410] msm: camera: ife: Do not acquire IFE2 for HVX usecase in lagoon In Lagoon camera there is no HVX support for IFE2. Therefore at acquire time while acquiring IFE2 we are checking if dsp_mode (HVX usecase) is set or not. If it is set then we are failing the acquire. CRs-Fixed: 2663455 Change-Id: I86235d8bcb9861db1d2570a59615ed227ee1b1eb Signed-off-by: Wyes Karny --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 19 ++++++++++++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 1 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c | 5 +++- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h | 2 ++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 28 ++++++++++++++++++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 29 +++++++++++++++++++ 7 files changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 4846c2809842..d412b52c496c 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1524,6 +1524,16 @@ static int cam_ife_hw_mgr_acquire_csid_hw( if (!ife_hw_mgr->csid_devices[i]) continue; + if (csid_acquire->in_port->dsp_mode) { + rc = ife_hw_mgr->ife_devices[i]->hw_ops + .process_cmd( + ife_hw_mgr->ife_devices[i]->hw_priv, + CAM_ISP_HW_CMD_QUERY_DSP_MODE, + NULL, 0); + if (rc) + continue; + } + hw_intf = ife_hw_mgr->csid_devices[i]; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, csid_acquire, @@ -1539,6 +1549,15 @@ static int cam_ife_hw_mgr_acquire_csid_hw( if (!ife_hw_mgr->csid_devices[i]) continue; + if (csid_acquire->in_port->dsp_mode) { + rc = ife_hw_mgr->ife_devices[i]->hw_ops.process_cmd( + ife_hw_mgr->ife_devices[i]->hw_priv, + CAM_ISP_HW_CMD_QUERY_DSP_MODE, + NULL, 0); + if (rc) + continue; + } + hw_intf = ife_hw_mgr->csid_devices[i]; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, csid_acquire, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index fc6951b2fa1e..79cdf5152331 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -104,6 +104,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, + CAM_ISP_HW_CMD_QUERY_DSP_MODE, CAM_ISP_HW_CMD_DUMP_HW, CAM_ISP_HW_CMD_FE_TRIGGER_CMD, CAM_ISP_HW_CMD_MAX, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index cd32edbc0565..cb5d22c3c626 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -594,6 +594,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CORE_CONFIG: case CAM_ISP_HW_CMD_BW_UPDATE_V2: case CAM_ISP_HW_CMD_DUMP_HW: + case CAM_ISP_HW_CMD_QUERY_DSP_MODE: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c index 77e2a059af57..0d204b7a2400 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -85,6 +85,9 @@ static int cam_vfe_get_dt_properties(struct cam_hw_soc_info *soc_info) break; } + vfe_soc_private->dsp_disabled = of_property_read_bool(of_node, + "dsp-disabled"); + end: return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h index 082c535cf3b5..3081274faed2 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -24,6 +24,7 @@ * @cpas_version: Has cpas version read from Hardware * @ubwc_static_ctrl: UBWC static control configuration * @is_ife_lite: Flag to indicate full vs lite IFE + * @dsp_disabled: Flag to indicate DSP is not supported for VFE */ struct cam_vfe_soc_private { uint32_t cpas_handle; @@ -33,6 +34,7 @@ struct cam_vfe_soc_private { int32_t dsp_clk_rate; uint32_t ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX]; bool is_ife_lite; + bool dsp_disabled; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 332332cfccc0..47d34b6c9840 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -599,6 +599,31 @@ int cam_vfe_top_write(void *device_priv, return -EPERM; } +int cam_vfe_top_query_dsp_mode(struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + + if (!top_priv) { + CAM_ERR(CAM_ISP, "Error! Invalid arguments"); + return -EINVAL; + } + + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + if (soc_private->dsp_disabled) + rc = -EINVAL; + return rc; +} + int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -651,6 +676,9 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_hw_dump(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_QUERY_DSP_MODE: + rc = cam_vfe_top_query_dsp_mode(top_priv, cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index dc15cab5e2f4..a6f662ff547f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -508,6 +508,31 @@ int cam_vfe_top_ver3_write(void *device_priv, return -EPERM; } +int cam_vfe_top_ver3_query_dsp_mode(struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + + if (!top_priv) { + CAM_ERR(CAM_ISP, "Error, Invalid arguments"); + return -EINVAL; + } + + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + if (soc_private->dsp_disabled) + rc = -EINVAL; + return rc; +} + int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -561,6 +586,10 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CORE_CONFIG: rc = cam_vfe_core_config_control(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_QUERY_DSP_MODE: + rc = cam_vfe_top_ver3_query_dsp_mode(top_priv, cmd_args, + arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type); -- GitLab From 0647776c3a48b8e0d6d88601a68dcb948b5d461a Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Wed, 6 May 2020 10:46:27 +0530 Subject: [PATCH 295/410] msm: camera: isp: return error to UMD if config fails If IFE config is failed then return error to UMD so that UMD can stop further camera operations. CRs-Fixed: 2677985 Change-Id: Ifeb8bdd8792b0723849c76357ea5b60ec13ec3b4 Signed-off-by: Tejas Prajapati --- drivers/cam_isp/cam_isp_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 63cd569c18b4..fe069396729a 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -4641,7 +4641,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, ctx->state = CAM_CTX_READY; trace_cam_context_state("ISP", ctx); if (rc == -ETIMEDOUT) - rc = cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); + cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); goto end; -- GitLab From 00b08d3208c0c60f9a3524b7504c1283b6dd6dba Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Wed, 29 Apr 2020 13:40:18 +0530 Subject: [PATCH 296/410] msm: camera: utils: add spacing between register values when using the cam_io_dump function to dump the register values we are getting 4 register values without spacing which makes is difficult to read, so adding space between two specific register values. CRs-Fixed: 2675959 Change-Id: I7e5db59398e406c30aa9729eb38331aa85736175 Signed-off-by: Tejas Prajapati --- drivers/cam_utils/cam_io_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_utils/cam_io_util.c b/drivers/cam_utils/cam_io_util.c index d35320e7e487..fcbc4b5e00f5 100644 --- a/drivers/cam_utils/cam_io_util.c +++ b/drivers/cam_utils/cam_io_util.c @@ -265,8 +265,8 @@ int cam_io_dump(void __iomem *base_addr, uint32_t start_offset, int size) p_str += 11; } data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i)); - snprintf(p_str, 9, "%08x ", data); - p_str += 8; + snprintf(p_str, 10, "%08x ", data); + p_str += 9; if ((i + 1) % NUM_REGISTER_PER_LINE == 0) { CAM_ERR(CAM_UTIL, "%s", line_str); line_str[0] = '\0'; -- GitLab From 7eee5ea6854c6e7a9821fe2da77b2bfc17f800c9 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Thu, 7 May 2020 00:34:12 +0530 Subject: [PATCH 297/410] msm: camera: reqmgr: Work queue names added Added wrapper functions for each workq to enable workq names in log. CRs-Fixed: 2684378 Change-Id: If5b3671fbf20777cc891cba4b27cad6ed3a0d146 Signed-off-by: Wyes Karny --- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 8 +++++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 25 ++++++++++++++++--- drivers/cam_isp/cam_isp_context.c | 8 +++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 8 +++++- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 16 ++++++++++-- .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 9 +++++-- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 8 +++++- drivers/cam_req_mgr/cam_req_mgr_core.c | 11 ++++++-- drivers/cam_req_mgr/cam_req_mgr_workq.c | 8 +++--- drivers/cam_req_mgr/cam_req_mgr_workq.h | 11 ++++++-- 10 files changed, 92 insertions(+), 20 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 6a422038f5a5..dc2c625ca8bb 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1936,6 +1936,11 @@ int cam_fd_hw_mgr_deinit(struct device_node *of_node) return 0; } +static void cam_req_mgr_process_workq_cam_fd_worker(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + int cam_fd_hw_mgr_init(struct device_node *of_node, struct cam_hw_mgr_intf *hw_mgr_intf) { @@ -2081,7 +2086,8 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, } rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK, - &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0); + &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0, + cam_req_mgr_process_workq_cam_fd_worker); if (rc) { CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc); goto detach_smmu; 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 cc8b516e0d64..01a4fb16005c 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 @@ -5974,28 +5974,45 @@ static int cam_icp_mgr_init_devs(struct device_node *of_node) return rc; } +static void cam_req_mgr_process_workq_icp_command_queue(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + +static void cam_req_mgr_process_workq_icp_message_queue(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + +static void cam_req_mgr_process_workq_icp_timer_queue(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + static int cam_icp_mgr_create_wq(void) { int rc; int i; rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, - 0); + &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, 0, + cam_req_mgr_process_workq_icp_command_queue); if (rc) { CAM_ERR(CAM_ICP, "unable to create a command worker"); goto cmd_work_failed; } rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0); + &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0, + cam_req_mgr_process_workq_icp_message_queue); if (rc) { CAM_ERR(CAM_ICP, "unable to create a message worker"); goto msg_work_failed; } rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0); + &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0, + cam_req_mgr_process_workq_icp_timer_queue); if (rc) { CAM_ERR(CAM_ICP, "unable to create a timer worker"); goto timer_work_failed; diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 63cd569c18b4..85e7bc9a5f55 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -4223,6 +4223,11 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, return rc; } +static void cam_req_mgr_process_workq_offline_ife_worker(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, void *args) { @@ -4347,7 +4352,8 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, ctx_isp->offline_context = true; rc = cam_req_mgr_workq_create("offline_ife", 20, - &ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0); + &ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0, + cam_req_mgr_process_workq_offline_ife_worker); if (rc) CAM_ERR(CAM_ISP, "Failed to create workq for offline IFE rc:%d", diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 4846c2809842..9f6c8d170c1a 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -7405,6 +7405,11 @@ static int cam_ife_hw_mgr_debug_register(void) return -ENOMEM; } +static void cam_req_mgr_process_workq_cam_ife_worker(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) { int rc = -EFAULT; @@ -7553,7 +7558,8 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) /* Create Worker for ife_hw_mgr with 10 tasks */ rc = cam_req_mgr_workq_create("cam_ife_worker", 10, - &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0); + &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0, + cam_req_mgr_process_workq_cam_ife_worker); if (rc < 0) { CAM_ERR(CAM_ISP, "Unable to create worker"); goto end; diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index ac2612356448..342c6d3fb4e9 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1285,6 +1285,16 @@ static int cam_jpeg_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) return rc; } +static void cam_req_mgr_process_workq_jpeg_command_queue(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + +static void cam_req_mgr_process_workq_jpeg_message_queue(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + static int cam_jpeg_setup_workqs(void) { int rc, i; @@ -1293,7 +1303,8 @@ static int cam_jpeg_setup_workqs(void) "jpeg_command_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_frame, - CRM_WORKQ_USAGE_NON_IRQ, 0); + CRM_WORKQ_USAGE_NON_IRQ, 0, + cam_req_mgr_process_workq_jpeg_command_queue); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); goto work_process_frame_failed; @@ -1303,7 +1314,8 @@ static int cam_jpeg_setup_workqs(void) "jpeg_message_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_irq_cb, - CRM_WORKQ_USAGE_IRQ, 0); + CRM_WORKQ_USAGE_IRQ, 0, + cam_req_mgr_process_workq_jpeg_message_queue); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); goto work_process_irq_cb_failed; diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 537fc48a619e..5cf8c55c0e37 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -1041,6 +1041,11 @@ static int cam_lrme_mgr_create_debugfs_entry(void) return rc; } +static void cam_req_mgr_process_workq_cam_lrme_device_submit_worker( + struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} int cam_lrme_mgr_register_device( struct cam_hw_intf *lrme_hw_intf, @@ -1068,8 +1073,8 @@ int cam_lrme_mgr_register_device( CAM_DBG(CAM_LRME, "Create submit workq for %s", buf); rc = cam_req_mgr_workq_create(buf, CAM_LRME_WORKQ_NUM_TASK, - &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, - 0); + &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, 0, + cam_req_mgr_process_workq_cam_lrme_device_submit_worker); if (rc) { CAM_ERR(CAM_LRME, "Unable to create a worker, rc=%d", rc); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index ef076a3c6279..ad4e695f575e 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -76,6 +76,11 @@ static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core, return rc; } +static void cam_req_mgr_process_workq_cam_lrme_hw_worker(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + static int cam_lrme_hw_dev_probe(struct platform_device *pdev) { struct cam_hw_info *lrme_hw; @@ -115,7 +120,8 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) rc = cam_req_mgr_workq_create("cam_lrme_hw_worker", CAM_LRME_HW_WORKQ_NUM_TASK, - &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0); + &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0, + cam_req_mgr_process_workq_cam_lrme_hw_worker); if (rc) { CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc); goto free_memory; diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index f75ee21f87fe..25cb710f73aa 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3357,6 +3357,11 @@ int cam_req_mgr_destroy_session( return rc; } +static void cam_req_mgr_process_workq_link_worker(struct work_struct *w) +{ + cam_req_mgr_process_workq(w); +} + int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) { int rc = 0; @@ -3435,7 +3440,8 @@ int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) link_info->u.link_info_v1.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, - &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag, + cam_req_mgr_process_workq_link_worker); if (rc < 0) { CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); __cam_req_mgr_destroy_link_info(link); @@ -3544,7 +3550,8 @@ int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) link_info->u.link_info_v2.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, - &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag, + cam_req_mgr_process_workq_link_worker); if (rc < 0) { CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); __cam_req_mgr_destroy_link_info(link); diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.c b/drivers/cam_req_mgr/cam_req_mgr_workq.c index 29d98503f305..0c9ff7c419ca 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include "cam_req_mgr_workq.h" @@ -88,7 +88,7 @@ static int cam_req_mgr_process_task(struct crm_workq_task *task) * cam_req_mgr_process_workq() - main loop handling * @w: workqueue task pointer */ -static void cam_req_mgr_process_workq(struct work_struct *w) +void cam_req_mgr_process_workq(struct work_struct *w) { struct cam_req_mgr_core_workq *workq = NULL; struct crm_workq_task *task; @@ -172,7 +172,7 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, int cam_req_mgr_workq_create(char *name, int32_t num_tasks, struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, - int flags) + int flags, void (*func)(struct work_struct *w)) { int32_t i, wq_flags = 0, max_active_tasks = 0; struct crm_workq_task *task; @@ -202,7 +202,7 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, } /* Workq attributes initialization */ - INIT_WORK(&crm_workq->work, cam_req_mgr_process_workq); + INIT_WORK(&crm_workq->work, func); spin_lock_init(&crm_workq->lock_bh); CAM_DBG(CAM_CRM, "LOCK_DBG workq %s lock %pK", name, &crm_workq->lock_bh); diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.h b/drivers/cam_req_mgr/cam_req_mgr_workq.h index f938710b69ae..6416b66647f4 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_workq.h +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_REQ_MGR_WORKQ_H_ @@ -96,6 +96,12 @@ struct cam_req_mgr_core_workq { } task; }; +/** + * cam_req_mgr_process_workq() - main loop handling + * @w: workqueue task pointer + */ +void cam_req_mgr_process_workq(struct work_struct *w); + /** * cam_req_mgr_workq_create() * @brief : create a workqueue @@ -106,12 +112,13 @@ struct cam_req_mgr_core_workq { * @in_irq : Set to one if workq might be used in irq context * @flags : Bitwise OR of Flags for workq behavior. * e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL + * @func : function pointer for cam_req_mgr_process_workq wrapper function * This function will allocate and create workqueue and pass * the workq pointer to caller. */ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, - int flags); + int flags, void (*func)(struct work_struct *w)); /** * cam_req_mgr_workq_destroy() -- GitLab From 14e0860ad8872a4d1df71dbfe45551c6d428ab0f Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Mon, 11 May 2020 23:33:35 +0530 Subject: [PATCH 298/410] msm: camera: utils: Handle cx_ipeak register failure gracefully If cx_ipeak def config is not available the device registration was failing which was resulting in probe failure. This change gives a warning and returns success. CRs-Fixed: 2683960 Change-Id: Ide0c60f7e1bf83b2afcb1288972d087e009b9c8c Signed-off-by: Vikram Sharma --- drivers/cam_utils/cam_cx_ipeak.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_utils/cam_cx_ipeak.c b/drivers/cam_utils/cam_cx_ipeak.c index b0f93ba045e0..58246e86b8da 100644 --- a/drivers/cam_utils/cam_cx_ipeak.c +++ b/drivers/cam_utils/cam_cx_ipeak.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -35,7 +35,7 @@ int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info) if (cam_cx_ipeak) { goto exit; } else { - rc = -EINVAL; + CAM_WARN(CAM_UTIL, "cx_ipeak_register failed"); goto exit; } -- GitLab From 9591ccfd28ce7ff790023115486e14ae2577b267 Mon Sep 17 00:00:00 2001 From: Zhaohong Chen Date: Mon, 30 Mar 2020 02:22:15 +0800 Subject: [PATCH 299/410] msm: camera: sensor: Add support for multiple slave address Add support for program multiple slave addresses in a i2c sensor sequence. CRs-Fixed: 2660303 Change-Id: Idbb1c6c77ed0494c3e22cb14055ea7a613772c5a Signed-off-by: Zhaohong Chen --- .../cam_sensor/cam_sensor_core.c | 168 +++++++++++++----- .../cam_sensor_utils/cam_sensor_cmn_header.h | 7 +- .../cam_sensor_utils/cam_sensor_util.c | 45 ++--- 3 files changed, 148 insertions(+), 72 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 696bbd3b90cb..1362deba12d2 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -278,12 +278,99 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, return rc; } +static int32_t cam_sensor_restore_slave_info(struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + + switch (s_ctrl->io_master_info.master_type) { + case CCI_MASTER: + s_ctrl->io_master_info.cci_client->sid = + (s_ctrl->sensordata->slave_info.sensor_slave_addr >> 1); + s_ctrl->io_master_info.cci_client->i2c_freq_mode = + s_ctrl->sensordata->slave_info.i2c_freq_mode; + break; + + case I2C_MASTER: + s_ctrl->io_master_info.client->addr = + s_ctrl->sensordata->slave_info.sensor_slave_addr; + break; + + case SPI_MASTER: + break; + + default: + CAM_ERR(CAM_SENSOR, "Invalid master type: %d", + s_ctrl->io_master_info.master_type); + rc = -EINVAL; + break; + } + + return rc; +} + +static int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info, + struct cam_sensor_ctrl_t *s_ctrl, + bool isInit) +{ + int32_t rc = 0; + struct cam_sensor_cci_client *cci_client = NULL; + + switch (s_ctrl->io_master_info.master_type) { + case CCI_MASTER: + cci_client = s_ctrl->io_master_info.cci_client; + if (!cci_client) { + CAM_ERR(CAM_SENSOR, "failed: cci_client %pK", + cci_client); + return -EINVAL; + } + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = i2c_info->slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + CAM_DBG(CAM_SENSOR, " Master: %d sid: 0x%x freq_mode: %d", + cci_client->cci_i2c_master, i2c_info->slave_addr, + i2c_info->i2c_freq_mode); + break; + + case I2C_MASTER: + s_ctrl->io_master_info.client->addr = i2c_info->slave_addr; + break; + + case SPI_MASTER: + break; + + default: + CAM_ERR(CAM_SENSOR, "Invalid master type: %d", + s_ctrl->io_master_info.master_type); + rc = -EINVAL; + break; + } + + if (isInit) { + s_ctrl->sensordata->slave_info.sensor_slave_addr = + i2c_info->slave_addr; + s_ctrl->sensordata->slave_info.i2c_freq_mode = + i2c_info->i2c_freq_mode; + } + + return rc; +} + static int32_t cam_sensor_i2c_modes_util( - struct camera_io_master *io_master_info, + struct cam_sensor_ctrl_t *s_ctrl, struct i2c_settings_list *i2c_list) { int32_t rc = 0; uint32_t i, size; + struct camera_io_master *io_master_info; + + if (s_ctrl == NULL) { + CAM_ERR(CAM_SENSOR, "Invalid args"); + return -EINVAL; + } + + io_master_info = &s_ctrl->io_master_info; if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { rc = camera_io_dev_write(io_master_info, @@ -333,39 +420,20 @@ static int32_t cam_sensor_i2c_modes_util( return rc; } } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_SET_I2C_INFO) { + rc = cam_sensor_update_i2c_info(&i2c_list->slave_info, + s_ctrl, + false); + } else if ((i2c_list->op_code == CAM_SENSOR_I2C_READ_RANDOM) || + (i2c_list->op_code == CAM_SENSOR_I2C_READ_SEQ)) { + rc = cam_sensor_i2c_read_data( + &s_ctrl->i2c_data.read_settings, + &s_ctrl->io_master_info); } return rc; } -int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info, - struct cam_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - struct cam_sensor_cci_client *cci_client = NULL; - - if (s_ctrl->io_master_info.master_type == CCI_MASTER) { - cci_client = s_ctrl->io_master_info.cci_client; - if (!cci_client) { - CAM_ERR(CAM_SENSOR, "failed: cci_client %pK", - cci_client); - return -EINVAL; - } - cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; - cci_client->sid = i2c_info->slave_addr >> 1; - cci_client->retries = 3; - cci_client->id_map = 0; - cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; - CAM_DBG(CAM_SENSOR, " Master: %d sid: %d freq_mode: %d", - cci_client->cci_i2c_master, i2c_info->slave_addr, - i2c_info->i2c_freq_mode); - } - - s_ctrl->sensordata->slave_info.sensor_slave_addr = - i2c_info->slave_addr; - return rc; -} - int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, struct cam_sensor_ctrl_t *s_ctrl) { @@ -411,7 +479,7 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, return -EINVAL; } i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; - rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl); + rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl, true); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed in Updating the i2c Info"); return rc; @@ -989,12 +1057,13 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } if (s_ctrl->i2c_data.read_settings.is_settings_valid) { - rc = cam_sensor_i2c_read_data( - &s_ctrl->i2c_data.read_settings, - &s_ctrl->io_master_info); + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_READ); if (rc < 0) { - CAM_ERR(CAM_SENSOR, "cannot read data: %d", rc); - delete_request(&s_ctrl->i2c_data.read_settings); + CAM_ERR(CAM_SENSOR, + "cannot apply read settings"); + delete_request( + &s_ctrl->i2c_data.read_settings); goto release_mutex; } rc = delete_request( @@ -1005,6 +1074,11 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } } + + CAM_DBG(CAM_SENSOR, + "CAM_CONFIG_DEV done sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); } break; default: @@ -1101,8 +1175,7 @@ int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) int rc; struct cam_sensor_power_ctrl_t *power_info; struct cam_camera_slave_info *slave_info; - struct cam_hw_soc_info *soc_info = - &s_ctrl->soc_info; + struct cam_hw_soc_info *soc_info; if (!s_ctrl) { CAM_ERR(CAM_SENSOR, "failed: %pK", s_ctrl); @@ -1117,6 +1190,8 @@ int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) return -EINVAL; } + soc_info = &s_ctrl->soc_info; + if (s_ctrl->bob_pwm_switch) { rc = cam_sensor_bob_pwm_mode_switch(soc_info, s_ctrl->bob_reg_index, true); @@ -1205,6 +1280,10 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, i2c_set = &s_ctrl->i2c_data.streamoff_settings; break; } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_READ: { + i2c_set = &s_ctrl->i2c_data.read_settings; + break; + } case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: case CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE: default: @@ -1213,14 +1292,13 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, if (i2c_set->is_settings_valid == 1) { list_for_each_entry(i2c_list, &(i2c_set->list_head), list) { - rc = cam_sensor_i2c_modes_util( - &(s_ctrl->io_master_info), + rc = cam_sensor_i2c_modes_util(s_ctrl, i2c_list); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to apply settings: %d", rc); - return rc; + goto EXIT_RESTORE; } } } @@ -1231,14 +1309,13 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, i2c_set->request_id == req_id) { list_for_each_entry(i2c_list, &(i2c_set->list_head), list) { - rc = cam_sensor_i2c_modes_util( - &(s_ctrl->io_master_info), + rc = cam_sensor_i2c_modes_util(s_ctrl, i2c_list); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to apply settings: %d", rc); - return rc; + goto EXIT_RESTORE; } } } else { @@ -1268,7 +1345,7 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, } if (!del_req_id) - return rc; + goto EXIT_RESTORE; CAM_DBG(CAM_SENSOR, "top: %llu, del_req_id:%llu", top, del_req_id); @@ -1289,6 +1366,9 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, } } +EXIT_RESTORE: + (void)cam_sensor_restore_slave_info(s_ctrl); + return rc; } diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 563414e640cc..43734ace9c9d 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SENSOR_CMN_HEADER_ @@ -223,7 +223,8 @@ enum cam_sensor_i2c_cmd_type { CAM_SENSOR_I2C_WRITE_SEQ, CAM_SENSOR_I2C_READ_RANDOM, CAM_SENSOR_I2C_READ_SEQ, - CAM_SENSOR_I2C_POLL + CAM_SENSOR_I2C_POLL, + CAM_SENSOR_I2C_SET_I2C_INFO }; struct common_header { @@ -288,6 +289,7 @@ struct cam_sensor_i2c_seq_reg { struct i2c_settings_list { struct cam_sensor_i2c_reg_setting i2c_settings; struct cam_sensor_i2c_seq_reg seq_settings; + struct cam_cmd_i2c_info slave_info; enum cam_sensor_i2c_cmd_type op_code; struct list_head list; }; @@ -323,6 +325,7 @@ struct cam_camera_slave_info { uint16_t sensor_id_reg_addr; uint16_t sensor_id; uint16_t sensor_id_mask; + uint8_t i2c_freq_mode; }; struct msm_sensor_init_params { diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index cf10ee5d7edf..b0c0b4384366 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -368,36 +368,23 @@ static int32_t cam_sensor_handle_continuous_read( } static int cam_sensor_handle_slave_info( - struct camera_io_master *io_master, - uint32_t *cmd_buf) + uint32_t *cmd_buf, + struct i2c_settings_array *i2c_reg_settings, + struct list_head **list_ptr) { int rc = 0; struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + struct i2c_settings_list *i2c_list; - if (io_master == NULL || cmd_buf == NULL) { - CAM_ERR(CAM_SENSOR, "Invalid args"); - return -EINVAL; + i2c_list = + cam_sensor_get_i2c_ptr(i2c_reg_settings, 1); + if (!i2c_list || !i2c_list->i2c_settings.reg_setting) { + CAM_ERR(CAM_SENSOR, "Failed in allocating mem for list"); + return -ENOMEM; } - switch (io_master->master_type) { - case CCI_MASTER: - io_master->cci_client->sid = (i2c_info->slave_addr >> 1); - io_master->cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; - break; - - case I2C_MASTER: - io_master->client->addr = i2c_info->slave_addr; - break; - - case SPI_MASTER: - break; - - default: - CAM_ERR(CAM_SENSOR, "Invalid master type: %d", - io_master->master_type); - rc = -EINVAL; - break; - } + i2c_list->op_code = CAM_SENSOR_I2C_SET_I2C_INFO; + i2c_list->slave_info = *i2c_info; return rc; } @@ -617,7 +604,7 @@ int cam_sensor_i2c_command_parser( goto end; } rc = cam_sensor_handle_slave_info( - io_master, cmd_buf); + cmd_buf, i2c_reg_settings, &list); if (rc) { CAM_ERR(CAM_SENSOR, "Handle slave info failed with rc: %d", @@ -809,6 +796,12 @@ int32_t cam_sensor_i2c_read_data( list_for_each_entry(i2c_list, &(i2c_settings->list_head), list) { + if (i2c_list->op_code == CAM_SENSOR_I2C_SET_I2C_INFO) { + CAM_DBG(CAM_SENSOR, + "CAM_SENSOR_I2C_SET_I2C_INFO continue"); + continue; + } + read_buff = i2c_list->i2c_settings.read_buff; buff_length = i2c_list->i2c_settings.read_buff_len; if ((read_buff == NULL) || (buff_length == 0)) { -- GitLab From 51369bd51d3a85fd8ccb2b90c09aba153d1bfd15 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Tue, 19 May 2020 11:57:02 +0530 Subject: [PATCH 300/410] msm: camera: ife: Do not reset epd value during csid reset EPD value is retrieved from init packet and set. It is uninitialized during CSID global reset as part of CSID init. uninitialization of EPD variable is removed to fix the issue. CRs-Fixed: 2690666 Change-Id: I3454007d3130e4cb8397ab0b09416da7f000bab2 Signed-off-by: Ravikishore Pampana --- .../cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index d80a8a08ed05..ed5f93829019 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -526,7 +526,6 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->hw_intf->hw_idx, val); csid_hw->error_irq_count = 0; csid_hw->prev_boot_timestamp = 0; - csid_hw->epd_supported = 0; end: return rc; -- GitLab From 463158a771a4a27381d480e742c7393a73c7cbae Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 11 May 2020 11:37:23 -0700 Subject: [PATCH 301/410] msm: camera: reqmgr: Add provision in UAPI for INIT exp timeout Add provision in CRM link control to accept any long exposure timeout value so that CRM can modify it's internal WD timer during link activate. CRs-Fixed: 2679913 Change-Id: Icedeeef32dcc5c881277f28dc2c0fbb40fa1e7f1 Signed-off-by: Karthik Anantha Ram --- include/uapi/media/cam_req_mgr.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 56223e99d8be..126d49d4b3f5 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -231,6 +231,9 @@ struct cam_req_mgr_sync_mode { * @session_hdl: Input param - Identifier for CSL session * @num_links: Input Param - Num of links * @reserved: reserved field + * @init_timeout: To account for INIT exposure settings + * If there is no change in exp settings + * field needs to assigned to 0 * @link_hdls: Input Param - Links to be activated/deactivated * * @opcode: CAM_REQ_MGR_LINK_CONTROL @@ -240,6 +243,7 @@ struct cam_req_mgr_link_control { int32_t session_hdl; int32_t num_links; int32_t reserved; + int32_t init_timeout[MAX_LINKS_PER_SESSION]; int32_t link_hdls[MAX_LINKS_PER_SESSION]; }; -- GitLab From 4eba6a54a48c900d87612bb0947657ed397c6f87 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Thu, 28 May 2020 18:24:28 +0530 Subject: [PATCH 302/410] msm: camera: isp: Prevent event processing during overflow In case of hw error, we should not process camif events. This change is to prevent processing sof epoch rup and eof event if overflow_pending flag is ON. CRs-Fixed: 2694908 Change-Id: Iefb552dbcf550727227493b1d5894ef1a7d07533 Signed-off-by: Ayush Kumar --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 30 ++++++++++----------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index fe5b9565ce41..ab0631798aaf 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -686,7 +686,7 @@ static void cam_ife_hw_mgr_print_acquire_info( goto fail; CAM_INFO(CAM_ISP, - "Acquired %s IFE[%d %d] with [%u pix] [%u pd] [%u rdi] ports for ctx:%u", + "Successfully acquire %s IFE[%d %d] with [%u pix] [%u pd] [%u rdi] ports for ctx:%u", (hw_mgr_ctx->is_dual) ? "dual" : "single", hw_idx[CAM_ISP_HW_SPLIT_LEFT], hw_idx[CAM_ISP_HW_SPLIT_RIGHT], num_pix_port, num_pd_port, num_rdi_port, hw_mgr_ctx->ctx_index); @@ -696,7 +696,7 @@ static void cam_ife_hw_mgr_print_acquire_info( fail: CAM_ERR(CAM_ISP, "Acquire HW failed for ctx:%u", hw_mgr_ctx->ctx_index); CAM_INFO(CAM_ISP, - "Previously acquired %s IFE[%d %d] with [%u pix] [%u pd] [%u rdi] ports for ctx:%u", + "Fail to acquire %s IFE[%d %d] with [%u pix] [%u pd] [%u rdi] ports for ctx:%u", (hw_mgr_ctx->is_dual) ? "dual" : "single", hw_idx[CAM_ISP_HW_SPLIT_LEFT], hw_idx[CAM_ISP_HW_SPLIT_RIGHT], num_pix_port, num_pd_port, num_rdi_port, hw_mgr_ctx->ctx_index); @@ -7060,6 +7060,9 @@ static int cam_ife_hw_mgr_handle_hw_rup( return 0; } + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + return 0; + ife_hwr_irq_rup_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE]; @@ -7070,8 +7073,6 @@ static int cam_ife_hw_mgr_handle_hw_rup( ife_hw_mgr_ctx->master_hw_idx)) break; - if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) - break; ife_hwr_irq_rup_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); break; @@ -7082,8 +7083,6 @@ static int cam_ife_hw_mgr_handle_hw_rup( case CAM_ISP_HW_VFE_IN_RDI3: if (!ife_hw_mgr_ctx->is_rdi_only_context) break; - if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) - break; ife_hwr_irq_rup_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); break; @@ -7175,6 +7174,9 @@ static int cam_ife_hw_mgr_handle_hw_epoch( return 0; } + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + return 0; + ife_hw_irq_epoch_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH]; @@ -7184,9 +7186,6 @@ static int cam_ife_hw_mgr_handle_hw_epoch( rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, CAM_ISP_HW_EVENT_EPOCH); if (!rc) { - if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) - break; - epoch_done_event_data.frame_id_meta = event_info->th_reg_val; ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, @@ -7229,6 +7228,9 @@ static int cam_ife_hw_mgr_handle_hw_sof( return 0; } + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + return 0; + memset(&sof_done_event_data, 0, sizeof(sof_done_event_data)); ife_hw_irq_sof_cb = @@ -7255,9 +7257,6 @@ static int cam_ife_hw_mgr_handle_hw_sof( if (ife_hw_mgr_ctx->use_frame_header_ts) sof_done_event_data.timestamp = 0x0; - if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) - break; - ife_hw_irq_sof_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); } @@ -7272,8 +7271,6 @@ static int cam_ife_hw_mgr_handle_hw_sof( cam_ife_mgr_cmd_get_sof_timestamp(ife_hw_mgr_ctx, &sof_done_event_data.timestamp, &sof_done_event_data.boot_time); - if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) - break; ife_hw_irq_sof_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); break; @@ -7309,6 +7306,9 @@ static int cam_ife_hw_mgr_handle_hw_eof( return 0; } + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + return 0; + ife_hw_irq_eof_cb = ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF]; @@ -7318,8 +7318,6 @@ static int cam_ife_hw_mgr_handle_hw_eof( rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, CAM_ISP_HW_EVENT_EOF); if (!rc) { - if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) - break; ife_hw_irq_eof_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_EOF, &eof_done_event_data); } -- GitLab From 5969a17ac396b47af04f235e6ebf50b01732db52 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Fri, 22 May 2020 16:05:14 +0530 Subject: [PATCH 303/410] msm: camera: ife: Acquire IFE which are HVX supported for HVX usecase At acquire time we first check if dsp_mode is enabled or not. If enabled we query each IFE if it supports HVX or not. We try to acquire the IFE which are HVX supported. CRs-Fixed: 2691895 Change-Id: I819c6fa56b1efa63a0c8eac0c32d7a6b1a12f2d9 Signed-off-by: Wyes Karny --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 13 ++++++++---- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 12 +++++++++++ .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 2 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 20 +++++++++++++----- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 21 +++++++++++++------ 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index fe5b9565ce41..ee130ed7524f 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1553,6 +1553,7 @@ static int cam_ife_hw_mgr_acquire_csid_hw( int i; int rc = -1; struct cam_hw_intf *hw_intf; + struct cam_isp_hw_cmd_query vfe_query; if (!ife_hw_mgr || !csid_acquire) { CAM_ERR(CAM_ISP, @@ -1567,11 +1568,13 @@ static int cam_ife_hw_mgr_acquire_csid_hw( continue; if (csid_acquire->in_port->dsp_mode) { + vfe_query.query_cmd = + CAM_ISP_HW_CMD_QUERY_DSP_MODE; rc = ife_hw_mgr->ife_devices[i]->hw_ops .process_cmd( ife_hw_mgr->ife_devices[i]->hw_priv, - CAM_ISP_HW_CMD_QUERY_DSP_MODE, - NULL, 0); + CAM_ISP_HW_CMD_QUERY, + &vfe_query, sizeof(vfe_query)); if (rc) continue; } @@ -1592,10 +1595,12 @@ static int cam_ife_hw_mgr_acquire_csid_hw( continue; if (csid_acquire->in_port->dsp_mode) { + vfe_query.query_cmd = + CAM_ISP_HW_CMD_QUERY_DSP_MODE; rc = ife_hw_mgr->ife_devices[i]->hw_ops.process_cmd( ife_hw_mgr->ife_devices[i]->hw_priv, - CAM_ISP_HW_CMD_QUERY_DSP_MODE, - NULL, 0); + CAM_ISP_HW_CMD_QUERY, + &vfe_query, sizeof(vfe_query)); if (rc) continue; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 020c3c88197b..093b4f9a1114 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -104,6 +104,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, + CAM_ISP_HW_CMD_QUERY, CAM_ISP_HW_CMD_QUERY_DSP_MODE, CAM_ISP_HW_CMD_DUMP_HW, CAM_ISP_HW_CMD_FE_TRIGGER_CMD, @@ -111,6 +112,17 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_MAX, }; +/* + * struct cam_isp_hw_cmd_query + * + * @Brief: Structure representing query command to HW + * + * @query_cmd: Command identifier + */ +struct cam_isp_hw_cmd_query { + int query_cmd; +}; + /* * struct cam_isp_resource_node: * diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index cb5d22c3c626..5f861f954228 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -594,7 +594,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CORE_CONFIG: case CAM_ISP_HW_CMD_BW_UPDATE_V2: case CAM_ISP_HW_CMD_DUMP_HW: - case CAM_ISP_HW_CMD_QUERY_DSP_MODE: + case CAM_ISP_HW_CMD_QUERY: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 47d34b6c9840..4f1026b8ca9d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -599,28 +599,38 @@ int cam_vfe_top_write(void *device_priv, return -EPERM; } -int cam_vfe_top_query_dsp_mode(struct cam_vfe_top_ver2_priv *top_priv, +int cam_vfe_top_query(struct cam_vfe_top_ver2_priv *top_priv, void *cmd_args, uint32_t arg_size) { int rc = 0; + struct cam_isp_hw_cmd_query *vfe_query; struct cam_hw_soc_info *soc_info = NULL; struct cam_vfe_soc_private *soc_private = NULL; - if (!top_priv) { + if (!top_priv || !cmd_args) { CAM_ERR(CAM_ISP, "Error! Invalid arguments"); return -EINVAL; } soc_info = top_priv->common_data.soc_info; soc_private = soc_info->soc_private; + vfe_query = (struct cam_isp_hw_cmd_query *)cmd_args; if (!soc_private) { CAM_ERR(CAM_ISP, "Error soc_private NULL"); return -EINVAL; } - if (soc_private->dsp_disabled) + switch (vfe_query->query_cmd) { + case CAM_ISP_HW_CMD_QUERY_DSP_MODE: + if (soc_private->dsp_disabled) + rc = -EINVAL; + break; + default: rc = -EINVAL; + CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", vfe_query->query_cmd); + break; + } return rc; } @@ -676,8 +686,8 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_hw_dump(top_priv, cmd_args, arg_size); break; - case CAM_ISP_HW_CMD_QUERY_DSP_MODE: - rc = cam_vfe_top_query_dsp_mode(top_priv, cmd_args, arg_size); + case CAM_ISP_HW_CMD_QUERY: + rc = cam_vfe_top_query(top_priv, cmd_args, arg_size); break; default: rc = -EINVAL; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index a6f662ff547f..2548dd0ac0ca 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -508,28 +508,38 @@ int cam_vfe_top_ver3_write(void *device_priv, return -EPERM; } -int cam_vfe_top_ver3_query_dsp_mode(struct cam_vfe_top_ver3_priv *top_priv, +int cam_vfe_top_ver3_query(struct cam_vfe_top_ver3_priv *top_priv, void *cmd_args, uint32_t arg_size) { int rc = 0; + struct cam_isp_hw_cmd_query *vfe_query; struct cam_hw_soc_info *soc_info = NULL; struct cam_vfe_soc_private *soc_private = NULL; - if (!top_priv) { + if (!top_priv || !cmd_args) { CAM_ERR(CAM_ISP, "Error, Invalid arguments"); return -EINVAL; } soc_info = top_priv->common_data.soc_info; soc_private = soc_info->soc_private; + vfe_query = (struct cam_isp_hw_cmd_query *)cmd_args; if (!soc_private) { CAM_ERR(CAM_ISP, "Error soc_private NULL"); return -EINVAL; } - if (soc_private->dsp_disabled) + switch (vfe_query->query_cmd) { + case CAM_ISP_HW_CMD_QUERY_DSP_MODE: + if (soc_private->dsp_disabled) + rc = -EINVAL; + break; + default: rc = -EINVAL; + CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", vfe_query->query_cmd); + break; + } return rc; } @@ -586,9 +596,8 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_CORE_CONFIG: rc = cam_vfe_core_config_control(top_priv, cmd_args, arg_size); break; - case CAM_ISP_HW_CMD_QUERY_DSP_MODE: - rc = cam_vfe_top_ver3_query_dsp_mode(top_priv, cmd_args, - arg_size); + case CAM_ISP_HW_CMD_QUERY: + rc = cam_vfe_top_ver3_query(top_priv, cmd_args, arg_size); break; default: rc = -EINVAL; -- GitLab From 66c84934454a65a5e2cd038302373111739288df Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Wed, 29 Apr 2020 11:52:35 +0530 Subject: [PATCH 304/410] msm: camera: reqmgr: Modify SOF watchlog timer for INIT exposure In case of long exposure shots, watchdog timer needs to be modified for init exposure seeting also to avoid trigger. CRs-Fixed: 2679913 Change-Id: Ife8b3ec32103aff71d281e11b68e0d48f4ef79e1 Signed-off-by: Chandan Kumar Jha --- drivers/cam_req_mgr/cam_req_mgr_core.c | 22 ++++++++++++++++++---- drivers/cam_req_mgr/cam_req_mgr_core.h | 3 +++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 25cb710f73aa..355e43d6c9fb 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -49,6 +49,7 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) link->initial_skip = true; link->sof_timestamp = 0; link->prev_sof_timestamp = 0; + link->skip_wd_validation = false; } void cam_req_mgr_handle_core_shutdown(void) @@ -521,6 +522,13 @@ static void __cam_req_mgr_validate_crm_wd_timer( int next_frame_timeout = 0, current_frame_timeout = 0; struct cam_req_mgr_req_queue *in_q = link->req.in_q; + if (link->skip_wd_validation) { + CAM_DBG(CAM_CRM, + "skipping modifying wd timer for first frame after streamon"); + link->skip_wd_validation = false; + return; + } + idx = in_q->rd_idx; __cam_req_mgr_dec_idx( &idx, (link->max_delay - 1), @@ -538,6 +546,7 @@ static void __cam_req_mgr_validate_crm_wd_timer( CAM_DBG(CAM_CRM, "rd_idx: %d idx: %d current_frame_timeout: %d ms", in_q->rd_idx, idx, current_frame_timeout); + spin_lock_bh(&link->link_state_spin_lock); if (link->watchdog) { if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > @@ -559,8 +568,8 @@ static void __cam_req_mgr_validate_crm_wd_timer( crm_timer_modify(link->watchdog, current_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT); - } else if (link->watchdog->expires > - CAM_REQ_MGR_WATCHDOG_TIMEOUT) { + } else if (!next_frame_timeout && (link->watchdog->expires > + CAM_REQ_MGR_WATCHDOG_TIMEOUT)) { CAM_DBG(CAM_CRM, "Reset wd timer to default from %d ms to %d ms", link->watchdog->expires, @@ -3895,6 +3904,7 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) struct cam_req_mgr_connected_device *dev = NULL; struct cam_req_mgr_link_evt_data evt_data; + int init_timeout = 0; if (!control) { CAM_ERR(CAM_CRM, "Control command is NULL"); @@ -3926,10 +3936,13 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) spin_lock_bh(&link->link_state_spin_lock); link->state = CAM_CRM_LINK_STATE_READY; spin_unlock_bh(&link->link_state_spin_lock); + if (control->init_timeout[i]) + link->skip_wd_validation = true; + init_timeout = (2 * control->init_timeout[i]); /* Start SOF watchdog timer */ rc = crm_timer_init(&link->watchdog, - CAM_REQ_MGR_WATCHDOG_TIMEOUT, link, - &__cam_req_mgr_sof_freeze); + (init_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT), + link, &__cam_req_mgr_sof_freeze); if (rc < 0) { CAM_ERR(CAM_CRM, "SOF timer start fails: link=0x%x", @@ -3960,6 +3973,7 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) /* Destroy SOF watchdog timer */ spin_lock_bh(&link->link_state_spin_lock); link->state = CAM_CRM_LINK_STATE_IDLE; + link->skip_wd_validation = false; crm_timer_exit(&link->watchdog); spin_unlock_bh(&link->link_state_spin_lock); } else { diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 1893eed379c5..74e3a2448110 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -349,6 +349,8 @@ struct cam_req_mgr_connected_device { * @dual_trigger : Links needs to wait for two triggers prior to * applying the settings * @trigger_cnt : trigger count value per device initiating the trigger + * @skip_wd_validation : skip initial frames crm_wd_timer validation in the + * case of long exposure use case */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -381,6 +383,7 @@ struct cam_req_mgr_core_link { uint64_t prev_sof_timestamp; bool dual_trigger; uint32_t trigger_cnt[CAM_REQ_MGR_MAX_TRIGGERS]; + bool skip_wd_validation; }; -- GitLab From 6b8ef71c55c60978eb34f5f97e825b86838b3425 Mon Sep 17 00:00:00 2001 From: taojiang Date: Mon, 25 May 2020 14:23:41 +0800 Subject: [PATCH 305/410] msm: camera: sensor: add ref count logic for camera sensor subdev some 3rd-part APP such as Gstreamer will cause sensor probe status not correct and therefor camera App failed to open camera. Add v4l2_subdev_intenal_ops open function for camera sensor for open counter,Do not call internal_ops->close() every time when call cam_req_mgr_close() so that open/close count for sensor sub_dev driver can match each other. CRs-Fixed: 2688114 Change-Id: I46318251e7ce1ed513bb57e0d72f95dfea22a77b Signed-off-by: taojiang --- drivers/cam_req_mgr/cam_req_mgr_dev.c | 14 ++++++-- .../cam_sensor/cam_sensor_core.c | 4 +-- .../cam_sensor/cam_sensor_dev.c | 36 +++++++++++++++++-- .../cam_sensor/cam_sensor_dev.h | 3 +- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 9f9ae3e4e327..2ce03eaa341e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -116,6 +116,7 @@ static int cam_req_mgr_open(struct file *filep) spin_unlock_bh(&g_dev.cam_eventq_lock); g_dev.open_cnt++; + CAM_DBG(CAM_CRM, " CRM open cnt %d", g_dev.open_cnt); rc = cam_mem_mgr_init(); if (rc) { g_dev.open_cnt--; @@ -157,13 +158,21 @@ static int cam_req_mgr_close(struct file *filep) CAM_WARN(CAM_CRM, "release invoked associated userspace process has died"); - mutex_lock(&g_dev.cam_lock); + mutex_lock(&g_dev.cam_lock); if (g_dev.open_cnt <= 0) { mutex_unlock(&g_dev.cam_lock); return -EINVAL; } + g_dev.open_cnt--; + CAM_DBG(CAM_CRM, "CRM open_cnt %d", g_dev.open_cnt); + + if (g_dev.open_cnt > 0) { + mutex_unlock(&g_dev.cam_lock); + return 0; + } + cam_req_mgr_handle_core_shutdown(); list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { @@ -176,7 +185,6 @@ static int cam_req_mgr_close(struct file *filep) } } - g_dev.open_cnt--; v4l2_fh_release(filep); spin_lock_bh(&g_dev.cam_eventq_lock); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 1362deba12d2..de74112bd3fb 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -817,8 +817,8 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, if ((s_ctrl->is_probe_succeed == 0) || (s_ctrl->sensor_state != CAM_SENSOR_INIT)) { CAM_WARN(CAM_SENSOR, - "Not in right state to aquire %d", - s_ctrl->sensor_state); + "Not in right state to aquire %d, probe %d", + s_ctrl->sensor_state, s_ctrl->is_probe_succeed); rc = -EINVAL; goto release_mutex; } diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index 765a1244a0aa..c1b661638d05 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_sensor_dev.h" @@ -27,6 +27,26 @@ static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, return rc; } +static int cam_sensor_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "s_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + s_ctrl->open_cnt++; + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + + CAM_DBG(CAM_SENSOR, "sensor Subdev open count %d", s_ctrl->open_cnt); + + return 0; +} + static int cam_sensor_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { @@ -39,7 +59,16 @@ static int cam_sensor_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&(s_ctrl->cam_sensor_mutex)); - cam_sensor_shutdown(s_ctrl); + if (s_ctrl->open_cnt <= 0) { + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return -EINVAL; + } + + s_ctrl->open_cnt--; + CAM_DBG(CAM_SENSOR, "sensor Subdev open count %d", s_ctrl->open_cnt); + + if (s_ctrl->open_cnt == 0) + cam_sensor_shutdown(s_ctrl); mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return 0; @@ -97,6 +126,7 @@ static struct v4l2_subdev_ops cam_sensor_subdev_ops = { }; static const struct v4l2_subdev_internal_ops cam_sensor_internal_ops = { + .open = cam_sensor_subdev_open, .close = cam_sensor_subdev_close, }; @@ -155,6 +185,7 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, s_ctrl->of_node = client->dev.of_node; s_ctrl->io_master_info.master_type = I2C_MASTER; s_ctrl->is_probe_succeed = 0; + s_ctrl->open_cnt = 0; s_ctrl->last_flush_req = 0; rc = cam_sensor_parse_dt(s_ctrl); @@ -283,6 +314,7 @@ static int32_t cam_sensor_driver_platform_probe( /* Initialize sensor device type */ s_ctrl->of_node = pdev->dev.of_node; s_ctrl->is_probe_succeed = 0; + s_ctrl->open_cnt = 0; s_ctrl->last_flush_req = 0; /*fill in platform device*/ diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h index b1963e15eb59..d9e8eaaeb129 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SENSOR_DEV_H_ @@ -111,6 +111,7 @@ struct cam_sensor_ctrl_t { bool bob_pwm_switch; uint32_t last_flush_req; uint16_t pipeline_delay; + int32_t open_cnt; }; #endif /* _CAM_SENSOR_DEV_H_ */ -- GitLab From adca65aa34f372d16a7a26fd505d28b180c83a57 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Fri, 10 Apr 2020 13:53:34 -0700 Subject: [PATCH 306/410] msm: camera: isp: Remove request ID in bubble sof notification This change removes valid request ID from sof notification when bubble is detected. The sof notification for this request will be sent after the state machine moves out of bubble applied state. This is to avoid duplication of timestamps in case of bubble due to IRQ delays. CRs-Fixed: 2671273 Change-Id: I5334fab41ae5bce8a42e421747b35f9bfd32aff3 Signed-off-by: Venkat Chinta --- drivers/cam_isp/cam_isp_context.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 7ec69545da82..b4161ec9849e 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1505,7 +1505,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); - if (req->request_id > ctx_isp->reported_req_id) { + if ((req->request_id > ctx_isp->reported_req_id) + && !req_isp->bubble_report) { request_id = req->request_id; ctx_isp->reported_req_id = request_id; } -- GitLab From b6637e3bbbcb11170882dcd21bbc0712ba5ac74f Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 13 May 2020 14:38:59 -0700 Subject: [PATCH 307/410] msm: camera: isp: Update last reported request ID correctly The last reported request ID indicates the request ID for which the shutter was sent last. Only update this field for requests that have not bubbled in a given IFE ctx. CRs-Fixed: 2680502 Change-Id: I9ee4b479fe95800efa40ea1ff8d840fc79ef6528 Signed-off-by: Karthik Anantha Ram --- drivers/cam_isp/cam_isp_context.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 7ec69545da82..890784e8a68a 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1280,7 +1280,9 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( } list_for_each_entry(req, &ctx->active_req_list, list) { - if (req->request_id > ctx_isp->reported_req_id) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if ((!req_isp->bubble_detected) && + (req->request_id > ctx_isp->reported_req_id)) { request_id = req->request_id; ctx_isp->reported_req_id = request_id; __cam_isp_ctx_update_event_record(ctx_isp, -- GitLab From cd2bb50f2a92e75d4c33394b93a89b722fb400a9 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Tue, 2 Jun 2020 15:44:48 +0530 Subject: [PATCH 308/410] msm: camera: reqmgr: Add null check for error notify function Null check is added for error notify function in request manager. CRs-Fixed: 2688303 Change-Id: I70237c51c8fa9f3e0af66c4e2d3c3eed5fe78bd9 Signed-off-by: Wyes Karny --- drivers/cam_req_mgr/cam_req_mgr_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 25cb710f73aa..afaeec8fb171 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -224,6 +224,12 @@ static int __cam_req_mgr_notify_error_on_link( struct cam_req_mgr_message msg; int rc = 0, pd; + if (!link || !dev) { + CAM_ERR(CAM_CRM, "Invalid Arguments link: 0x%x dev: 0x%x!", + link, dev); + return -EINVAL; + } + session = (struct cam_req_mgr_core_session *)link->parent; pd = dev->dev_info.p_delay; -- GitLab From 2ab21acbeed0e102d6ad46a7c2c25d4220ddf419 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Tue, 26 May 2020 04:20:39 +0530 Subject: [PATCH 309/410] msm: camera: csiphy: Add mipi flags to phy config -Add mipi flags mask to phy cmd buffer. -Enable skew calibration settings only if the corresponding flag is set. CRs-fixed: 2697576 Change-Id: I0353e57daf49ce15d7573b57dbaa9363dbc59635 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_core.c | 15 +++++++- .../cam_csiphy/cam_csiphy_dev.h | 6 ++-- .../include/cam_csiphy_1_2_2_hwreg.h | 6 ++-- .../include/cam_csiphy_1_2_3_hwreg.h | 36 +++++++++---------- include/uapi/media/cam_sensor.h | 7 ++-- 5 files changed, 44 insertions(+), 26 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 65e571f036f3..8d4bbd80852a 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -23,6 +23,8 @@ #define LANE_MASK_2PH 0x1F #define LANE_MASK_3PH 0x7 +#define SKEW_CAL_MASK 0x2 + static int csiphy_dump; module_param(csiphy_dump, int, 0644); @@ -242,7 +244,8 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, csiphy_dev->csiphy_info.data_rate = cam_cmd_csiphy_info->data_rate; } - + csiphy_dev->csiphy_info.mipi_flags = + cam_cmd_csiphy_info->mipi_flags; if (cam_cmd_csiphy_info->secure_mode == 1) cam_csiphy_update_secure_info(csiphy_dev, @@ -381,6 +384,7 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) uint8_t lane_cnt, lane_pos = 0; uint16_t settle_cnt = 0; uint64_t intermediate_var; + uint8_t skew_cal_enable = 0; void __iomem *csiphybase; struct csiphy_reg_t *csiphy_common_reg = NULL; struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE]; @@ -415,6 +419,9 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) } mask <<= 1; } + + skew_cal_enable = + csiphy_dev->csiphy_info.mipi_flags & SKEW_CAL_MASK; } else { if (csiphy_dev->csiphy_info.combo_mode == 1) { if (csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg) @@ -522,6 +529,12 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) csiphybase + reg_array[lane_pos][i].reg_addr); break; + case CSIPHY_SKEW_CAL: + if (skew_cal_enable) + cam_io_w_mb(reg_array[lane_pos][i].reg_data, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; default: CAM_DBG(CAM_CSIPHY, "Do Nothing"); break; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 78c7a848cd81..70b8cc9d8249 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_DEV_H_ @@ -53,6 +53,7 @@ #define CSIPHY_DNP_PARAMS 4 #define CSIPHY_2PH_REGS 5 #define CSIPHY_3PH_REGS 6 +#define CSIPHY_SKEW_CAL 7 #define CSIPHY_MAX_INSTANCES 2 @@ -219,7 +220,7 @@ struct csiphy_ctrl_t { * @data_rate : Data rate in mbps * @data_rate_combo_sensor: data rate of combo sensor * in the the same phy - * + * @mipi_flags : Mipi flags */ struct cam_csiphy_param { uint16_t lane_mask; @@ -232,6 +233,7 @@ struct cam_csiphy_param { uint64_t settle_time_combo_sensor; uint64_t data_rate; uint64_t data_rate_combo_sensor; + uint32_t mipi_flags; }; /** diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h index 119b6b575b60..637867398bab 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -49,7 +49,7 @@ csiphy_2ph_v1_2_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -89,7 +89,7 @@ csiphy_2ph_v1_2_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, @@ -109,7 +109,7 @@ csiphy_2ph_v1_2_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h index 01bc307bccff..067a6bc1fce1 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -73,8 +73,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0060, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, @@ -123,8 +123,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0260, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, @@ -148,8 +148,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0460, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, @@ -173,8 +173,8 @@ csiphy_reg_t csiphy_2ph_v1_2_3_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0660, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, @@ -201,8 +201,8 @@ struct csiphy_reg_t {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0060, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, @@ -228,8 +228,8 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x075C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0760, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x075C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0760, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { @@ -252,8 +252,8 @@ struct csiphy_reg_t {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_SKEW_CAL}, + {0x0800, 0x00, 0x00, CSIPHY_SKEW_CAL}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, @@ -277,8 +277,8 @@ struct csiphy_reg_t {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0460, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, @@ -303,8 +303,8 @@ struct csiphy_reg_t {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_SKEW_CAL}, + {0x0660, 0x0D, 0x00, CSIPHY_SKEW_CAL}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h index cc86f2706c63..33601fc1f0b4 100644 --- a/include/uapi/media/cam_sensor.h +++ b/include/uapi/media/cam_sensor.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_CAM_SENSOR_H__ @@ -334,7 +334,8 @@ struct cam_cmd_unconditional_wait { * @3phase : Details whether 3Phase / 2Phase operation * @settle_time : Settling time in ms * @data_rate : Data rate - * + * @mipi_flags : Mipi flags mask + * @reserved */ struct cam_csiphy_info { uint16_t lane_mask; @@ -345,6 +346,8 @@ struct cam_csiphy_info { uint8_t secure_mode; uint64_t settle_time; uint64_t data_rate; + uint32_t mipi_flags; + uint32_t reserved; } __attribute__((packed)); /** -- GitLab From d02846049dfce77fbdded5d70cf2f2d8c3905e39 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 27 Apr 2020 08:46:18 +0530 Subject: [PATCH 310/410] msm: camera: isp: Correct the bitmask for packet header Bitmask for printing the CSI short packet and CPHY packet is configured wrong. Change the bitmask to print the correct values. CRs-Fixed: 2672724 Change-Id: I716ea7f6e1dacc9669498d01550009a290374237 Signed-off-by: Gaurav Jindal --- .../cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index d80a8a08ed05..3a607dbf16b8 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -4714,7 +4714,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short pkt VC :%d DT:%d LC:%d", csid_hw->hw_intf->hw_idx, - (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csi2_reg->csid_csi2_rx_captured_short_pkt_1_addr); CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short packet ECC :%d", @@ -4731,7 +4731,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d cphy packet VC :%d DT:%d WC:%d", csid_hw->hw_intf->hw_idx, - (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); } /*read the IPP errors */ -- GitLab From f089179776b4dd029cc2ab5de3283ddea48638f1 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 31 Mar 2020 21:09:19 +0530 Subject: [PATCH 311/410] msm: camera: ife: IFE debug enhancement for overflow debugging In many error cases it is required to know the bandwidth applied on axi ports and camnoc axi clock rate values. Added cpas api to print the current axi bus votes, camnoc axi clock and ahb vote level.This api can be called for isp errors such as bus overflow, pxl overflow cases. On RDI overflow printing last applied IFE clock, dumping the CAMNOC fill-level registers to know the pending and queued transactions, SOF EPOCH and EOF timing to know exactly at what time the RDI overflow came, Width and height of specific Write master. CRs-Fixed: 2623885 Change-Id: Icaffe7dafddcf7e1dc8ad386f2acfe0d1a4f6c16 Signed-off-by: Tejas Prajapati --- drivers/cam_cpas/cam_cpas_hw.c | 75 +++++++++-- drivers/cam_cpas/cam_cpas_hw.h | 6 + drivers/cam_cpas/cam_cpas_hw_intf.h | 1 + drivers/cam_cpas/cam_cpas_intf.c | 24 ++++ drivers/cam_cpas/include/cam_cpas_api.h | 10 ++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 72 ++++++++++- .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 3 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 13 +- .../isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 9 ++ .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 9 ++ .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h | 11 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 43 +++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 95 +++++++------- .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c | 70 +++++++++++ .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 66 +++++++++- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 69 ++++++++++- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 68 +++++++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 116 +++++++++++++++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h | 9 ++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 28 ++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 17 +++ 23 files changed, 745 insertions(+), 73 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index fa840f944757..93986fceaed4 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -83,7 +83,7 @@ static int cam_cpas_util_vote_bus_client_level( static int cam_cpas_util_vote_bus_client_bw( struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, - bool camnoc_bw) + bool camnoc_bw, uint64_t *applied_ab, uint64_t *applied_ib) { struct msm_bus_paths *path; struct msm_bus_scale_pdata *pdata; @@ -146,6 +146,10 @@ static int cam_cpas_util_vote_bus_client_bw( CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", bus_client->client_id, bus_client->name, ab, ib, idx); msm_bus_scale_client_update_request(bus_client->client_id, idx); + if (applied_ab) + *applied_ab = ab; + if (applied_ib) + *applied_ib = ib; return 0; } @@ -221,7 +225,8 @@ static int cam_cpas_util_unregister_bus_client( return -EINVAL; if (bus_client->dyn_vote) - cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); + cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false, + NULL, NULL); else cam_cpas_util_vote_bus_client_level(bus_client, 0); @@ -309,6 +314,7 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, int rc, i = 0; struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; uint64_t ab_bw, ib_bw; + uint64_t applied_ab_bw = 0, applied_ib_bw = 0; rc = cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, (enable == true) ? CAM_SVS_VOTE : CAM_SUSPEND_VOTE); @@ -329,13 +335,15 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, for (i = 0; i < cpas_core->num_axi_ports; i++) { rc = cam_cpas_util_vote_bus_client_bw( &cpas_core->axi_port[i].bus_client, - ab_bw, ib_bw, false); + ab_bw, ib_bw, false, &applied_ab_bw, &applied_ib_bw); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, rc=%d", enable, rc); goto remove_ahb_vote; } + cpas_core->axi_port[i].applied_ab_bw = applied_ab_bw; + cpas_core->axi_port[i].applied_ib_bw = applied_ib_bw; } return 0; @@ -501,6 +509,8 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %lld %d", required_camnoc_bw, clk_rate, rc); + + cpas_core->applied_camnoc_axi_rate = clk_rate; } } @@ -689,6 +699,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( int rc = 0; struct cam_cpas_axi_port *camnoc_axi_port = NULL; uint64_t camnoc_bw; + uint64_t applied_ab = 0, applied_ib = 0; if (soc_private->control_camnoc_axi_clk) { rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); @@ -729,7 +740,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( rc = cam_cpas_util_vote_bus_client_bw( &camnoc_axi_port->bus_client, - 0, camnoc_bw, true); + 0, camnoc_bw, true, &applied_ab, &applied_ib); CAM_DBG(CAM_CPAS, "camnoc vote camnoc_bw[%llu] rc=%d %s", @@ -740,6 +751,8 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( camnoc_bw, rc); break; } + camnoc_axi_port->applied_ab_bw = applied_ab; + camnoc_axi_port->applied_ib_bw = applied_ib; } return rc; } @@ -762,6 +775,7 @@ static int cam_cpas_util_apply_client_axi_vote( curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; int rc = 0, i = 0; + uint64_t applied_ab = 0, applied_ib = 0; mutex_lock(&cpas_core->tree_lock); if (!cpas_client->tree_node_valid) { @@ -937,13 +951,16 @@ static int cam_cpas_util_apply_client_axi_vote( rc = cam_cpas_util_vote_bus_client_bw( &mnoc_axi_port->bus_client, - mnoc_ab_bw, mnoc_ib_bw, false); + mnoc_ab_bw, mnoc_ib_bw, false, &applied_ab, + &applied_ib); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", mnoc_ab_bw, mnoc_ib_bw, rc); goto unlock_tree; } + mnoc_axi_port->applied_ab_bw = applied_ab; + mnoc_axi_port->applied_ib_bw = applied_ib; } rc = cam_cpas_camnoc_set_vote_axi_clk_rate( cpas_hw, camnoc_axi_port_updated); @@ -981,7 +998,7 @@ static int cam_cpas_util_apply_default_axi_vote( axi_port->axi_port_name, mnoc_ab_bw, mnoc_ib_bw); rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, - mnoc_ab_bw, mnoc_ib_bw, false); + mnoc_ab_bw, mnoc_ib_bw, false, NULL, NULL); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", @@ -1006,7 +1023,7 @@ static int cam_cpas_util_apply_default_axi_vote( axi_port->axi_port_name, camnoc_ab_bw, camnoc_ib_bw); rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, - camnoc_ab_bw, camnoc_ib_bw, false); + camnoc_ab_bw, camnoc_ib_bw, false, NULL, NULL); if (rc) { CAM_ERR(CAM_CPAS, "Failed in camnoc vote ab[%llu] ib[%llu] rc=%d", @@ -1763,6 +1780,46 @@ static int cam_cpas_hw_get_hw_info(void *hw_priv, return 0; } +static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + int rc = 0; + uint32_t i; + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + CAM_INFO(CAM_CPAS, + "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", + cpas_core->axi_port[i].axi_port_name, + cpas_core->axi_port[i].ab_bw, + cpas_core->axi_port[i].ib_bw, + cpas_core->axi_port[i].additional_bw, + cpas_core->axi_port[i].applied_ab_bw, + cpas_core->axi_port[i].applied_ib_bw); + } + + if (soc_private->control_camnoc_axi_clk) { + CAM_INFO(CAM_CPAS, "applied camnoc axi clk[%lld]", + cpas_core->applied_camnoc_axi_rate); + } else { + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + CAM_INFO(CAM_CPAS, + "[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]", + cpas_core->camnoc_axi_port[i].axi_port_name, + cpas_core->camnoc_axi_port[i].ab_bw, + cpas_core->camnoc_axi_port[i].ib_bw, + cpas_core->camnoc_axi_port[i].additional_bw, + cpas_core->camnoc_axi_port[i].applied_ab_bw, + cpas_core->camnoc_axi_port[i].applied_ib_bw); + } + } + + CAM_INFO(CAM_CPAS, "ahb client curr vote level[%d]", + cpas_core->ahb_bus_client.curr_vote_level); + + return rc; +} static int cam_cpas_hw_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -1866,6 +1923,10 @@ static int cam_cpas_hw_process_cmd(void *hw_priv, cmd_axi_vote->client_handle, cmd_axi_vote->axi_vote); break; } + case CAM_CPAS_HW_CMD_LOG_VOTE: { + rc = cam_cpas_log_vote(hw_priv); + break; + } default: CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type); break; diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index cfa7dfbb69b2..acad4ba44b17 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -155,6 +155,8 @@ struct cam_cpas_bus_client { * @ib_bw: IB bw value for this port * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients + * @applied_ab_bw: applied ab bw for this port + * @applied_ib_bw: applied ib bw for this port */ struct cam_cpas_axi_port { const char *axi_port_name; @@ -165,6 +167,8 @@ struct cam_cpas_axi_port { uint64_t ib_bw; uint64_t camnoc_bw; uint64_t additional_bw; + uint64_t applied_ab_bw; + uint64_t applied_ib_bw; }; /** @@ -189,6 +193,7 @@ struct cam_cpas_axi_port { * @irq_count_wq: wait variable to ensure all irq's are handled * @dentry: debugfs file entry * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus + * @applied_camnoc_axi_rate: applied camnoc axi clock rate */ struct cam_cpas { struct cam_cpas_hw_caps hw_caps; @@ -210,6 +215,7 @@ struct cam_cpas { wait_queue_head_t irq_count_wq; struct dentry *dentry; bool ahb_bus_scaling_disable; + uint64_t applied_camnoc_axi_rate; }; int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); diff --git a/drivers/cam_cpas/cam_cpas_hw_intf.h b/drivers/cam_cpas/cam_cpas_hw_intf.h index 580242308346..3f644363062c 100644 --- a/drivers/cam_cpas/cam_cpas_hw_intf.h +++ b/drivers/cam_cpas/cam_cpas_hw_intf.h @@ -38,6 +38,7 @@ enum cam_cpas_hw_cmd_process { CAM_CPAS_HW_CMD_REG_READ, CAM_CPAS_HW_CMD_AHB_VOTE, CAM_CPAS_HW_CMD_AXI_VOTE, + CAM_CPAS_HW_CMD_LOG_VOTE, CAM_CPAS_HW_CMD_INVALID, }; diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index 402710d81741..d63ac2263355 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -392,6 +392,30 @@ int cam_cpas_start(uint32_t client_handle, } EXPORT_SYMBOL(cam_cpas_start); +void cam_cpas_log_votes(void) +{ + uint32_t dummy_args; + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args, + sizeof(dummy_args)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + } + +} +EXPORT_SYMBOL(cam_cpas_log_votes); + int cam_cpas_unregister_client(uint32_t client_handle) { int rc; diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 67a2a50b5816..d36800bd13b8 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -624,5 +624,15 @@ const char *cam_cpas_axi_util_path_type_to_string( const char *cam_cpas_axi_util_trans_type_to_string( uint32_t path_data_type); +/** + * cam_cpas_log_votes() + * + * @brief: API to print the all bw votes of axi client. It also print the + * applied camnoc axi clock vote value and ahb vote value + * + * @return 0 on success. + * + */ +void cam_cpas_log_votes(void); #endif /* _CAM_CPAS_API_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index aae46c84d811..6fcdd3d0b47c 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -7004,11 +7004,67 @@ static int cam_ife_hw_mgr_handle_csid_event( return 0; } +static int cam_ife_hw_mgr_handle_hw_dump_info( + void *ctx, + void *evt_info) +{ + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = + (struct cam_ife_hw_mgr_ctx *)ctx; + struct cam_isp_hw_event_info *event_info = + (struct cam_isp_hw_event_info *)evt_info; + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_hw_intf *hw_intf; + uint32_t i, out_port_id; + int rc = 0; + + list_for_each_entry(hw_mgr_res, + &ife_hw_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF) { + hw_intf = rsrc_node->hw_intf; + if (hw_intf && + hw_intf->hw_ops.process_cmd) + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CAMIF_DATA, + rsrc_node, + sizeof(struct cam_isp_resource_node)); + } + } + } + + out_port_id = event_info->res_id & 0xFF; + hw_mgr_res = + &ife_hw_mgr_ctx->res_list_ife_out[out_port_id]; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_BUS_INFO, + (void *)event_info, + sizeof(struct cam_isp_hw_event_info)); + } + } + + return rc; +} + static int cam_ife_hw_mgr_handle_hw_err( + void *ctx, void *evt_info) { + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx; struct cam_isp_hw_event_info *event_info = evt_info; - uint32_t core_idx; + uint32_t core_idx; struct cam_isp_hw_error_event_data error_event_data = {0}; struct cam_hw_event_recovery_data recovery_data = {0}; int rc = -EINVAL; @@ -7027,6 +7083,18 @@ static int cam_ife_hw_mgr_handle_hw_err( return rc; } + if (ctx) { + ife_hw_mgr_ctx = + (struct cam_ife_hw_mgr_ctx *)ctx; + if (event_info->res_type == + CAM_ISP_RESOURCE_VFE_IN && + !ife_hw_mgr_ctx->is_rdi_only_context && + event_info->res_id != + CAM_ISP_HW_VFE_IN_CAMIF) + cam_ife_hw_mgr_handle_hw_dump_info( + ife_hw_mgr_ctx, event_info); + } + core_idx = event_info->hw_idx; if (g_ife_hw_mgr.debug_cfg.enable_recovery) @@ -7421,7 +7489,7 @@ static int cam_ife_hw_mgr_event_handler( break; case CAM_ISP_HW_EVENT_ERROR: - rc = cam_ife_hw_mgr_handle_hw_err(evt_info); + rc = cam_ife_hw_mgr_handle_hw_err(priv, evt_info); break; default: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 093b4f9a1114..7198f3a2f2ef 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -94,8 +94,10 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, CAM_ISP_HW_CMD_UBWC_UPDATE, + CAM_ISP_HW_CMD_DUMP_BUS_INFO, CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, + CAM_ISP_HW_CMD_CAMIF_DATA, CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 5f861f954228..faf36dfb80d0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -595,6 +595,8 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_BW_UPDATE_V2: case CAM_ISP_HW_CMD_DUMP_HW: case CAM_ISP_HW_CMD_QUERY: + case CAM_ISP_HW_CMD_QUERY_DSP_MODE: + case CAM_ISP_HW_CMD_CAMIF_DATA: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); @@ -606,6 +608,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_UBWC_UPDATE: case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + case CAM_ISP_HW_CMD_DUMP_BUS_INFO: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h index 3081274faed2..34ae02bce011 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -25,6 +25,7 @@ * @ubwc_static_ctrl: UBWC static control configuration * @is_ife_lite: Flag to indicate full vs lite IFE * @dsp_disabled: Flag to indicate DSP is not supported for VFE + * @ife_clk_src: IFE source clock */ struct cam_vfe_soc_private { uint32_t cpas_handle; @@ -35,6 +36,7 @@ struct cam_vfe_soc_private { uint32_t ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX]; bool is_ife_lite; bool dsp_disabled; + uint64_t ife_clk_src; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 63df625221cc..a65d7aa966fd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -170,6 +170,14 @@ struct cam_vfe_top_dump_data vfe170_dump_data = { }, }; +static struct cam_vfe_rdi_overflow_status vfe170_rdi_irq_status = { + .rdi0_overflow_mask = 0x8, + .rdi1_overflow_mask = 0x10, + .rdi2_overflow_mask = 0x18, + .rdi3_overflow_mask = 0x20, + .rdi_overflow_mask = 0x3c, +}; + static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .common_reg = &vfe170_top_common_reg, .camif_hw_info = { @@ -183,8 +191,9 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { .reg_data = NULL, }, .rdi_hw_info = { - .common_reg = &vfe170_top_common_reg, - .rdi_reg = &vfe170_rdi_reg, + .common_reg = &vfe170_top_common_reg, + .rdi_reg = &vfe170_rdi_reg, + .rdi_irq_status = &vfe170_rdi_irq_status, .reg_data = { &vfe_170_rdi_0_data, &vfe_170_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h index fab29ff17eab..84b17694e60e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -25,6 +25,14 @@ static struct cam_irq_register_set vfe170_150_top_irq_reg_set[2] = { }, }; +static struct cam_vfe_rdi_overflow_status vfe170_150_rdi_irq_status = { + .rdi0_overflow_mask = 0x8, + .rdi1_overflow_mask = 0x10, + .rdi2_overflow_mask = 0x18, + .rdi3_overflow_mask = 0x20, + .rdi_overflow_mask = 0x3c, +}; + static struct cam_irq_controller_reg_info vfe170_150_top_irq_reg_info = { .num_registers = 2, .irq_reg_set = vfe170_150_top_irq_reg_set, @@ -360,6 +368,7 @@ static struct cam_vfe_top_ver2_hw_info vfe170_150_top_hw_info = { .common_reg = &vfe170_150_top_common_reg, .rdi_reg = &vfe170_150_rdi_reg, .common_reg_data = &vfe170_150_rdi_reg_data, + .rdi_irq_status = &vfe170_150_rdi_irq_status, .reg_data = { &vfe_170_150_rdi_0_data, &vfe_170_150_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 9512ad06c65e..b26592912c93 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -27,6 +27,14 @@ static struct cam_irq_register_set vfe175_130_top_irq_reg_set[2] = { }, }; +static struct cam_vfe_rdi_overflow_status vfe175_130_rdi_irq_status = { + .rdi0_overflow_mask = 0x8, + .rdi1_overflow_mask = 0x10, + .rdi2_overflow_mask = 0x18, + .rdi3_overflow_mask = 0x20, + .rdi_overflow_mask = 0x3c, +}; + static struct cam_irq_controller_reg_info vfe175_130_top_irq_reg_info = { .num_registers = 2, .irq_reg_set = vfe175_130_top_irq_reg_set, @@ -441,6 +449,7 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { .common_reg = &vfe175_130_top_common_reg, .rdi_reg = &vfe175_130_rdi_reg, .common_reg_data = &vfe175_130_rdi_reg_data, + .rdi_irq_status = &vfe175_130_rdi_irq_status, .reg_data = { &vfe_175_130_rdi_0_data, &vfe_175_130_rdi_1_data, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h index aab38c791637..7ea461b21dbd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_LITE17X_H_ @@ -87,6 +87,14 @@ static struct cam_vfe_rdi_reg_data vfe17x_rdi_3_data = { .reg_update_irq_mask = 0x100, }; +static struct cam_vfe_rdi_overflow_status vfe17x_rdi_irq_status = { + .rdi0_overflow_mask = 0x8, + .rdi1_overflow_mask = 0x10, + .rdi2_overflow_mask = 0x18, + .rdi3_overflow_mask = 0x20, + .rdi_overflow_mask = 0x3c, +}; + static struct cam_vfe_top_ver2_hw_info vfe17x_top_hw_info = { .common_reg = &vfe17x_top_common_reg, .camif_hw_info = { @@ -104,6 +112,7 @@ static struct cam_vfe_top_ver2_hw_info vfe17x_top_hw_info = { &vfe17x_rdi_2_data, &vfe17x_rdi_3_data, }, + .rdi_irq_status = &vfe17x_rdi_irq_status, }, .num_mux = 4, .mux_type = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 0b6569027b7e..fa12389f9dd9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -143,6 +143,8 @@ struct cam_vfe_bus_ver2_wm_resource_data { uint32_t ubwc_lossy_threshold_0; uint32_t ubwc_lossy_threshold_1; uint32_t ubwc_bandwidth_limit; + uint32_t acquired_width; + uint32_t acquired_height; }; struct cam_vfe_bus_ver2_comp_grp_data { @@ -986,6 +988,8 @@ static int cam_vfe_bus_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; + rsrc_data->acquired_width = out_port_info->width; + rsrc_data->acquired_height = out_port_info->height; rsrc_data->is_dual = is_dual; /* Set WM offset value to default */ rsrc_data->offset = 0; @@ -3741,6 +3745,42 @@ static int __cam_vfe_bus_process_cmd(void *priv, return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); } +int cam_vfe_bus_dump_wm_data(void *priv, void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv = + (struct cam_vfe_bus_ver2_priv *) priv; + struct cam_isp_hw_event_info *event_info = + (struct cam_isp_hw_event_info *)cmd_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + int i, wm_idx; + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id; + + vfe_out_res_id = cam_vfe_bus_get_out_res_id(event_info->res_id); + rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; + rsrc_data = rsrc_node->res_priv; + for (i = 0; i < rsrc_data->num_wm; i++) { + wm_idx = cam_vfe_bus_get_wm_idx(vfe_out_res_id, i); + if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d", + vfe_out_res_id); + return -EINVAL; + } + wm_data = bus_priv->bus_client[wm_idx].res_priv; + CAM_INFO(CAM_ISP, + "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", + wm_data->common_data->core_index, wm_idx, + wm_data->width, + wm_data->height, + wm_data->stride, wm_data->h_init, + wm_data->en_cfg, + wm_data->acquired_width, + wm_data->acquired_height); + } + return 0; +} + static int cam_vfe_bus_process_cmd( struct cam_isp_resource_node *priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -3779,6 +3819,9 @@ static int cam_vfe_bus_process_cmd( case CAM_ISP_HW_CMD_UBWC_UPDATE: rc = cam_vfe_bus_update_ubwc_config(cmd_args); break; + case CAM_ISP_HW_CMD_DUMP_BUS_INFO: + rc = cam_vfe_bus_dump_wm_data(priv, cmd_args, arg_size); + break; case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: rc = cam_vfe_bus_update_ubwc_config_v2(cmd_args); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 017ad12e9dd7..1b108e51e5a1 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -128,6 +128,8 @@ struct cam_vfe_bus_ver3_wm_resource_data { uint32_t ubwc_lossy_threshold_1; uint32_t ubwc_offset_lossy_variance; uint32_t ubwc_bandwidth_limit; + uint32_t acquired_width; + uint32_t acquired_height; }; struct cam_vfe_bus_ver3_comp_grp_data { @@ -1130,6 +1132,8 @@ static int cam_vfe_bus_ver3_acquire_wm( rsrc_data->width = out_port_info->width; rsrc_data->height = out_port_info->height; + rsrc_data->acquired_width = out_port_info->width; + rsrc_data->acquired_height = out_port_info->height; rsrc_data->is_dual = is_dual; /* Set WM offset value to default */ rsrc_data->offset = 0; @@ -2444,34 +2448,37 @@ static int cam_vfe_bus_ver3_deinit_vfe_out_resource( return 0; } -static void cam_vfe_bus_ver3_print_dimensions( +static int cam_vfe_bus_ver3_print_dimensions( enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, - enum cam_vfe_bus_plane_type plane, struct cam_vfe_bus_ver3_priv *bus_priv) { - struct cam_isp_resource_node *wm_res = NULL; - struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; - int wm_idx = 0; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + int i, wm_idx; - wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, plane, - bus_priv->common_data.is_lite); - - if (wm_idx < 0 || wm_idx >= bus_priv->num_client || plane > PLANE_C) { - CAM_ERR(CAM_ISP, - "Unsupported VFE out_type:0x%X plane:%d wm_idx:%d max_idx:%d", - vfe_out_res_id, plane, wm_idx, - bus_priv->num_client - 1); - return; + rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; + rsrc_data = rsrc_node->res_priv; + for (i = 0; i < rsrc_data->num_wm; i++) { + wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, i, + bus_priv->common_data.is_lite); + if (wm_idx < 0 || wm_idx >= bus_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d", + vfe_out_res_id); + return -EINVAL; + } + wm_data = bus_priv->bus_client[wm_idx].res_priv; + CAM_INFO(CAM_ISP, + "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", + wm_data->common_data->core_index, wm_idx, + wm_data->width, + wm_data->height, + wm_data->stride, wm_data->h_init, + wm_data->en_cfg, + wm_data->acquired_width, + wm_data->acquired_height); } - - wm_res = &bus_priv->bus_client[wm_idx]; - wm_data = wm_res->res_priv; - - CAM_INFO(CAM_ISP, - "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u", - wm_data->common_data->core_index, wm_idx, wm_data->width, - wm_data->height, wm_data->stride, wm_data->h_init, - wm_data->en_cfg); + return 0; } static int cam_vfe_bus_ver3_handle_bus_irq(uint32_t evt_id, @@ -2577,7 +2584,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 0 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI0, - PLANE_Y, bus_priv); } @@ -2586,7 +2592,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI1, - PLANE_Y, bus_priv); } @@ -2595,7 +2600,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 2 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI2, - PLANE_Y, bus_priv); } @@ -2604,7 +2608,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "RDI 3 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI3, - PLANE_Y, bus_priv); } } @@ -2639,7 +2642,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID Y 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL, - PLANE_Y, bus_priv); } @@ -2647,7 +2649,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID C 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL, - PLANE_C, bus_priv); } @@ -2655,7 +2656,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID YC 4:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS4, - PLANE_Y, bus_priv); } @@ -2663,7 +2663,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "VID YC 16:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS16, - PLANE_Y, bus_priv); } @@ -2671,7 +2670,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP Y 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, - PLANE_Y, bus_priv); } @@ -2679,7 +2677,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP C 1:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, - PLANE_C, bus_priv); } @@ -2687,7 +2684,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP YC 4:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, - PLANE_Y, bus_priv); } @@ -2695,7 +2691,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "DISP YC 16:1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, - PLANE_Y, bus_priv); } @@ -2703,7 +2698,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "FD Y image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FD, - PLANE_Y, bus_priv); } @@ -2711,7 +2705,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "FD C image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_FD, - PLANE_C, bus_priv); } @@ -2720,7 +2713,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "PIXEL RAW DUMP image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, - PLANE_Y, bus_priv); } @@ -2728,7 +2720,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS HDR BE image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, - PLANE_Y, bus_priv); } @@ -2737,7 +2728,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "STATS HDR BHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, - PLANE_Y, bus_priv); } @@ -2746,7 +2736,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( "STATS TINTLESS BG image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, - PLANE_Y, bus_priv); } @@ -2754,7 +2743,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS AWB BG image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, - PLANE_Y, bus_priv); } @@ -2762,7 +2750,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS BHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, - PLANE_Y, bus_priv); } @@ -2770,7 +2757,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS RS image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, - PLANE_Y, bus_priv); } @@ -2778,7 +2764,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS CS image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, - PLANE_Y, bus_priv); } @@ -2786,7 +2771,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS IHIST image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, - PLANE_Y, bus_priv); } @@ -2794,7 +2778,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "STATS BAF image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, - PLANE_Y, bus_priv); } @@ -2802,7 +2785,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "PD image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_2PD, - PLANE_Y, bus_priv); } @@ -2810,7 +2792,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "LCR image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_LCR, - PLANE_Y, bus_priv); } @@ -2818,7 +2799,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 0 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI0, - PLANE_Y, bus_priv); } @@ -2826,7 +2806,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 1 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI1, - PLANE_Y, bus_priv); } @@ -2834,7 +2813,6 @@ static int cam_vfe_bus_ver3_err_irq_bottom_half( CAM_INFO(CAM_ISP, "RDI 2 image size violation"); cam_vfe_bus_ver3_print_dimensions( CAM_VFE_BUS_VER3_VFE_OUT_RDI2, - PLANE_Y, bus_priv); } @@ -3740,6 +3718,19 @@ static int cam_vfe_bus_ver3_process_cmd( bus_priv->error_irq_handle = 0; } break; + case CAM_ISP_HW_CMD_DUMP_BUS_INFO: { + struct cam_isp_hw_event_info *event_info; + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id; + + event_info = + (struct cam_isp_hw_event_info *)cmd_args; + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + vfe_out_res_id = + cam_vfe_bus_ver3_get_out_res_id(event_info->res_id); + rc = cam_vfe_bus_ver3_print_dimensions( + vfe_out_res_id, bus_priv); + break; + } case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: rc = cam_vfe_bus_ver3_update_ubwc_config_v2(cmd_args); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c index c7380f805938..e4ff7255df5b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -36,6 +36,7 @@ struct cam_vfe_mux_camif_lite_data { evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; struct list_head free_payload_list; spinlock_t spin_lock; + struct timeval error_ts; }; static int cam_vfe_camif_lite_get_evt_payload( @@ -133,6 +134,12 @@ static int cam_vfe_camif_lite_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_lite_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_lite_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -301,6 +308,9 @@ static int cam_vfe_camif_lite_resource_start( } } + rsrc_data->error_ts.tv_sec = 0; + rsrc_data->error_ts.tv_usec = 0; + CAM_DBG(CAM_ISP, "Start Camif Lite IFE %d Done", camif_lite_res->hw_intf->hw_idx); return rc; @@ -405,6 +415,44 @@ static int cam_vfe_camif_lite_handle_irq_top_half(uint32_t evt_id, return rc; } +static int cam_vfe_camif_lite_cpas_fifo_levels_reg_dump( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv) +{ + struct cam_vfe_soc_private *soc_private = + camif_lite_priv->soc_info->soc_private; + uint32_t val; + + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || + soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_INFO(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + + } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } + + return 0; + +} + static int cam_vfe_camif_lite_handle_irq_bottom_half( void *handler_priv, void *evt_payload_priv) @@ -416,6 +464,9 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( struct cam_isp_hw_event_info evt_info; uint32_t irq_status0; uint32_t irq_status1; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -427,6 +478,9 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( payload = evt_payload_priv; irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + soc_info = camif_lite_priv->soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; evt_info.hw_idx = camif_lite_node->hw_intf->hw_idx; evt_info.res_id = camif_lite_node->res_id; @@ -464,11 +518,27 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE Received ERROR", evt_info.hw_idx); + cam_vfe_camif_lite_cpas_fifo_levels_reg_dump(camif_lite_priv); + + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + CAM_INFO(CAM_ISP, + "ERROR time %lld:%lld", + camif_lite_priv->error_ts.tv_sec, + camif_lite_priv->error_ts.tv_usec); + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + cam_cpas_log_votes(); + } cam_vfe_camif_lite_put_evt_payload(camif_lite_priv, &payload); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index 1617e84a0ebc..b54c43a145bc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -40,6 +40,10 @@ struct cam_vfe_mux_camif_lite_data { uint32_t camif_debug; struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; + struct timeval sof_ts; + struct timeval epoch_ts; + struct timeval eof_ts; + struct timeval error_ts; }; static int cam_vfe_camif_lite_get_evt_payload( @@ -137,6 +141,12 @@ static int cam_vfe_camif_lite_err_irq_top_half( return rc; cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_lite_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_lite_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -293,6 +303,15 @@ static int cam_vfe_camif_lite_resource_start( rsrc_data->mem_base + rsrc_data->camif_lite_reg->lite_epoch_irq); + rsrc_data->error_ts.tv_sec = 0; + rsrc_data->error_ts.tv_usec = 0; + rsrc_data->sof_ts.tv_sec = 0; + rsrc_data->sof_ts.tv_usec = 0; + rsrc_data->epoch_ts.tv_sec = 0; + rsrc_data->epoch_ts.tv_usec = 0; + rsrc_data->eof_ts.tv_sec = 0; + rsrc_data->eof_ts.tv_usec = 0; + skip_core_cfg: camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; @@ -888,6 +907,7 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); + cam_cpas_log_votes(); } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { @@ -1062,6 +1082,8 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( struct cam_vfe_soc_private *soc_private = NULL; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; int i = 0; + uint32_t status_0 = 0; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -1097,6 +1119,10 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received SOF", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; + camif_lite_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_lite_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, @@ -1108,6 +1134,10 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EPOCH", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; + camif_lite_priv->epoch_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_lite_priv->epoch_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, @@ -1119,18 +1149,50 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EOF", evt_info.hw_idx, evt_info.res_id); ret = CAM_VFE_IRQ_STATUS_SUCCESS; + camif_lite_priv->eof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_lite_priv->eof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); } - if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] - & camif_lite_priv->reg_data->error_irq_mask0) { + status_0 = irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_lite_priv->reg_data->error_irq_mask0; + if (status_0) { CAM_ERR(CAM_ISP, "VFE:%d Overflow", camif_lite_node->hw_intf->hw_idx); evt_info.err_type = CAM_VFE_IRQ_STATUS_OVERFLOW; + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + CAM_INFO(CAM_ISP, + "ERROR time %lld:%lld", + camif_lite_priv->error_ts.tv_sec, + camif_lite_priv->error_ts.tv_usec); + + if (camif_lite_node->rdi_only_ctx) + CAM_INFO(CAM_ISP, + "SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_lite_priv->sof_ts.tv_sec, + camif_lite_priv->sof_ts.tv_usec, + camif_lite_priv->epoch_ts.tv_sec, + camif_lite_priv->epoch_ts.tv_usec, + camif_lite_priv->eof_ts.tv_sec, + camif_lite_priv->eof_ts.tv_usec); + + if (status_0 & 0x8000000) + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_2; + + if (status_0 & 0x10000000) + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (status_0 & 0x20000000) + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_0; if (camif_lite_priv->event_cb) camif_lite_priv->event_cb(camif_lite_priv->priv, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 86e0716d7b05..f39cc4d470bb 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -50,6 +50,10 @@ struct cam_vfe_mux_camif_data { uint32_t camif_debug; uint32_t dual_hw_idx; uint32_t is_dual; + struct timeval sof_ts; + struct timeval epoch_ts; + struct timeval eof_ts; + struct timeval error_ts; }; static int cam_vfe_camif_get_evt_payload( @@ -144,6 +148,12 @@ static int cam_vfe_camif_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -293,6 +303,14 @@ static int cam_vfe_camif_resource_init( if (rc) CAM_ERR(CAM_ISP, "failed to enable dsp clk"); } + camif_data->sof_ts.tv_sec = 0; + camif_data->sof_ts.tv_usec = 0; + camif_data->epoch_ts.tv_sec = 0; + camif_data->epoch_ts.tv_usec = 0; + camif_data->eof_ts.tv_sec = 0; + camif_data->eof_ts.tv_usec = 0; + camif_data->error_ts.tv_sec = 0; + camif_data->error_ts.tv_usec = 0; return rc; } @@ -625,6 +643,26 @@ static int cam_vfe_camif_sof_irq_debug( return 0; } +int cam_vfe_camif_dump_timestamps( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_data *camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + + CAM_INFO(CAM_ISP, + "CAMIF ERROR time %lld:%lld SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->error_ts.tv_sec, + camif_priv->error_ts.tv_usec, + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); + + return 0; +} + static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -649,6 +687,9 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; camif_priv->camif_debug = *((uint32_t *)cmd_args); break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_camif_dump_timestamps(rsrc_node, cmd_args); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -704,6 +745,7 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, uint32_t irq_status0; uint32_t irq_status1; uint32_t val; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -725,6 +767,10 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { CAM_DBG(CAM_ISP, "Received EOF"); + camif_priv->eof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->eof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -746,8 +792,13 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, false; camif_priv->irq_debug_cnt = 0; } - } else + } else { CAM_DBG(CAM_ISP, "Received SOF"); + camif_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; + } if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -768,6 +819,10 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "Received EPOCH"); + camif_priv->epoch_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->epoch_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -779,6 +834,11 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & camif_priv->reg_data->error_irq_mask0) { CAM_DBG(CAM_ISP, "Received ERROR"); + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); @@ -794,12 +854,15 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { CAM_DBG(CAM_ISP, "Received ERROR"); + ktime_get_boottime_ts64(&ts); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); - CAM_INFO(CAM_ISP, "Violation status = %x", - payload->irq_reg_val[2]); + CAM_INFO(CAM_ISP, + "curr mono time sec %lld.%lld Violation status = %x", + ts.tv_sec, ts.tv_nsec/1000, payload->irq_reg_val[2]); ret = CAM_VFE_IRQ_STATUS_OVERFLOW; if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index fd7aaaf27cde..de4299a47034 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -55,6 +55,10 @@ struct cam_vfe_mux_camif_ver3_data { uint32_t qcfa_bin; bool is_fe_enabled; bool is_offline; + struct timeval sof_ts; + struct timeval epoch_ts; + struct timeval eof_ts; + struct timeval error_ts; }; static int cam_vfe_camif_ver3_get_evt_payload( @@ -140,6 +144,12 @@ static int cam_vfe_camif_ver3_err_irq_top_half( return rc; cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + camif_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + camif_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -296,6 +306,14 @@ static int cam_vfe_camif_ver3_resource_init( CAM_ERR(CAM_ISP, "failed to enable dsp clk, rc = %d", rc); } + camif_data->sof_ts.tv_sec = 0; + camif_data->sof_ts.tv_usec = 0; + camif_data->epoch_ts.tv_sec = 0; + camif_data->epoch_ts.tv_usec = 0; + camif_data->eof_ts.tv_sec = 0; + camif_data->eof_ts.tv_usec = 0; + camif_data->error_ts.tv_sec = 0; + camif_data->error_ts.tv_usec = 0; return rc; } @@ -746,6 +764,26 @@ static int cam_vfe_camif_ver3_sof_irq_debug( return 0; } +int cam_vfe_camif_ver3_dump_timestamps( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv = + (struct cam_vfe_mux_camif_ver3_data *)rsrc_node->res_priv; + + CAM_INFO(CAM_ISP, + "CAMIF ERROR time %lld:%lld SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->error_ts.tv_sec, + camif_priv->error_ts.tv_usec, + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); + + return 0; +} + static int cam_vfe_camif_ver3_process_cmd( struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -782,6 +820,9 @@ static int cam_vfe_camif_ver3_process_cmd( *((struct cam_hw_soc_info **)cmd_args) = camif_priv->soc_info; rc = 0; break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_camif_ver3_dump_timestamps(rsrc_node, cmd_args); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -943,6 +984,7 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", val0, val1, val2); + cam_cpas_log_votes(); return; } @@ -1254,6 +1296,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; + struct timespec64 ts; uint32_t val = 0; int i = 0; @@ -1291,9 +1334,14 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, false; camif_priv->irq_debug_cnt = 0; } - } else + } else { CAM_DBG(CAM_ISP, "VFE:%d Received SOF", evt_info.hw_idx); + camif_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; + } if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1306,6 +1354,10 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); evt_info.th_reg_val = payload->th_reg_val; + camif_priv->epoch_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->epoch_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1317,6 +1369,10 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->eof_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EOF", evt_info.hw_idx); + camif_priv->eof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + camif_priv->eof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, @@ -1329,6 +1385,11 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, & camif_priv->reg_data->error_irq_mask0) { CAM_ERR(CAM_ISP, "VFE:%d Overflow", evt_info.hw_idx); + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); @@ -1353,6 +1414,11 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + if (camif_priv->event_cb) camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 1b6b8ba3e3d6..9649cfedf47b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -21,7 +21,9 @@ struct cam_vfe_mux_rdi_data { struct cam_vfe_top_ver2_reg_offset_common *common_reg; struct cam_vfe_rdi_ver2_reg *rdi_reg; struct cam_vfe_rdi_common_reg_data *rdi_common_reg_data; + struct cam_vfe_rdi_overflow_status *rdi_irq_status; struct cam_vfe_rdi_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; cam_hw_mgr_event_cb_func event_cb; void *priv; @@ -33,6 +35,8 @@ struct cam_vfe_mux_rdi_data { spinlock_t spin_lock; enum cam_isp_hw_sync_mode sync_mode; + struct timeval sof_ts; + struct timeval error_ts; }; static int cam_vfe_rdi_get_evt_payload( @@ -81,6 +85,44 @@ static int cam_vfe_rdi_put_evt_payload( return 0; } +static int cam_vfe_rdi_cpas_reg_dump( +struct cam_vfe_mux_rdi_data *rdi_priv) +{ + struct cam_vfe_soc_private *soc_private = + rdi_priv->soc_info->soc_private; + uint32_t val; + + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || + soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_INFO(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + + } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } + + return 0; + +} + static int cam_vfe_rdi_err_irq_top_half( uint32_t evt_id, struct cam_irq_th_payload *th_payload) @@ -124,6 +166,12 @@ static int cam_vfe_rdi_err_irq_top_half( } cam_isp_hw_get_timestamp(&evt_payload->ts); + if (error_flag) { + rdi_priv->error_ts.tv_sec = + evt_payload->ts.mono_time.tv_sec; + rdi_priv->error_ts.tv_usec = + evt_payload->ts.mono_time.tv_usec; + } for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -282,6 +330,11 @@ static int cam_vfe_rdi_resource_start( } } + rsrc_data->sof_ts.tv_sec = 0; + rsrc_data->sof_ts.tv_usec = 0; + rsrc_data->error_ts.tv_sec = 0; + rsrc_data->error_ts.tv_usec = 0; + CAM_DBG(CAM_ISP, "Start RDI %d", rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0); end: @@ -392,6 +445,11 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; uint32_t irq_status0; + uint32_t irq_status1; + uint32_t irq_rdi_status; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct timespec64 ts; if (!handler_priv || !evt_payload_priv) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -401,8 +459,12 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, rdi_node = handler_priv; rdi_priv = rdi_node->res_priv; payload = evt_payload_priv; + soc_info = rdi_priv->soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; evt_info.hw_idx = rdi_node->hw_intf->hw_idx; evt_info.res_id = rdi_node->res_id; @@ -412,7 +474,10 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, if (irq_status0 & rdi_priv->reg_data->sof_irq_mask) { CAM_DBG(CAM_ISP, "Received SOF"); - + rdi_priv->sof_ts.tv_sec = + payload->ts.mono_time.tv_sec; + rdi_priv->sof_ts.tv_usec = + payload->ts.mono_time.tv_usec; if (rdi_priv->event_cb) rdi_priv->event_cb(rdi_priv->priv, CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); @@ -430,6 +495,53 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_SUCCESS; } + if (!rdi_priv->rdi_irq_status) + goto end; + + irq_rdi_status = + (irq_status1 & + rdi_priv->rdi_irq_status->rdi_overflow_mask); + if (irq_rdi_status) { + ktime_get_boottime_ts64(&ts); + CAM_INFO(CAM_ISP, + "current monotonic time stamp seconds %lld:%lld", + ts.tv_sec, ts.tv_nsec/1000); + + cam_vfe_rdi_cpas_reg_dump(rdi_priv); + + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + CAM_INFO(CAM_ISP, + "ERROR time %lld:%lld SOF %lld:%lld", + rdi_priv->error_ts.tv_sec, + rdi_priv->error_ts.tv_usec, + rdi_priv->sof_ts.tv_sec, + rdi_priv->sof_ts.tv_usec); + + if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi0_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_0; + } + else if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi1_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_1; + } + else if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi2_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_2; + } + else if (irq_rdi_status & + rdi_priv->rdi_irq_status->rdi3_overflow_mask) { + evt_info.res_id = CAM_ISP_IFE_OUT_RES_RDI_3; + } + + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_ERROR, + (void *)&evt_info); + cam_cpas_log_votes(); + } +end: cam_vfe_rdi_put_evt_payload(rdi_priv, &payload); CAM_DBG(CAM_ISP, "returing status = %d", ret); return ret; @@ -461,6 +573,8 @@ int cam_vfe_rdi_ver2_init( rdi_priv->rdi_reg = rdi_info->rdi_reg; rdi_priv->vfe_irq_controller = vfe_irq_controller; rdi_priv->rdi_common_reg_data = rdi_info->common_reg_data; + rdi_priv->soc_info = soc_info; + rdi_priv->rdi_irq_status = rdi_info->rdi_irq_status; switch (rdi_node->res_id) { case CAM_ISP_HW_VFE_IN_RDI0: diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h index f002b3218ab4..70a2cb756cea 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h @@ -17,6 +17,14 @@ struct cam_vfe_rdi_ver2_reg { uint32_t reg_update_cmd; }; +struct cam_vfe_rdi_overflow_status { + uint32_t rdi0_overflow_mask; + uint32_t rdi1_overflow_mask; + uint32_t rdi2_overflow_mask; + uint32_t rdi3_overflow_mask; + uint32_t rdi_overflow_mask; +}; + struct cam_vfe_rdi_common_reg_data { uint32_t subscribe_irq_mask0; uint32_t subscribe_irq_mask1; @@ -35,6 +43,7 @@ struct cam_vfe_rdi_ver2_hw_info { struct cam_vfe_top_ver2_reg_offset_common *common_reg; struct cam_vfe_rdi_ver2_reg *rdi_reg; struct cam_vfe_rdi_common_reg_data *common_reg_data; + struct cam_vfe_rdi_overflow_status *rdi_irq_status; struct cam_vfe_rdi_reg_data *reg_data[CAM_VFE_RDI_VER2_MAX]; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 4f1026b8ca9d..828d31c5c81c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -83,8 +83,11 @@ static int cam_vfe_top_set_hw_clk_rate( struct cam_hw_soc_info *soc_info = NULL; int i, rc = 0; unsigned long max_clk_rate = 0; + struct cam_vfe_soc_private *soc_private = NULL; soc_info = top_priv->common_data.soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; for (i = 0; i < top_priv->top_common.num_mux; i++) { if (top_priv->req_clk_rate[i] > max_clk_rate) @@ -96,7 +99,7 @@ static int cam_vfe_top_set_hw_clk_rate( CAM_DBG(CAM_PERF, "VFE: Clock name=%s idx=%d clk=%llu", soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); - + soc_private->ife_clk_src = max_clk_rate; rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); if (!rc) @@ -179,6 +182,19 @@ static int cam_vfe_top_mux_get_reg_update( return -EINVAL; } +static int cam_vfe_top_get_data( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_resource_node *res = cmd_args; + + if (res->process_cmd) + return res->process_cmd(res, + CAM_ISP_HW_CMD_CAMIF_DATA, cmd_args, arg_size); + + return -EINVAL; +} + int cam_vfe_top_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -543,6 +559,8 @@ int cam_vfe_top_stop(void *device_priv, struct cam_vfe_top_ver2_priv *top_priv; struct cam_isp_resource_node *mux_res; struct cam_hw_info *hw_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; int i, rc = 0; if (!device_priv || !stop_args) { @@ -553,6 +571,8 @@ int cam_vfe_top_stop(void *device_priv, top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; mux_res = (struct cam_isp_resource_node *)stop_args; hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; if ((mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || (mux_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) || @@ -583,7 +603,7 @@ int cam_vfe_top_stop(void *device_priv, } } } - + soc_private->ife_clk_src = 0; return rc; } @@ -662,6 +682,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_top_get_data(top_priv, cmd_args, + arg_size); + break; case CAM_ISP_HW_CMD_CLOCK_UPDATE: rc = cam_vfe_top_clock_update(top_priv, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index 2548dd0ac0ca..90d23486fb51 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -212,6 +212,19 @@ static int cam_vfe_top_ver3_mux_get_reg_update( return -EINVAL; } +static int cam_vfe_top_ver3_get_data( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_resource_node *res = cmd_args; + + if (res->process_cmd) + return res->process_cmd(res, + CAM_ISP_HW_CMD_CAMIF_DATA, cmd_args, arg_size); + + return -EINVAL; +} + int cam_vfe_top_ver3_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -573,6 +586,10 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_ver3_mux_get_reg_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_CAMIF_DATA: + rc = cam_vfe_top_ver3_get_data(top_priv, cmd_args, + arg_size); + break; case CAM_ISP_HW_CMD_CLOCK_UPDATE: rc = cam_vfe_top_ver3_clock_update(top_priv, cmd_args, arg_size); -- GitLab From 089231c6606bc6975f1516a65d9de066ec24b5aa Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 8 Jun 2020 00:47:48 +0530 Subject: [PATCH 312/410] msm: camera: lrme: Remove Workaround for Lagoon BU During Lagoon bring up, lrme clock has some issue causing the probe failure. To unblock, based on cpas version lrme hw start during probe time was skipped. Now the issue is fixed in clock driver, so remove the workaround. CRs-Fixed: 2704460 Change-Id: Ifef1485fd54a51dd67e3adedb50267c71dfbb0d8 Signed-off-by: Gaurav Jindal --- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index ad4e695f575e..a1414da98bfb 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -89,8 +89,6 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) const struct of_device_id *match_dev = NULL; struct cam_lrme_hw_info *hw_info; int rc, i; - int32_t camera_hw_version; - lrme_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); if (!lrme_hw) { @@ -160,18 +158,10 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) goto release_cdm; } - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + rc = cam_lrme_hw_start(lrme_hw, NULL, 0); if (rc) { - CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); - goto release_cdm; - } - - if (camera_hw_version != CAM_CPAS_TITAN_170_V200) { - rc = cam_lrme_hw_start(lrme_hw, NULL, 0); - if (rc) { - CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc); - goto detach_smmu; - } + CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc); + goto detach_smmu; } rc = cam_lrme_hw_util_get_caps(lrme_hw, &lrme_core->hw_caps); @@ -182,12 +172,10 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) goto detach_smmu; } - if (camera_hw_version != CAM_CPAS_TITAN_170_V200) { - rc = cam_lrme_hw_stop(lrme_hw, NULL, 0); - if (rc) { - CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc); - goto detach_smmu; - } + rc = cam_lrme_hw_stop(lrme_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc); + goto detach_smmu; } lrme_core->hw_idx = lrme_hw->soc_info.index; -- GitLab From 8a1156a1a96cf201be7cb91dac22fb391542794f Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 12 Jun 2020 16:18:05 +0530 Subject: [PATCH 313/410] msm: camera: sensor: unregister subdev if cpas registration fails In case if the CPAS registration is failed before freeing the memory of the subdev, subdev need to be unregistered so that subdev list entry will not become NULL and other subdev can be added. CRs-Fixed: 2708016 Change-Id: I464c73411596fc562fc7a190ddfa130f23ee487a Signed-off-by: Tejas Prajapati --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 5 ++++- drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 855fe5e68573..21ef008a7137 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -469,13 +469,16 @@ static int cam_cci_platform_probe(struct platform_device *pdev) rc = cam_cpas_register_client(&cpas_parms); if (rc) { CAM_ERR(CAM_CCI, "CPAS registration failed"); - goto cci_no_resource; + goto cci_unregister_subdev; } CAM_DBG(CAM_CCI, "CPAS registration successful handle=%d", cpas_parms.client_handle); new_cci_dev->cpas_handle = cpas_parms.client_handle; return rc; + +cci_unregister_subdev: + cam_unregister_subdev(&(new_cci_dev->v4l2_dev_str)); cci_no_resource: kfree(new_cci_dev); return rc; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index ba98d9adcc2d..a8a883dbbea2 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_csiphy_dev.h" @@ -181,13 +181,16 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) rc = cam_cpas_register_client(&cpas_parms); if (rc) { CAM_ERR(CAM_CSIPHY, "CPAS registration failed rc: %d", rc); - goto csiphy_no_resource; + goto csiphy_unregister_subdev; } CAM_DBG(CAM_CSIPHY, "CPAS registration successful handle=%d", cpas_parms.client_handle); new_csiphy_dev->cpas_handle = cpas_parms.client_handle; return rc; + +csiphy_unregister_subdev: + cam_unregister_subdev(&(new_csiphy_dev->v4l2_dev_str)); csiphy_no_resource: mutex_destroy(&new_csiphy_dev->mutex); kfree(new_csiphy_dev->ctrl_reg); -- GitLab From 2bd69f530d359652c698484296949f9c63e91b91 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 2 Apr 2020 20:43:26 +0530 Subject: [PATCH 314/410] msm: camera: sensor: Dump phy registers on error Dump csiphy registers on following fatal errors: 1. lane overflow error 2. unbounded frame error 3. SOT ans EOT reception error 4. stream underflow error These errors irqs are set at csid end, Currently there is no interface to send message from one subdevice to other if the subdev is not a real time device. This change adds an interface to notify the no real time subdev.o real time subdev. CRs-Fixed: 2696744 Change-Id: I522167d1639ac298bc739a8a5a380a01356f0776 Signed-off-by: Vishal Verma --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 6 ++- drivers/cam_req_mgr/cam_req_mgr_dev.c | 20 +++++++- drivers/cam_req_mgr/cam_subdev.h | 25 +++++++++- .../cam_csiphy/cam_csiphy_dev.c | 23 ++++++++- .../cam_csiphy/cam_csiphy_dev.h | 2 + .../cam_csiphy/cam_csiphy_soc.c | 47 +++++++++++++++++++ .../cam_csiphy/cam_csiphy_soc.h | 9 +++- .../cam_csiphy/include/cam_csiphy_1_0_hwreg.h | 3 +- .../cam_csiphy/include/cam_csiphy_1_1_hwreg.h | 3 +- .../include/cam_csiphy_1_2_1_hwreg.h | 1 + .../include/cam_csiphy_1_2_2_hwreg.h | 1 + .../include/cam_csiphy_1_2_3_hwreg.h | 1 + .../cam_csiphy/include/cam_csiphy_1_2_hwreg.h | 1 + .../cam_csiphy/include/cam_csiphy_2_0_hwreg.h | 3 +- 14 files changed, 137 insertions(+), 8 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 3a607dbf16b8..d7793d28717e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -7,7 +7,7 @@ #include #include #include - +#include #include #include "cam_isp_hw_mgr_intf.h" @@ -18,6 +18,7 @@ #include "cam_debug_util.h" #include "cam_cpas_api.h" #include "cam_tasklet_util.h" +#include "cam_subdev.h" /* Timeout value in msec */ #define IFE_CSID_TIMEOUT 1000 @@ -1721,6 +1722,9 @@ static void cam_ife_csid_halt_csi2( csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_IRQ_ERR, + csid_hw->csi2_rx_cfg.phy_sel); } static int cam_ife_csid_init_config_pxl_path( diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 2ce03eaa341e..6e0c406ca482 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -643,6 +643,24 @@ void cam_register_subdev_fops(struct v4l2_file_operations *fops) } EXPORT_SYMBOL(cam_register_subdev_fops); +void cam_subdev_notify_message(u32 subdev_type, + enum cam_subdev_message_type_t message_type, + uint32_t data) +{ + struct v4l2_subdev *sd = NULL; + struct cam_subdev *csd = NULL; + + list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + sd->entity.name = video_device_node_name(sd->devnode); + if (sd->entity.function == subdev_type) { + csd = container_of(sd, struct cam_subdev, sd); + if (csd->msg_cb != NULL) + csd->msg_cb(sd, message_type, data); + } + } +} +EXPORT_SYMBOL(cam_subdev_notify_message); + int cam_register_subdev(struct cam_subdev *csd) { struct v4l2_subdev *sd; @@ -671,7 +689,7 @@ int cam_register_subdev(struct cam_subdev *csd) sd = &csd->sd; v4l2_subdev_init(sd, csd->ops); sd->internal_ops = csd->internal_ops; - snprintf(sd->name, ARRAY_SIZE(sd->name), csd->name); + snprintf(sd->name, V4L2_SUBDEV_NAME_SIZE, "%s", csd->name); v4l2_set_subdevdata(sd, csd->token); sd->flags = csd->sd_flags; diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h index 385643d5e532..5a0ef2ef5ecf 100644 --- a/drivers/cam_req_mgr/cam_subdev.h +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SUBDEV_H_ @@ -16,6 +16,10 @@ #define CAM_SUBDEVICE_EVENT_MAX 30 +enum cam_subdev_message_type_t { + CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1 +}; + /** * struct cam_subdev - describes a camera sub-device * @@ -34,6 +38,7 @@ * @ent_function: Media entity function type. Can be: * %CAM_IFE_DEVICE_TYPE - identifies as IFE device. * %CAM_ICP_DEVICE_TYPE - identifies as ICP device. + * @msg_cb: Pointer to the callback function to dump PHY status. * * Each instance of a subdev driver should create this struct, either * stand-alone or embedded in a larger struct. This structure should be @@ -49,8 +54,26 @@ struct cam_subdev { u32 sd_flags; void *token; u32 ent_function; + void (*msg_cb)( + struct v4l2_subdev *sd, + enum cam_subdev_message_type_t msg_type, + uint32_t data); }; +/** + * cam_subdev_notify_message() + * + * @brief: Notify message to a subdevs of specific type + * + * @subdev_type: Subdev type + * @message_type: message type + * @data: data to be delivered. + * + */ +void cam_subdev_notify_message(u32 subdev_type, + enum cam_subdev_message_type_t message_type, + uint32_t data); + /** * cam_subdev_probe() * diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index ba98d9adcc2d..2ccf91e8f37a 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_csiphy_dev.h" @@ -9,6 +9,25 @@ #include "cam_csiphy_core.h" #include +static void cam_csiphy_subdev_handle_message( + struct v4l2_subdev *sd, + enum cam_subdev_message_type_t message_type, + uint32_t data) +{ + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + + switch (message_type) { + case CAM_SUBDEV_MESSAGE_IRQ_ERR: + CAM_INFO(CAM_CSIPHY, "subdev index : %d CSIPHY index: %d", + csiphy_dev->soc_info.index, data); + if (data == csiphy_dev->soc_info.index) + cam_csiphy_status_dmp(csiphy_dev); + break; + default: + break; + } +} + static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -148,6 +167,8 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); new_csiphy_dev->v4l2_dev_str.ent_function = CAM_CSIPHY_DEVICE_TYPE; + new_csiphy_dev->v4l2_dev_str.msg_cb = + cam_csiphy_subdev_handle_message; new_csiphy_dev->v4l2_dev_str.token = new_csiphy_dev; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 70b8cc9d8249..3940911147f7 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -87,6 +87,7 @@ enum cam_csiphy_state { * @mipi_csiphy_interrupt_clear0_addr: * CSIPhy interrupt clear addr * @csiphy_version: CSIPhy Version + * @csiphy_interrupt_status_size: CSIPhy status register size * @csiphy_common_array_size: CSIPhy common array size * @csiphy_reset_array_size: CSIPhy reset array size * @csiphy_2ph_config_array_size: 2ph settings size @@ -108,6 +109,7 @@ struct csiphy_reg_parms_t { uint32_t mipi_csiphy_interrupt_mask_addr; uint32_t mipi_csiphy_interrupt_clear0_addr; uint32_t csiphy_version; + uint32_t csiphy_interrupt_status_size; uint32_t csiphy_common_array_size; uint32_t csiphy_reset_array_size; uint32_t csiphy_2ph_config_array_size; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 3d053643eb49..d9e8eb94cfa0 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -78,6 +78,53 @@ int32_t cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info) return rc; } +int32_t cam_csiphy_status_dmp(struct csiphy_device *csiphy_dev) +{ + struct csiphy_reg_parms_t *csiphy_reg = NULL; + int32_t rc = 0; + resource_size_t size = 0; + void __iomem *phy_base = NULL; + int reg_id = 0; + uint32_t irq, status_reg, clear_reg; + + if (!csiphy_dev) { + rc = -EINVAL; + CAM_ERR(CAM_CSIPHY, "invalid input %d", rc); + return rc; + } + + csiphy_reg = &csiphy_dev->ctrl_reg->csiphy_reg; + phy_base = csiphy_dev->soc_info.reg_map[0].mem_base; + status_reg = csiphy_reg->mipi_csiphy_interrupt_status0_addr; + clear_reg = csiphy_reg->mipi_csiphy_interrupt_clear0_addr; + size = csiphy_reg->csiphy_interrupt_status_size; + + CAM_INFO(CAM_CSIPHY, "PHY base addr=%pK offset=0x%x size=%d", + phy_base, status_reg, size); + + if (phy_base != NULL) { + for (reg_id = 0; reg_id < size; reg_id++) { + uint32_t offset; + + offset = status_reg + (0x4 * reg_id); + irq = cam_io_r(phy_base + offset); + offset = clear_reg + (0x4 * reg_id); + cam_io_w_mb(irq, phy_base + offset); + cam_io_w_mb(0, phy_base + offset); + + CAM_INFO(CAM_CSIPHY, + "CSIPHY%d_IRQ_STATUS_ADDR%d = 0x%x", + csiphy_dev->soc_info.index, reg_id, irq); + } + } else { + rc = -EINVAL; + CAM_ERR(CAM_CSIPHY, "phy base is NULL %d", rc); + return rc; + } + + return rc; +} + enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev) { CAM_DBG(CAM_CSIPHY, "voting for SVS"); diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index c02b9556add4..561d74293e90 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_SOC_H_ @@ -70,4 +70,11 @@ int cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev); */ int cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info); +/** + * @csiphy_dev: CSIPhy device structure + * + * This API dumps memory for the entire status region + */ +int32_t cam_csiphy_status_dmp(struct csiphy_device *csiphy_dev); + #endif /* _CAM_CSIPHY_SOC_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h index e910162858b3..eaedc7b672a8 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_0_HWREG_H_ @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_0 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 5, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 14, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h index 30b61067a792..e1db638da5f0 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_1_1_HWREG_H_ @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_1 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 5, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 14, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h index c9fb93f7e9bd..8bf373677a51 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_1 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 20, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h index 637867398bab..165b751c12c5 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 8, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 18, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h index 067a6bc1fce1..5a950f843083 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_3 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 23, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index 3cf02e90358d..8a87d4056a6b 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 7, .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 19, diff --git a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h index cbd0dc582b32..453da81ff35d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h +++ b/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSIPHY_2_0_HWREG_H_ @@ -12,6 +12,7 @@ struct csiphy_reg_parms_t csiphy_v2_0 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_interrupt_status_size = 11, .csiphy_common_array_size = 6, .csiphy_reset_array_size = 3, .csiphy_2ph_config_array_size = 15, -- GitLab From 4625e14533ea94ecc0519179ae343a5decc4573e Mon Sep 17 00:00:00 2001 From: daopingl Date: Fri, 19 Jun 2020 18:32:47 +0800 Subject: [PATCH 315/410] msm: camera: smmu: add null check for memory slot function add null check for camera memory slot function. CRs-Fixed: 2674888 Change-Id: I171d479919f0375028f55689148a1b097312c329 Signed-off-by: daopingl --- drivers/cam_req_mgr/cam_mem_mgr.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index a389eae1526a..e4fdcd284a72 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -177,18 +177,22 @@ static int32_t cam_mem_get_slot(void) int32_t idx; mutex_lock(&tbl.m_lock); - idx = find_first_zero_bit(tbl.bitmap, tbl.bits); - if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + if (tbl.bitmap) { + idx = find_first_zero_bit(tbl.bitmap, tbl.bits); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + mutex_unlock(&tbl.m_lock); + return -ENOMEM; + } + + set_bit(idx, tbl.bitmap); + tbl.bufq[idx].active = true; + mutex_init(&tbl.bufq[idx].q_lock); mutex_unlock(&tbl.m_lock); - return -ENOMEM; + return idx; } - set_bit(idx, tbl.bitmap); - tbl.bufq[idx].active = true; - mutex_init(&tbl.bufq[idx].q_lock); mutex_unlock(&tbl.m_lock); - - return idx; + return -EINVAL; } static void cam_mem_put_slot(int32_t idx) -- GitLab From 698031316667dd1f0ec85b42e3342921d7e0ee0d Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Tue, 16 Jun 2020 00:07:59 +0530 Subject: [PATCH 316/410] msm: camera: cpas: Return error code for resource enable failure In the case of resource enable failure we need to return the error code to give the caller information about failure. Change-Id: I72f3f8619445abf9a5aececfc83cf9d2d680d5d6 CRs-Fixed: 2709705 Signed-off-by: Wyes Karny --- drivers/cam_cpas/cam_cpas_hw.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index fa840f944757..dc94de0fb73e 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -1287,7 +1287,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, struct cam_ahb_vote remove_ahb; struct cam_axi_vote axi_vote = {0}; enum cam_vote_level applied_level = CAM_SVS_VOTE; - int rc, i = 0; + int rc, ret = 0, i = 0; struct cam_cpas_private_soc *soc_private = NULL; bool invalid_start = true; @@ -1441,25 +1441,26 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, remove_axi_vote: memset(&axi_vote, 0x0, sizeof(struct cam_axi_vote)); - rc = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); - if (rc) - CAM_ERR(CAM_CPAS, "Unable to create per path votes rc: %d", rc); + ret = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); + if (ret) + CAM_ERR(CAM_CPAS, "Unable to create per path votes ret: %d", + ret); cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start fail Vote", &axi_vote); - rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + ret = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); - if (rc) - CAM_ERR(CAM_CPAS, "Unable to remove axi votes rc: %d", rc); + if (ret) + CAM_ERR(CAM_CPAS, "Unable to remove axi votes ret: %d", ret); remove_ahb_vote: remove_ahb.type = CAM_VOTE_ABSOLUTE; remove_ahb.vote.level = CAM_SUSPEND_VOTE; - rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + ret = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, &remove_ahb, NULL); - if (rc) - CAM_ERR(CAM_CPAS, "Removing AHB vote failed, rc=%d", rc); + if (ret) + CAM_ERR(CAM_CPAS, "Removing AHB vote failed, ret: %d", ret); error: mutex_unlock(&cpas_core->client_mutex[client_indx]); -- GitLab From bb237a44eb558849c5d30e5bee20a0bc6d4db078 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Wed, 1 Jul 2020 22:57:48 +0530 Subject: [PATCH 317/410] msm: camera: isp: Init spinlock to avoid unexpected behaviour Using spin lock without init may result in unexpected behaviour, This change initialize ctx_lock during init. CRs-Fixed: 2724911 Change-Id: I250e6b1359bf9f3e2f3ec1ee27f6df84a50b207d Signed-off-by: Vikram Sharma --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 6fcdd3d0b47c..e585ced506f4 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -7659,6 +7659,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr)); mutex_init(&g_ife_hw_mgr.ctx_mutex); + spin_lock_init(&g_ife_hw_mgr.ctx_lock); if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "CSID num is different then IFE num"); -- GitLab From a6abe6c356160532f91286cc98c6e7b1f22332b0 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Tue, 23 Jun 2020 10:48:35 +0530 Subject: [PATCH 318/410] msm: camera: csid: Increment error count for ERROR_CRC and ERROR_ECC This change will help recovring from multiple CRC and ECC errors. CRs-Fixed: 2715172 Change-Id: Ie76703a100b1b90b3bf8a9c47deac1a5d5654c00 Signed-off-by: Vikram Sharma --- .../cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 537779839202..7aba9bc84a5f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -4584,16 +4584,19 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; } if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & CSID_CSI2_RX_ERROR_CRC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; } if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & CSID_CSI2_RX_ERROR_ECC) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; } if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { -- GitLab From 6b3b21c0a69065d4a645a0f8ae9e14381d1a1c4c Mon Sep 17 00:00:00 2001 From: taojiang Date: Mon, 22 Jun 2020 16:49:19 +0800 Subject: [PATCH 319/410] msm: camera: common: add reference count for all video subdevs Add reference count for all camera subdevs to avoid open/close count mismatch. CRs-Fixed: 2714527 Change-Id: I68c38106a071bb2e87c5e2695ebf60035f8e6a62 Signed-off-by: taojiang --- drivers/cam_fd/cam_fd_dev.c | 13 +++++-- .../cam_actuator/cam_actuator_dev.c | 33 +++++++++++++++-- .../cam_actuator/cam_actuator_dev.h | 3 +- .../cam_csiphy/cam_csiphy_dev.c | 31 +++++++++++++++- .../cam_csiphy/cam_csiphy_dev.h | 1 + .../cam_eeprom/cam_eeprom_dev.c | 35 +++++++++++++++++-- .../cam_eeprom/cam_eeprom_dev.h | 3 +- .../cam_flash/cam_flash_dev.c | 31 +++++++++++++++- .../cam_flash/cam_flash_dev.h | 1 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 33 +++++++++++++++-- .../cam_sensor_module/cam_ois/cam_ois_dev.h | 3 +- 11 files changed, 173 insertions(+), 14 deletions(-) diff --git a/drivers/cam_fd/cam_fd_dev.c b/drivers/cam_fd/cam_fd_dev.c index c92cea8fc9e9..ddf6cf3843de 100644 --- a/drivers/cam_fd/cam_fd_dev.c +++ b/drivers/cam_fd/cam_fd_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved. */ #include @@ -68,16 +68,22 @@ static int cam_fd_dev_close(struct v4l2_subdev *sd, } mutex_lock(&fd_dev->lock); + if (fd_dev->open_cnt <= 0) { + mutex_unlock(&fd_dev->lock); + return -EINVAL; + } fd_dev->open_cnt--; CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); - mutex_unlock(&fd_dev->lock); if (!node) { CAM_ERR(CAM_FD, "Node ptr is NULL"); + mutex_unlock(&fd_dev->lock); return -EINVAL; } - cam_node_shutdown(node); + if (fd_dev->open_cnt == 0) + cam_node_shutdown(node); + mutex_unlock(&fd_dev->lock); return 0; } @@ -131,6 +137,7 @@ static int cam_fd_dev_probe(struct platform_device *pdev) mutex_init(&g_fd_dev.lock); g_fd_dev.probe_done = true; + g_fd_dev.open_cnt = 0; CAM_DBG(CAM_FD, "Camera FD probe complete"); diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 46bd99fc9e29..0da40d3613a1 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved. */ #include "cam_actuator_dev.h" @@ -72,6 +72,25 @@ static long cam_actuator_init_subdev_do_ioctl(struct v4l2_subdev *sd, } #endif +static int cam_actuator_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_actuator_ctrl_t *a_ctrl = + v4l2_get_subdevdata(sd); + + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "a_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + a_ctrl->open_cnt++; + CAM_DBG(CAM_ACTUATOR, "actuator_dev open count %d", a_ctrl->open_cnt); + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return 0; +} + static int cam_actuator_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { @@ -84,7 +103,14 @@ static int cam_actuator_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&(a_ctrl->actuator_mutex)); - cam_actuator_shutdown(a_ctrl); + if (a_ctrl->open_cnt <= 0) { + mutex_unlock(&(a_ctrl->actuator_mutex)); + return -EINVAL; + } + a_ctrl->open_cnt--; + CAM_DBG(CAM_ACTUATOR, "actuator_dev open count %d", a_ctrl->open_cnt); + if (a_ctrl->open_cnt == 0) + cam_actuator_shutdown(a_ctrl); mutex_unlock(&(a_ctrl->actuator_mutex)); return 0; @@ -102,6 +128,7 @@ static struct v4l2_subdev_ops cam_actuator_subdev_ops = { }; static const struct v4l2_subdev_internal_ops cam_actuator_internal_ops = { + .open = cam_actuator_subdev_open, .close = cam_actuator_subdev_close, }; @@ -210,6 +237,7 @@ static int32_t cam_actuator_driver_i2c_probe(struct i2c_client *client, cam_actuator_apply_request; a_ctrl->last_flush_req = 0; a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + a_ctrl->open_cnt = 0; return rc; @@ -372,6 +400,7 @@ static int32_t cam_actuator_driver_platform_probe( platform_set_drvdata(pdev, a_ctrl); a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + a_ctrl->open_cnt = 0; return rc; diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h index e4bfaed4414f..2837cd85c9d4 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ @@ -115,6 +115,7 @@ struct cam_actuator_ctrl_t { struct cam_actuator_query_cap act_info; struct intf_params bridge_intf; uint32_t last_flush_req; + uint32_t open_cnt; }; #endif /* _CAM_ACTUATOR_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index 9b05979c648f..d127a70a7b7f 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -50,6 +50,26 @@ static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, return rc; } + +static int cam_csiphy_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct csiphy_device *csiphy_dev = + v4l2_get_subdevdata(sd); + + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "csiphy_dev ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&csiphy_dev->mutex); + csiphy_dev->open_cnt++; + CAM_DBG(CAM_CSIPHY, "csiphy_dev open count %d", csiphy_dev->open_cnt); + mutex_unlock(&csiphy_dev->mutex); + + return 0; +} + static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { @@ -62,7 +82,14 @@ static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&csiphy_dev->mutex); - cam_csiphy_shutdown(csiphy_dev); + if (csiphy_dev->open_cnt <= 0) { + mutex_unlock(&csiphy_dev->mutex); + return -EINVAL; + } + csiphy_dev->open_cnt--; + CAM_DBG(CAM_CSIPHY, "csiphy_dev open count %d", csiphy_dev->open_cnt); + if (csiphy_dev->open_cnt == 0) + cam_csiphy_shutdown(csiphy_dev); mutex_unlock(&csiphy_dev->mutex); return 0; @@ -120,6 +147,7 @@ static const struct v4l2_subdev_ops csiphy_subdev_ops = { }; static const struct v4l2_subdev_internal_ops csiphy_subdev_intern_ops = { + .open = cam_csiphy_subdev_open, .close = cam_csiphy_subdev_close, }; @@ -192,6 +220,7 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) new_csiphy_dev->acquire_count = 0; new_csiphy_dev->start_dev_count = 0; new_csiphy_dev->is_acquired_dev_combo_mode = 0; + new_csiphy_dev->open_cnt = 0; cpas_parms.cam_cpas_client_cb = NULL; cpas_parms.cell_index = new_csiphy_dev->soc_info.index; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 3940911147f7..76bfc441b060 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -293,6 +293,7 @@ struct csiphy_device { struct cam_hw_soc_info soc_info; uint32_t cpas_handle; uint32_t config_count; + uint32_t open_cnt; uint64_t csiphy_cpas_cp_reg_mask[CSIPHY_MAX_INSTANCES]; }; diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index 328541553b59..c3fc4397ce94 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_eeprom_dev.h" @@ -27,6 +27,26 @@ static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, return rc; } +static int cam_eeprom_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_eeprom_ctrl_t *e_ctrl = + v4l2_get_subdevdata(sd); + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "e_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(e_ctrl->eeprom_mutex)); + e_ctrl->open_cnt++; + CAM_DBG(CAM_EEPROM, "eeprom Subdev open count %d", e_ctrl->open_cnt); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + + return 0; +} + + static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { @@ -39,7 +59,14 @@ static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&(e_ctrl->eeprom_mutex)); - cam_eeprom_shutdown(e_ctrl); + if (e_ctrl->open_cnt <= 0) { + mutex_unlock(&(e_ctrl->eeprom_mutex)); + return -EINVAL; + } + e_ctrl->open_cnt--; + CAM_DBG(CAM_EEPROM, "eeprom Subdev open count %d", e_ctrl->open_cnt); + if (e_ctrl->open_cnt == 0) + cam_eeprom_shutdown(e_ctrl); mutex_unlock(&(e_ctrl->eeprom_mutex)); return 0; @@ -116,6 +143,7 @@ static long cam_eeprom_init_subdev_do_ioctl(struct v4l2_subdev *sd, #endif static const struct v4l2_subdev_internal_ops cam_eeprom_internal_ops = { + .open = cam_eeprom_subdev_open, .close = cam_eeprom_subdev_close, }; @@ -217,6 +245,7 @@ static int cam_eeprom_i2c_driver_probe(struct i2c_client *client, e_ctrl->bridge_intf.ops.link_setup = NULL; e_ctrl->bridge_intf.ops.apply_req = NULL; e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + e_ctrl->open_cnt = 0; return rc; free_soc: @@ -338,6 +367,7 @@ static int cam_eeprom_spi_setup(struct spi_device *spi) e_ctrl->bridge_intf.ops.get_dev_info = NULL; e_ctrl->bridge_intf.ops.link_setup = NULL; e_ctrl->bridge_intf.ops.apply_req = NULL; + e_ctrl->open_cnt = 0; v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl); return rc; @@ -469,6 +499,7 @@ static int32_t cam_eeprom_platform_driver_probe( e_ctrl->bridge_intf.ops.apply_req = NULL; platform_set_drvdata(pdev, e_ctrl); e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + e_ctrl->open_cnt = 0; return rc; free_soc: diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h index 66f8aaddc958..65afb96661b1 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_EEPROM_DEV_H_ #define _CAM_EEPROM_DEV_H_ @@ -190,6 +190,7 @@ struct cam_eeprom_ctrl_t { uint16_t is_multimodule_mode; struct i2c_settings_array wr_settings; struct eebin_info eebin_info; + uint32_t open_cnt; }; int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl, diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index cbcaeefa59d0..d47149455526 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -342,6 +342,25 @@ static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client) return rc; } +static int cam_flash_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_flash_ctrl *fctrl = + v4l2_get_subdevdata(sd); + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + fctrl->open_cnt++; + CAM_DBG(CAM_FLASH, "Flash open count %d", fctrl->open_cnt); + mutex_unlock(&fctrl->flash_mutex); + + return 0; +} + static int cam_flash_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { @@ -354,7 +373,14 @@ static int cam_flash_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&fctrl->flash_mutex); - cam_flash_shutdown(fctrl); + if (fctrl->open_cnt <= 0) { + mutex_unlock(&fctrl->flash_mutex); + return -EINVAL; + } + fctrl->open_cnt--; + CAM_DBG(CAM_FLASH, "Flash open count %d", fctrl->open_cnt); + if (fctrl->open_cnt == 0) + cam_flash_shutdown(fctrl); mutex_unlock(&fctrl->flash_mutex); return 0; @@ -372,6 +398,7 @@ static struct v4l2_subdev_ops cam_flash_subdev_ops = { }; static const struct v4l2_subdev_internal_ops cam_flash_internal_ops = { + .open = cam_flash_subdev_open, .close = cam_flash_subdev_close, }; @@ -518,6 +545,7 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) mutex_init(&(fctrl->flash_mutex)); fctrl->flash_state = CAM_FLASH_STATE_INIT; + fctrl->open_cnt = 0; CAM_DBG(CAM_FLASH, "Probe success"); return rc; @@ -607,6 +635,7 @@ static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, mutex_init(&(fctrl->flash_mutex)); fctrl->flash_state = CAM_FLASH_STATE_INIT; + fctrl->open_cnt = 0; return rc; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index 3c3e83e32047..407246cb0d59 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -207,6 +207,7 @@ struct cam_flash_ctrl { struct camera_io_master io_master_info; struct i2c_data_settings i2c_data; uint32_t last_flush_req; + uint32_t open_cnt; }; int cam_flash_pmic_gpio_pkt_parser( diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 10044cec6efd..6de45da89c44 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved. */ #include "cam_ois_dev.h" @@ -27,6 +27,25 @@ static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, return rc; } +static int cam_ois_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_ois_ctrl_t *o_ctrl = + v4l2_get_subdevdata(sd); + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "o_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(o_ctrl->ois_mutex)); + o_ctrl->open_cnt++; + CAM_DBG(CAM_OIS, "OIS open count %d", o_ctrl->open_cnt); + mutex_unlock(&(o_ctrl->ois_mutex)); + + return 0; +} + static int cam_ois_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { @@ -39,7 +58,14 @@ static int cam_ois_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&(o_ctrl->ois_mutex)); - cam_ois_shutdown(o_ctrl); + if (o_ctrl->open_cnt <= 0) { + mutex_unlock(&(o_ctrl->ois_mutex)); + return -EINVAL; + } + o_ctrl->open_cnt--; + CAM_DBG(CAM_OIS, "OIS open count %d", o_ctrl->open_cnt); + if (o_ctrl->open_cnt == 0) + cam_ois_shutdown(o_ctrl); mutex_unlock(&(o_ctrl->ois_mutex)); return 0; @@ -111,6 +137,7 @@ static long cam_ois_init_subdev_do_ioctl(struct v4l2_subdev *sd, #endif static const struct v4l2_subdev_internal_ops cam_ois_internal_ops = { + .open = cam_ois_subdev_open, .close = cam_ois_subdev_close, }; @@ -198,6 +225,7 @@ static int cam_ois_i2c_driver_probe(struct i2c_client *client, goto soc_free; o_ctrl->cam_ois_state = CAM_OIS_INIT; + o_ctrl->open_cnt = 0; return rc; @@ -300,6 +328,7 @@ static int32_t cam_ois_platform_driver_probe( platform_set_drvdata(pdev, o_ctrl); o_ctrl->cam_ois_state = CAM_OIS_INIT; + o_ctrl->open_cnt = 0; return rc; unreg_subdev: diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index 788243ae9da0..d3ba747d96e7 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_OIS_DEV_H_ #define _CAM_OIS_DEV_H_ @@ -122,6 +122,7 @@ struct cam_ois_ctrl_t { uint8_t ois_fw_flag; uint8_t is_ois_calib; struct cam_ois_opcode opcode; + uint32_t open_cnt; }; #endif /*_CAM_OIS_DEV_H_ */ -- GitLab From 41755d5f0af94b0a5796c9bf5bc14889293ff539 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Thu, 2 Jul 2020 18:39:27 +0530 Subject: [PATCH 320/410] msm: camera: isp: Add format measure support for IFE lite This change adds format measure field for CSID in IFE Lite for version 17x and 480 hardware. CRs-Fixed: 2724224 Change-Id: I1b0d79559dcda14ea7f7edea6f43eb636f92ca5d Signed-off-by: Ayush Kumar --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h | 8 +++++++- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h index 4d8783ce0c0f..18ccc9846aea 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_LITE17X_H_ @@ -298,6 +298,12 @@ static const struct cam_ife_csid_common_reg_offset .ipp_irq_mask_all = 0x7FFF, .rdi_irq_mask_all = 0x7FFF, .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, + .format_measure_height_mask_val = 0xFFFF, + .format_measure_height_shift_val = 0x10, + .format_measure_width_mask_val = 0xFFFF, + .format_measure_width_shift_val = 0x0, }; static const struct cam_ife_csid_reg_offset cam_ife_csid_lite_17x_reg_offset = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h index b77f2dfa350e..6b6cdd96fa0a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_LITE_480_H_ @@ -321,6 +321,10 @@ static struct cam_ife_csid_common_reg_offset .ppp_irq_mask_all = 0xFFFF, .measure_en_hbi_vbi_cnt_mask = 0xC, .format_measure_en_val = 1, + .format_measure_height_mask_val = 0xFFFF, + .format_measure_height_shift_val = 0x10, + .format_measure_width_mask_val = 0xFFFF, + .format_measure_width_shift_val = 0x0, }; static struct cam_ife_csid_reg_offset cam_ife_csid_lite_480_reg_offset = { -- GitLab From 035284679183caa6e82f825a27d83d66e347fceb Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 8 Jun 2020 18:48:14 -0700 Subject: [PATCH 321/410] msm: camera: isp: Unmask CSI RX IRQs In stop immediate currently only the CSID path is reset, the RX is still capable of listening to IRQs. Unmask this in stop and enable them again at start. CRs-Fixed: 2698391 CRs-Fixed: 2720237 Change-Id: Iacdc9d241192e976b61728314a83d445534234c6 Signed-off-by: Karthik Anantha Ram Signed-off-by: Vishalsingh Hajeri Signed-off-by: taojiang --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 128 +++++++++++------- 1 file changed, 80 insertions(+), 48 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 7aba9bc84a5f..580143f03ce6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1545,6 +1545,71 @@ static int cam_ife_csid_config_tpg(struct cam_ife_csid_hw *csid_hw, return 0; } +static int cam_ife_csid_csi2_irq_ctrl( + struct cam_ife_csid_hw *csid_hw, + bool irq_enable) +{ + uint32_t val = 0; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (irq_enable) { + /*Enable the CSI2 rx interrupts */ + val = CSID_CSI2_RX_INFO_RST_DONE | + CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION | + CSID_CSI2_RX_ERROR_CRC | + CSID_CSI2_RX_ERROR_ECC | + CSID_CSI2_RX_ERROR_MMAPPED_VC_DT | + CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW | + CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME | + CSID_CSI2_RX_ERROR_CPHY_PH_CRC; + + if (csid_hw->epd_supported == 1) + CAM_INFO(CAM_ISP, + "Disable CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION for EPD"); + else + val = val | CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION; + + /* Enable the interrupt based on csid debug info set */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) + val |= CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) + val |= CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + } else { + /* Disable the CSI2 rx inerrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + } + + return 0; +} + static int cam_ife_csid_enable_csi2( struct cam_ife_csid_hw *csid_hw, struct cam_isp_resource_node *res) @@ -1605,51 +1670,7 @@ static int cam_ife_csid_enable_csi2( } } - /*Enable the CSI2 rx interrupts */ - val = CSID_CSI2_RX_INFO_RST_DONE | - CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW | - CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | - CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW | - CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW | - CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW | - CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION | - CSID_CSI2_RX_ERROR_CRC | - CSID_CSI2_RX_ERROR_ECC | - CSID_CSI2_RX_ERROR_MMAPPED_VC_DT | - CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW | - CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME | - CSID_CSI2_RX_ERROR_CPHY_PH_CRC; - - if (csid_hw->epd_supported == 1) - CAM_INFO(CAM_ISP, - "Disable CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION for EPD"); - else - val = val | CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION; - - /* Enable the interrupt based on csid debug info set */ - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) - val |= CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED | - CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED | - CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED | - CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED; - - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) - val |= CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED | - CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED | - CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED | - CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED; - - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) - val |= CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED; - - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) - val |= CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) - val |= CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED; - - cam_io_w_mb(val, soc_info->reg_map[0].mem_base + - csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); - + cam_ife_csid_csi2_irq_ctrl(csid_hw, true); return 0; } @@ -1686,9 +1707,7 @@ static int cam_ife_csid_disable_csi2( if (csid_hw->csi2_cfg_cnt) return 0; - /* Disable the CSI2 rx inerrupts */ - cam_io_w_mb(0, soc_info->reg_map[0].mem_base + - csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + cam_ife_csid_csi2_irq_ctrl(csid_hw, false); /* Reset the Rx CFG registers */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + @@ -3688,6 +3707,7 @@ int cam_ife_csid_start(void *hw_priv, void *start_args, struct cam_hw_info *csid_hw_info; struct cam_isp_resource_node *res; const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; if (!hw_priv || !start_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -3715,6 +3735,12 @@ int cam_ife_csid_start(void *hw_priv, void *start_args, csid_hw->sof_irq_triggered = false; csid_hw->irq_debug_cnt = 0; + spin_lock_irqsave(&csid_hw->lock_state, flags); + if (!csid_hw->device_enabled) + cam_ife_csid_csi2_irq_ctrl(csid_hw, true); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + CAM_DBG(CAM_ISP, "CSID:%d res_type :%d res_id:%d", csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); @@ -3798,6 +3824,7 @@ int cam_ife_csid_stop(void *hw_priv, struct cam_csid_hw_stop_args *csid_stop; uint32_t i; uint32_t res_mask = 0; + unsigned long flags; if (!hw_priv || !stop_args || (arg_size != sizeof(struct cam_csid_hw_stop_args))) { @@ -3817,6 +3844,11 @@ int cam_ife_csid_stop(void *hw_priv, csid_hw->hw_intf->hw_idx, csid_stop->num_res); + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 0; + cam_ife_csid_csi2_irq_ctrl(csid_hw, false); + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + /* Stop the resource first */ for (i = 0; i < csid_stop->num_res; i++) { res = csid_stop->node_res[i]; -- GitLab From 0e69194cd695a4f8da143c787ad37409e445ba43 Mon Sep 17 00:00:00 2001 From: Fernando Pacheco Date: Wed, 17 Jun 2020 12:37:39 -0700 Subject: [PATCH 322/410] msm: camera: cci: Fix incorrect use of cci config ioctl The cci configuration will be transitioned to a new API that does not require routing through the v4l layer. This is work-in-progrss so in the mean time prevent the device from being exposed as configurable from userspace. The ioctl will still be exposed to kernel users so fix the arg size as well. We want size of struct not pointer. CRs-Fixed: 2702760 Change-Id: I9c7bd8f76980603dbf27e1c5bc9b19f8a3b8a39a Signed-off-by: Fernando Pacheco --- drivers/cam_sensor_module/cam_cci/cam_cci_dev.c | 3 +-- drivers/cam_sensor_module/cam_cci/cam_cci_dev.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 21ef008a7137..c949608d183e 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -429,8 +429,7 @@ static int cam_cci_platform_probe(struct platform_device *pdev) sizeof(new_cci_dev->device_name)); new_cci_dev->v4l2_dev_str.name = new_cci_dev->device_name; - new_cci_dev->v4l2_dev_str.sd_flags = - (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + new_cci_dev->v4l2_dev_str.sd_flags = V4L2_SUBDEV_FL_HAS_EVENTS; new_cci_dev->v4l2_dev_str.ent_function = CAM_CCI_DEVICE_TYPE; new_cci_dev->v4l2_dev_str.token = diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index d65f5e5fd271..caa9be1a3be3 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_DEV_H_ @@ -298,6 +298,6 @@ irqreturn_t cam_cci_irq(int irq_num, void *data); struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); #define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl) #endif /* _CAM_CCI_DEV_H_ */ -- GitLab From 2a26f41c30f96c9c05f3047997442394494040b4 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 8 Jul 2020 16:06:40 -0700 Subject: [PATCH 323/410] msm: camera: req_mgr: Remove unwanted v4l2 operation CCI hardware is no longer register as device node with v4l2 layer. At time of notify message, there is missing check to read subdev name, which cause the null pointer issue. This change removes the sudbev node reading operation with devnode pointer as it is not being use anywhere in functionality. CRs-Fixed: 2702760, 2727771 Change-Id: Id362bd2edf4eea35f05115ae3a5b6c1d761bb437 Signed-off-by: Jigarkumar Zala --- drivers/cam_req_mgr/cam_req_mgr_dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 6e0c406ca482..81693e0d9d9e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -651,7 +651,6 @@ void cam_subdev_notify_message(u32 subdev_type, struct cam_subdev *csd = NULL; list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { - sd->entity.name = video_device_node_name(sd->devnode); if (sd->entity.function == subdev_type) { csd = container_of(sd, struct cam_subdev, sd); if (csd->msg_cb != NULL) -- GitLab From 3f6c968e738f23298e2b62fad0f0e7e88fa61276 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Fri, 17 Jul 2020 11:19:10 +0530 Subject: [PATCH 324/410] msm: camera: csiphy: Add concurrent DPHY-DPHY combo support Add support for concurrent DPHY-DPHY combo-mode operation in the CSIPHY KMD driver. CRs-Fixed: 2736507 Change-Id: Id65d0964e91286f69fea05a5d4df025af93d3f06 Signed-off-by: Shravan Nevatia --- .../cam_csiphy/cam_csiphy_core.c | 763 ++++++++++++------ .../cam_csiphy/cam_csiphy_dev.c | 25 +- .../cam_csiphy/cam_csiphy_dev.h | 145 ++-- .../cam_csiphy/cam_csiphy_soc.c | 22 +- .../cam_csiphy/cam_csiphy_soc.h | 3 +- 5 files changed, 614 insertions(+), 344 deletions(-) diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 8d4bbd80852a..c091c3e5cef3 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -33,25 +33,20 @@ static int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, { struct scm_desc desc = {0}; - if (offset >= CSIPHY_MAX_INSTANCES) { + if (offset >= CSIPHY_MAX_INSTANCES_PER_PHY) { CAM_ERR(CAM_CSIPHY, "Invalid CSIPHY offset"); return -EINVAL; } desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); desc.args[0] = protect; - desc.args[1] = csiphy_dev->csiphy_cpas_cp_reg_mask[offset]; + desc.args[1] = csiphy_dev->csiphy_info[offset].csiphy_cpas_cp_reg_mask; if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID_2), &desc)) { CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed"); return -EINVAL; } - CAM_INFO(CAM_CSIPHY, "PHY : %d offset: %d SEC: %d Mask: %d", - csiphy_dev->soc_info.index, - offset, - protect, - csiphy_dev->csiphy_cpas_cp_reg_mask[offset]); return 0; } @@ -60,17 +55,21 @@ int32_t cam_csiphy_get_instance_offset( struct csiphy_device *csiphy_dev, int32_t dev_handle) { - int32_t i; + int32_t i = 0; - if (csiphy_dev->acquire_count > - CSIPHY_MAX_INSTANCES) { - CAM_ERR(CAM_CSIPHY, "Invalid acquire count"); + if ((csiphy_dev->acquire_count > + csiphy_dev->session_max_device_support) || + (csiphy_dev->acquire_count < 0)) { + CAM_ERR(CAM_CSIPHY, + "Invalid acquire count: %d, Max supported device for session: %u", + csiphy_dev->acquire_count, + csiphy_dev->session_max_device_support); return -EINVAL; } for (i = 0; i < csiphy_dev->acquire_count; i++) { if (dev_handle == - csiphy_dev->bridge_intf.device_hdl[i]) + csiphy_dev->csiphy_info[i].hdl_data.device_hdl) break; } @@ -110,57 +109,114 @@ void cam_csiphy_reset(struct csiphy_device *csiphy_dev) } int32_t cam_csiphy_update_secure_info( - struct csiphy_device *csiphy_dev, - struct cam_csiphy_info *cam_cmd_csiphy_info, - struct cam_config_dev_cmd *cfg_dev) + struct csiphy_device *csiphy_dev, int32_t index) { - uint32_t clock_lane, adj_lane_mask, temp; - int32_t offset; + uint32_t adj_lane_mask = 0; + uint16_t lane_assign = 0; + uint8_t lane_cnt = 0; - if (csiphy_dev->acquire_count >= - CSIPHY_MAX_INSTANCES) { - CAM_ERR(CAM_CSIPHY, "Invalid acquire count"); - return -EINVAL; - } - - offset = cam_csiphy_get_instance_offset(csiphy_dev, - cfg_dev->dev_handle); - if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { - CAM_ERR(CAM_CSIPHY, "Invalid offset"); - return -EINVAL; - } + lane_assign = csiphy_dev->csiphy_info[index].lane_assign; + lane_cnt = csiphy_dev->csiphy_info[index].lane_cnt; - if (cam_cmd_csiphy_info->combo_mode) - clock_lane = - csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_combo_ck_ln; - else - clock_lane = - csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_clock_lane; - - adj_lane_mask = cam_cmd_csiphy_info->lane_mask & LANE_MASK_2PH & - ~clock_lane; - temp = adj_lane_mask & (clock_lane - 1); - adj_lane_mask = - ((adj_lane_mask & (~(clock_lane - 1))) >> 1) | temp; - - if (cam_cmd_csiphy_info->csiphy_3phase) - adj_lane_mask = cam_cmd_csiphy_info->lane_mask & LANE_MASK_3PH; + while (lane_cnt--) { + if ((lane_assign & 0xF) == 0x0) + adj_lane_mask |= 0x1; + else + adj_lane_mask |= (1 << (lane_assign & 0xF)); - csiphy_dev->csiphy_info.secure_mode[offset] = 1; + lane_assign >>= 4; + } - csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = + /* Logic to identify the secure bit */ + csiphy_dev->csiphy_info[index].csiphy_cpas_cp_reg_mask = adj_lane_mask << (csiphy_dev->soc_info.index * (CAM_CSIPHY_MAX_DPHY_LANES + CAM_CSIPHY_MAX_CPHY_LANES) + - (!cam_cmd_csiphy_info->csiphy_3phase) * + (!csiphy_dev->csiphy_info[index].csiphy_3phase) * (CAM_CSIPHY_MAX_CPHY_LANES)); + CAM_DBG(CAM_CSIPHY, "csi phy idx:%d, cp_reg_mask:0x%lx", + csiphy_dev->soc_info.index, + csiphy_dev->csiphy_info[index].csiphy_cpas_cp_reg_mask); + return 0; } +static int cam_csiphy_get_lane_enable( + struct csiphy_device *csiphy, int index, uint32_t *lane_enable) +{ + uint32_t lane_select = 0; + uint16_t lane_assign = csiphy->csiphy_info[index].lane_assign; + uint8_t lane_cnt = csiphy->csiphy_info[index].lane_cnt; + int rc = 0; + + while (lane_cnt--) { + if (csiphy->csiphy_info[index].csiphy_3phase) { + switch (lane_assign & 0xF) { + case 0x0: + lane_select |= CPHY_LANE_0; + break; + case 0x1: + lane_select |= CPHY_LANE_1; + break; + case 0x2: + lane_select |= CPHY_LANE_2; + break; + default: + CAM_ERR(CAM_CSIPHY, + "Wrong lane configuration for CPHY : %d", + lane_assign); + *lane_enable = 0; + return -EINVAL; + } + } else { + switch (lane_assign & 0xF) { + case 0x0: + lane_select |= DPHY_LANE_0; + lane_select |= DPHY_CLK_LN; + break; + case 0x1: + lane_select |= DPHY_LANE_1; + lane_select |= DPHY_CLK_LN; + break; + case 0x2: + lane_select |= DPHY_LANE_2; + if (csiphy->combo_mode) + lane_select |= DPHY_LANE_3; + else + lane_select |= DPHY_CLK_LN; + break; + case 0x3: + if (csiphy->combo_mode) { + CAM_ERR(CAM_CSIPHY, + "Wrong lane configuration for DPHYCombo: %d", + lane_assign); + *lane_enable = 0; + return -EINVAL; + } + lane_select |= DPHY_LANE_3; + lane_select |= DPHY_CLK_LN; + break; + default: + CAM_ERR(CAM_CSIPHY, + "Wrong lane configuration for DPHY: %d", + lane_assign); + *lane_enable = 0; + return -EINVAL; + } + } + lane_assign >>= 4; + } + + CAM_DBG(CAM_CSIPHY, "Lane_enable: 0x%x", lane_enable); + *lane_enable = lane_select; + + return rc; +} + int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, struct cam_config_dev_cmd *cfg_dev) { - int32_t rc = 0; + int rc = 0; uintptr_t generic_ptr; uintptr_t generic_pkt_ptr; struct cam_packet *csl_packet = NULL; @@ -169,6 +225,8 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, struct cam_csiphy_info *cam_cmd_csiphy_info = NULL; size_t len; size_t remain_len; + int index; + uint32_t lane_enable = 0; if (!cfg_dev || !csiphy_dev) { CAM_ERR(CAM_CSIPHY, "Invalid Args"); @@ -227,29 +285,82 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, cmd_buf += cmd_desc->offset / 4; cam_cmd_csiphy_info = (struct cam_csiphy_info *)cmd_buf; - csiphy_dev->config_count++; - csiphy_dev->csiphy_info.lane_cnt += cam_cmd_csiphy_info->lane_cnt; - csiphy_dev->csiphy_info.lane_mask |= cam_cmd_csiphy_info->lane_mask; - csiphy_dev->csiphy_info.csiphy_3phase = - cam_cmd_csiphy_info->csiphy_3phase; - csiphy_dev->csiphy_info.combo_mode |= cam_cmd_csiphy_info->combo_mode; - if (cam_cmd_csiphy_info->combo_mode == 1) { - csiphy_dev->csiphy_info.settle_time_combo_sensor = - cam_cmd_csiphy_info->settle_time; - csiphy_dev->csiphy_info.data_rate_combo_sensor = - cam_cmd_csiphy_info->data_rate; - } else { - csiphy_dev->csiphy_info.settle_time = - cam_cmd_csiphy_info->settle_time; - csiphy_dev->csiphy_info.data_rate = - cam_cmd_csiphy_info->data_rate; + index = cam_csiphy_get_instance_offset(csiphy_dev, cfg_dev->dev_handle); + if (index < 0 || index >= csiphy_dev->session_max_device_support) { + CAM_ERR(CAM_CSIPHY, "index is invalid: %d", index); + return -EINVAL; } - csiphy_dev->csiphy_info.mipi_flags = + + csiphy_dev->csiphy_info[index].lane_cnt = cam_cmd_csiphy_info->lane_cnt; + csiphy_dev->csiphy_info[index].lane_assign = + cam_cmd_csiphy_info->lane_assign; + + csiphy_dev->csiphy_info[index].settle_time = + cam_cmd_csiphy_info->settle_time; + csiphy_dev->csiphy_info[index].data_rate = + cam_cmd_csiphy_info->data_rate; + csiphy_dev->csiphy_info[index].secure_mode = + cam_cmd_csiphy_info->secure_mode; + csiphy_dev->csiphy_info[index].mipi_flags = cam_cmd_csiphy_info->mipi_flags; + csiphy_dev->csiphy_info[index].csiphy_3phase = + cam_cmd_csiphy_info->csiphy_3phase; + + rc = cam_csiphy_get_lane_enable(csiphy_dev, index, &lane_enable); + if (rc) { + CAM_ERR(CAM_CSIPHY, "Wrong lane configuration: %d", + csiphy_dev->csiphy_info[index].lane_assign); + if (csiphy_dev->combo_mode) { + CAM_DBG(CAM_CSIPHY, + "Resetting error to zero for other devices to configure"); + rc = 0; + } + lane_enable = 0; + csiphy_dev->csiphy_info[index].lane_enable = lane_enable; + goto reset_settings; + } + + csiphy_dev->csiphy_info[index].lane_enable = lane_enable; if (cam_cmd_csiphy_info->secure_mode == 1) cam_csiphy_update_secure_info(csiphy_dev, - cam_cmd_csiphy_info, cfg_dev); + index); + + csiphy_dev->config_count++; + + CAM_DBG(CAM_CSIPHY, + "phy version:%d, phy_idx: %d", + csiphy_dev->hw_version, + csiphy_dev->soc_info.index); + CAM_DBG(CAM_CSIPHY, + "phy_idx: %d, 3phase:%d, combo mode:%d, secure mode:%d", + csiphy_dev->soc_info.index, + csiphy_dev->csiphy_info[index].csiphy_3phase, + csiphy_dev->combo_mode, + cam_cmd_csiphy_info->secure_mode); + CAM_DBG(CAM_CSIPHY, + "lane_cnt: 0x%x, lane_assign: 0x%x, lane_enable: 0x%x", + csiphy_dev->csiphy_info[index].lane_cnt, + csiphy_dev->csiphy_info[index].lane_assign, + csiphy_dev->csiphy_info[index].lane_enable); + + CAM_DBG(CAM_CSIPHY, + "settle time:%llu, datarate:%llu, mipi flags: 0x%x", + csiphy_dev->csiphy_info[index].settle_time, + csiphy_dev->csiphy_info[index].data_rate, + csiphy_dev->csiphy_info[index].mipi_flags); + + return rc; + +reset_settings: + csiphy_dev->csiphy_info[index].lane_cnt = 0; + csiphy_dev->csiphy_info[index].lane_assign = 0; + csiphy_dev->csiphy_info[index].lane_enable = 0; + csiphy_dev->csiphy_info[index].settle_time = 0; + csiphy_dev->csiphy_info[index].data_rate = 0; + csiphy_dev->csiphy_info[index].mipi_flags = 0; + csiphy_dev->csiphy_info[index].secure_mode = 0; + csiphy_dev->csiphy_info[index].hdl_data.device_hdl = -1; return rc; } @@ -267,7 +378,8 @@ void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev) csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_addr); } -void cam_csiphy_cphy_data_rate_config(struct csiphy_device *csiphy_device) +static void cam_csiphy_cphy_data_rate_config( + struct csiphy_device *csiphy_device, int32_t idx) { int i = 0, j = 0; uint64_t phy_data_rate = 0; @@ -283,7 +395,7 @@ void cam_csiphy_cphy_data_rate_config(struct csiphy_device *csiphy_device) return; } - phy_data_rate = csiphy_device->csiphy_info.data_rate; + phy_data_rate = csiphy_device->csiphy_info[idx].data_rate; csiphybase = csiphy_device->soc_info.reg_map[0].mem_base; settings_table = @@ -376,82 +488,100 @@ irqreturn_t cam_csiphy_irq(int irq_num, void *data) return IRQ_HANDLED; } -int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) +int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev, + int32_t dev_handle) { int32_t rc = 0; - uint32_t lane_enable = 0, mask = 1, size = 0; - uint16_t lane_mask = 0, i = 0, cfg_size = 0, temp = 0; - uint8_t lane_cnt, lane_pos = 0; + uint32_t lane_enable = 0; + uint32_t size = 0; + uint16_t i = 0, cfg_size = 0; + uint16_t lane_assign = 0; + uint8_t lane_cnt; + int max_lanes = 0; uint16_t settle_cnt = 0; uint64_t intermediate_var; uint8_t skew_cal_enable = 0; + uint8_t lane_pos = 0; + int index; void __iomem *csiphybase; struct csiphy_reg_t *csiphy_common_reg = NULL; struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE]; - - lane_cnt = csiphy_dev->csiphy_info.lane_cnt; + bool is_3phase = false; csiphybase = csiphy_dev->soc_info.reg_map[0].mem_base; + CAM_DBG(CAM_CSIPHY, "ENTER"); if (!csiphybase) { CAM_ERR(CAM_CSIPHY, "csiphybase NULL"); return -EINVAL; } - if (!csiphy_dev->csiphy_info.csiphy_3phase) { - if (csiphy_dev->csiphy_info.combo_mode == 1) - reg_array = - csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg; - else - reg_array = - csiphy_dev->ctrl_reg->csiphy_2ph_reg; - csiphy_dev->num_irq_registers = 11; - cfg_size = - csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_config_array_size; - - lane_mask = csiphy_dev->csiphy_info.lane_mask & LANE_MASK_2PH; - for (i = 0; i < MAX_DPHY_DATA_LN; i++) { - if (mask == 0x2) { - if (lane_mask & mask) - lane_enable |= 0x80; - i--; - } else if (lane_mask & mask) { - lane_enable |= 0x1 << (i<<1); - } - mask <<= 1; - } + index = cam_csiphy_get_instance_offset(csiphy_dev, dev_handle); + if (index < 0 || index >= csiphy_dev->session_max_device_support) { + CAM_ERR(CAM_CSIPHY, "index is invalid: %d", index); + return -EINVAL; + } - skew_cal_enable = - csiphy_dev->csiphy_info.mipi_flags & SKEW_CAL_MASK; - } else { - if (csiphy_dev->csiphy_info.combo_mode == 1) { - if (csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg) - reg_array = - csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg; - else { + CAM_DBG(CAM_CSIPHY, + "Index: %d: expected dev_hdl: 0x%x : derived dev_hdl: 0x%x", + index, dev_handle, + csiphy_dev->csiphy_info[index].hdl_data.device_hdl); + csiphy_dev->num_irq_registers = 11; + + if (csiphy_dev->csiphy_info[index].csiphy_3phase) + is_3phase = true; + + if (csiphy_dev->combo_mode) { + if (is_3phase) { + if (csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg) { + reg_array = csiphy_dev->ctrl_reg + ->csiphy_2ph_3ph_mode_reg; + } else { + CAM_WARN(CAM_CSIPHY, + "CPHY combo mode reg settings not found"); reg_array = csiphy_dev->ctrl_reg->csiphy_3ph_reg; - CAM_ERR(CAM_CSIPHY, - "Unsupported configuration, Falling back to CPHY mode"); } - } else - reg_array = - csiphy_dev->ctrl_reg->csiphy_3ph_reg; - csiphy_dev->num_irq_registers = 11; - cfg_size = - csiphy_dev->ctrl_reg->csiphy_reg.csiphy_3ph_config_array_size; + cfg_size = csiphy_dev->ctrl_reg->csiphy_reg + .csiphy_3ph_config_array_size; + max_lanes = CAM_CSIPHY_MAX_CPHY_LANES; + } else { + /* DPHY combo mode*/ + if (csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg) { + reg_array = csiphy_dev + ->ctrl_reg->csiphy_2ph_combo_mode_reg; + } else { + CAM_WARN(CAM_CSIPHY, + "DPHY combo mode reg settings not found"); + reg_array = csiphy_dev + ->ctrl_reg->csiphy_2ph_reg; + } + cfg_size = csiphy_dev->ctrl_reg->csiphy_reg + .csiphy_2ph_config_array_size; + max_lanes = MAX_LANES; + } - lane_mask = csiphy_dev->csiphy_info.lane_mask & LANE_MASK_3PH; - mask = lane_mask; - while (mask != 0) { - temp = (i << 1)+1; - lane_enable |= ((mask & 0x1) << temp); - mask >>= 1; - i++; + skew_cal_enable = csiphy_dev->csiphy_info[index].mipi_flags & + SKEW_CAL_MASK; + } else { + /* for CPHY(3Phase) or DPHY(2Phase) Non combe mode selection */ + if (is_3phase) { + reg_array = csiphy_dev->ctrl_reg->csiphy_3ph_reg; + max_lanes = CAM_CSIPHY_MAX_CPHY_LANES; + cfg_size = csiphy_dev->ctrl_reg->csiphy_reg + .csiphy_3ph_config_array_size; + } else { + reg_array = csiphy_dev->ctrl_reg->csiphy_2ph_reg; + cfg_size = csiphy_dev->ctrl_reg->csiphy_reg + .csiphy_2ph_config_array_size; + max_lanes = MAX_LANES; } } - size = csiphy_dev->ctrl_reg->csiphy_reg.csiphy_common_array_size; + lane_cnt = csiphy_dev->csiphy_info[index].lane_cnt; + lane_assign = csiphy_dev->csiphy_info[index].lane_assign; + lane_enable = csiphy_dev->csiphy_info[index].lane_enable; + size = csiphy_dev->ctrl_reg->csiphy_reg.csiphy_common_array_size; for (i = 0; i < size; i++) { csiphy_common_reg = &csiphy_dev->ctrl_reg->csiphy_common_reg[i]; switch (csiphy_common_reg->csiphy_param_type) { @@ -468,7 +598,7 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) csiphy_common_reg->delay * 1000 + 10); break; case CSIPHY_2PH_REGS: - if (!csiphy_dev->csiphy_info.csiphy_3phase) { + if (!is_3phase) { cam_io_w_mb(csiphy_common_reg->reg_data, csiphybase + csiphy_common_reg->reg_addr); @@ -477,7 +607,7 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) } break; case CSIPHY_3PH_REGS: - if (csiphy_dev->csiphy_info.csiphy_3phase) { + if (is_3phase) { cam_io_w_mb(csiphy_common_reg->reg_data, csiphybase + csiphy_common_reg->reg_addr); @@ -490,23 +620,12 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) } } - while (lane_mask) { - if (!(lane_mask & 0x1)) { - lane_pos++; - lane_mask >>= 1; - continue; - } + intermediate_var = csiphy_dev->csiphy_info[index].settle_time; + do_div(intermediate_var, 200000000); + settle_cnt = intermediate_var; - intermediate_var = csiphy_dev->csiphy_info.settle_time; - do_div(intermediate_var, 200000000); - settle_cnt = intermediate_var; - if (csiphy_dev->csiphy_info.combo_mode == 1 && - (lane_pos >= 3)) { - intermediate_var = - csiphy_dev->csiphy_info.settle_time_combo_sensor; - do_div(intermediate_var, 200000000); - settle_cnt = intermediate_var; - } + for (lane_pos = 0; lane_pos < max_lanes; lane_pos++) { + CAM_DBG(CAM_CSIPHY, "lane_pos: %d is configuring", lane_pos); for (i = 0; i < cfg_size; i++) { switch (reg_array[lane_pos][i].csiphy_param_type) { case CSIPHY_LANE_ENABLE: @@ -544,12 +663,10 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) reg_array[lane_pos][i].delay*1000 + 10); } } - lane_mask >>= 1; - lane_pos++; } - if (csiphy_dev->csiphy_info.csiphy_3phase) - cam_csiphy_cphy_data_rate_config(csiphy_dev); + if (csiphy_dev->csiphy_info[index].csiphy_3phase) + cam_csiphy_cphy_data_rate_config(csiphy_dev, index); cam_csiphy_cphy_irq_config(csiphy_dev); @@ -564,19 +681,31 @@ void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) return; + if (!csiphy_dev->acquire_count) + return; + + if (csiphy_dev->acquire_count >= CSIPHY_MAX_INSTANCES_PER_PHY) { + CAM_WARN(CAM_CSIPHY, "acquire count is invalid: %u", + csiphy_dev->acquire_count); + csiphy_dev->acquire_count = + CSIPHY_MAX_INSTANCES_PER_PHY; + } + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { soc_info = &csiphy_dev->soc_info; for (i = 0; i < csiphy_dev->acquire_count; i++) { - if (csiphy_dev->csiphy_info.secure_mode[i]) + if (csiphy_dev->csiphy_info[i].secure_mode) cam_csiphy_notify_secure_mode( csiphy_dev, CAM_SECURE_MODE_NON_SECURE, i); - csiphy_dev->csiphy_info.secure_mode[i] = + csiphy_dev->csiphy_info[i].secure_mode = CAM_SECURE_MODE_NON_SECURE; - csiphy_dev->csiphy_cpas_cp_reg_mask[i] = 0; + csiphy_dev->csiphy_info[i].csiphy_cpas_cp_reg_mask = 0; + csiphy_dev->csiphy_info[i].settle_time = 0; + csiphy_dev->csiphy_info[i].data_rate = 0; } cam_csiphy_reset(csiphy_dev); @@ -587,22 +716,18 @@ void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) } if (csiphy_dev->csiphy_state == CAM_CSIPHY_ACQUIRE) { - if (csiphy_dev->bridge_intf.device_hdl[0] != -1) - cam_destroy_device_hdl( - csiphy_dev->bridge_intf.device_hdl[0]); - if (csiphy_dev->bridge_intf.device_hdl[1] != -1) - cam_destroy_device_hdl( - csiphy_dev->bridge_intf.device_hdl[1]); - csiphy_dev->bridge_intf.device_hdl[0] = -1; - csiphy_dev->bridge_intf.device_hdl[1] = -1; - csiphy_dev->bridge_intf.link_hdl[0] = -1; - csiphy_dev->bridge_intf.link_hdl[1] = -1; - csiphy_dev->bridge_intf.session_hdl[0] = -1; - csiphy_dev->bridge_intf.session_hdl[1] = -1; + for (i = 0; i < csiphy_dev->acquire_count; i++) { + if (csiphy_dev->csiphy_info[i].hdl_data.device_hdl + != -1) + cam_destroy_device_hdl( + csiphy_dev->csiphy_info[i] + .hdl_data.device_hdl); + csiphy_dev->csiphy_info[i].hdl_data.device_hdl = -1; + csiphy_dev->csiphy_info[i].hdl_data.session_hdl = -1; + } } csiphy_dev->ref_count = 0; - csiphy_dev->is_acquired_dev_combo_mode = 0; csiphy_dev->acquire_count = 0; csiphy_dev->start_dev_count = 0; csiphy_dev->csiphy_state = CAM_CSIPHY_INIT; @@ -613,6 +738,7 @@ static int32_t cam_csiphy_external_cmd(struct csiphy_device *csiphy_dev, { struct cam_csiphy_info cam_cmd_csiphy_info; int32_t rc = 0; + int32_t index = -1; if (copy_from_user(&cam_cmd_csiphy_info, u64_to_user_ptr(p_submit_cmd->packet_handle), @@ -620,37 +746,91 @@ static int32_t cam_csiphy_external_cmd(struct csiphy_device *csiphy_dev, CAM_ERR(CAM_CSIPHY, "failed to copy cam_csiphy_info\n"); rc = -EFAULT; } else { - csiphy_dev->csiphy_info.lane_cnt = - cam_cmd_csiphy_info.lane_cnt; - csiphy_dev->csiphy_info.lane_cnt = + index = cam_csiphy_get_instance_offset(csiphy_dev, + p_submit_cmd->dev_handle); + if (index < 0 || + index >= csiphy_dev->session_max_device_support) { + CAM_ERR(CAM_CSIPHY, "index is invalid: %d", index); + return -EINVAL; + } + + csiphy_dev->csiphy_info[index].lane_cnt = cam_cmd_csiphy_info.lane_cnt; - csiphy_dev->csiphy_info.lane_mask = - cam_cmd_csiphy_info.lane_mask; - csiphy_dev->csiphy_info.csiphy_3phase = + csiphy_dev->csiphy_info[index].lane_assign = + cam_cmd_csiphy_info.lane_assign; + csiphy_dev->csiphy_info[index].csiphy_3phase = cam_cmd_csiphy_info.csiphy_3phase; - csiphy_dev->csiphy_info.combo_mode = + csiphy_dev->combo_mode = cam_cmd_csiphy_info.combo_mode; - csiphy_dev->csiphy_info.settle_time = + csiphy_dev->csiphy_info[index].settle_time = cam_cmd_csiphy_info.settle_time; - csiphy_dev->csiphy_info.data_rate = + csiphy_dev->csiphy_info[index].data_rate = cam_cmd_csiphy_info.data_rate; CAM_DBG(CAM_CSIPHY, - "%s CONFIG_DEV_EXT settle_time= %lld lane_cnt=%d lane_mask=0x%x", + "%s CONFIG_DEV_EXT settle_time= %lld lane_cnt=%d", __func__, - csiphy_dev->csiphy_info.settle_time, - csiphy_dev->csiphy_info.lane_cnt, - csiphy_dev->csiphy_info.lane_mask); + csiphy_dev->csiphy_info[index].settle_time, + csiphy_dev->csiphy_info[index].lane_cnt); } return rc; } +static int cam_csiphy_update_lane( + struct csiphy_device *csiphy, int index, bool enable) +{ + int i = 0; + uint32_t lane_enable = 0; + uint32_t size = 0; + uint16_t lane_assign; + void __iomem *base_address; + struct csiphy_reg_t *csiphy_common_reg = NULL; + + base_address = csiphy->soc_info.reg_map[0].mem_base; + size = csiphy->ctrl_reg->csiphy_reg.csiphy_common_array_size; + + for (i = 0; i < size; i++) { + csiphy_common_reg = &csiphy->ctrl_reg->csiphy_common_reg[i]; + switch (csiphy_common_reg->csiphy_param_type) { + case CSIPHY_LANE_ENABLE: + CAM_DBG(CAM_CSIPHY, "LANE_ENABLE: %d", lane_enable); + lane_enable = cam_io_r(base_address + + csiphy_common_reg->reg_addr); + break; + } + } + + lane_assign = csiphy->csiphy_info[index].lane_assign; + + if (enable) + lane_enable |= csiphy->csiphy_info[index].lane_enable; + else + lane_enable &= ~csiphy->csiphy_info[index].lane_enable; + + CAM_DBG(CAM_CSIPHY, "lane_assign: 0x%x, lane_enable: 0x%x", + lane_assign, lane_enable); + for (i = 0; i < size; i++) { + csiphy_common_reg = &csiphy->ctrl_reg->csiphy_common_reg[i]; + switch (csiphy_common_reg->csiphy_param_type) { + case CSIPHY_LANE_ENABLE: + CAM_DBG(CAM_CSIPHY, "LANE_ENABLE: %d", lane_enable); + cam_io_w_mb(lane_enable, + base_address + csiphy_common_reg->reg_addr); + if (csiphy_common_reg->delay) + usleep_range(csiphy_common_reg->delay, + csiphy_common_reg->delay + 5); + break; + } + } + + return 0; +} + int32_t cam_csiphy_core_cfg(void *phy_dev, void *arg) { struct csiphy_device *csiphy_dev = (struct csiphy_device *)phy_dev; - struct intf_params *bridge_intf = NULL; struct cam_control *cmd = (struct cam_control *)arg; int32_t rc = 0; @@ -671,13 +851,28 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, case CAM_ACQUIRE_DEV: { struct cam_sensor_acquire_dev csiphy_acq_dev; struct cam_csiphy_acquire_dev_info csiphy_acq_params; - + int index; struct cam_create_dev_hdl bridge_params; - if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + CAM_DBG(CAM_CSIPHY, "ACQUIRE_CNT: %d COMBO_MODE: %d", + csiphy_dev->acquire_count, + csiphy_dev->combo_mode); + if ((csiphy_dev->csiphy_state == CAM_CSIPHY_START) && + (csiphy_dev->combo_mode == 0) && + (csiphy_dev->acquire_count > 0)) { CAM_ERR(CAM_CSIPHY, - "Not in right state to acquire : %d", - csiphy_dev->csiphy_state); + "NonComboMode does not support multiple acquire: Acquire_count: %d", + csiphy_dev->acquire_count); + rc = -EINVAL; + goto release_mutex; + } + + if ((csiphy_dev->acquire_count) && + (csiphy_dev->acquire_count >= + csiphy_dev->session_max_device_support)) { + CAM_ERR(CAM_CSIPHY, + "Max acquires are allowed in combo mode: %d", + csiphy_dev->session_max_device_support); rc = -EINVAL; goto release_mutex; } @@ -700,32 +895,16 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } - if (csiphy_dev->acquire_count == 2) { - CAM_ERR(CAM_CSIPHY, - "CSIPHY device do not allow more than 2 acquires"); - rc = -EINVAL; - goto release_mutex; + if (csiphy_acq_params.combo_mode == 1) { + CAM_DBG(CAM_CSIPHY, "combo mode stream detected"); + csiphy_dev->combo_mode = 1; + csiphy_dev->session_max_device_support = + CSIPHY_MAX_INSTANCES_PER_PHY; } - if ((csiphy_acq_params.combo_mode == 1) && - (csiphy_dev->is_acquired_dev_combo_mode == 1)) { - CAM_ERR(CAM_CSIPHY, - "Multiple Combo Acq are not allowed: cm: %d, acm: %d", - csiphy_acq_params.combo_mode, - csiphy_dev->is_acquired_dev_combo_mode); - rc = -EINVAL; - goto release_mutex; - } - - if ((csiphy_acq_params.combo_mode != 1) && - (csiphy_dev->is_acquired_dev_combo_mode != 1) && - (csiphy_dev->acquire_count == 1)) { - CAM_ERR(CAM_CSIPHY, - "Multiple Acquires are not allowed cm: %d acm: %d", - csiphy_acq_params.combo_mode, - csiphy_dev->is_acquired_dev_combo_mode); - rc = -EINVAL; - goto release_mutex; + if (!csiphy_acq_params.combo_mode) { + CAM_DBG(CAM_CSIPHY, "Non Combo Mode stream"); + csiphy_dev->session_max_device_support = 1; } bridge_params.ops = NULL; @@ -733,22 +912,17 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, bridge_params.v4l2_sub_dev_flag = 0; bridge_params.media_entity_flag = 0; bridge_params.priv = csiphy_dev; - - if (csiphy_acq_params.combo_mode >= 2) { - CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d", - csiphy_acq_params.combo_mode); - rc = -EINVAL; - goto release_mutex; - } - + index = csiphy_dev->acquire_count; csiphy_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); - bridge_intf = &csiphy_dev->bridge_intf; - bridge_intf->device_hdl[csiphy_acq_params.combo_mode] - = csiphy_acq_dev.device_handle; - bridge_intf->session_hdl[csiphy_acq_params.combo_mode] = + csiphy_dev->csiphy_info[index].hdl_data.device_hdl = + csiphy_acq_dev.device_handle; + csiphy_dev->csiphy_info[index].hdl_data.session_hdl = csiphy_acq_dev.session_handle; + CAM_DBG(CAM_CSIPHY, "Add dev_handle:0x%x at index: %d ", + csiphy_dev->csiphy_info[index].hdl_data.device_hdl, + index); if (copy_to_user(u64_to_user_ptr(cmd->handle), &csiphy_acq_dev, sizeof(struct cam_sensor_acquire_dev))) { @@ -756,11 +930,12 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, rc = -EINVAL; goto release_mutex; } - if (csiphy_acq_params.combo_mode == 1) - csiphy_dev->is_acquired_dev_combo_mode = 1; csiphy_dev->acquire_count++; - csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; + CAM_DBG(CAM_CSIPHY, "ACQUIRE_CNT: %d", + csiphy_dev->acquire_count); + if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; } break; case CAM_QUERY_CAP: { @@ -786,8 +961,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } - if ((csiphy_dev->csiphy_state != CAM_CSIPHY_START) || - !csiphy_dev->start_dev_count) { + if (csiphy_dev->csiphy_state != CAM_CSIPHY_START) { CAM_ERR(CAM_CSIPHY, "Not in right state to stop : %d", csiphy_dev->csiphy_state); goto release_mutex; @@ -795,35 +969,44 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, offset = cam_csiphy_get_instance_offset(csiphy_dev, config.dev_handle); - if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { - CAM_ERR(CAM_CSIPHY, "Invalid offset"); + if (offset < 0 || + offset >= csiphy_dev->session_max_device_support) { + CAM_ERR(CAM_CSIPHY, "Index is invalid: %d", offset); goto release_mutex; } + CAM_INFO(CAM_CSIPHY, + "STOP_DEV: CSIPHY_IDX: %d, Device_slot: %d, Datarate: %llu, Settletime: %llu", + csiphy_dev->soc_info.index, offset, + csiphy_dev->csiphy_info[offset].data_rate, + csiphy_dev->csiphy_info[offset].settle_time); + if (--csiphy_dev->start_dev_count) { CAM_DBG(CAM_CSIPHY, "Stop Dev ref Cnt: %d", csiphy_dev->start_dev_count); - if (csiphy_dev->csiphy_info.secure_mode[offset]) + if (csiphy_dev->csiphy_info[offset].secure_mode) cam_csiphy_notify_secure_mode( csiphy_dev, CAM_SECURE_MODE_NON_SECURE, offset); - csiphy_dev->csiphy_info.secure_mode[offset] = + csiphy_dev->csiphy_info[offset].secure_mode = CAM_SECURE_MODE_NON_SECURE; - csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0; + csiphy_dev->csiphy_info[offset].csiphy_cpas_cp_reg_mask + = 0; + cam_csiphy_update_lane(csiphy_dev, offset, false); goto release_mutex; } - if (csiphy_dev->csiphy_info.secure_mode[offset]) + if (csiphy_dev->csiphy_info[offset].secure_mode) cam_csiphy_notify_secure_mode( csiphy_dev, CAM_SECURE_MODE_NON_SECURE, offset); - csiphy_dev->csiphy_info.secure_mode[offset] = + csiphy_dev->csiphy_info[offset].secure_mode = CAM_SECURE_MODE_NON_SECURE; - csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0x0; + csiphy_dev->csiphy_info[offset].csiphy_cpas_cp_reg_mask = 0x0; rc = cam_csiphy_disable_hw(csiphy_dev); if (rc < 0) @@ -833,6 +1016,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, if (rc < 0) CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc); + CAM_DBG(CAM_CSIPHY, "All PHY devices stopped"); csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; } break; @@ -855,17 +1039,18 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, offset = cam_csiphy_get_instance_offset(csiphy_dev, release.dev_handle); - if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { - CAM_ERR(CAM_CSIPHY, "Invalid offset"); + if (offset < 0 || + offset >= csiphy_dev->session_max_device_support) { + CAM_ERR(CAM_CSIPHY, "index is invalid: %d", offset); goto release_mutex; } - if (csiphy_dev->csiphy_info.secure_mode[offset]) + if (csiphy_dev->csiphy_info[offset].secure_mode) cam_csiphy_notify_secure_mode( csiphy_dev, CAM_SECURE_MODE_NON_SECURE, offset); - csiphy_dev->csiphy_info.secure_mode[offset] = + csiphy_dev->csiphy_info[offset].secure_mode = CAM_SECURE_MODE_NON_SECURE; csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0x0; @@ -873,32 +1058,29 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, rc = cam_destroy_device_hdl(release.dev_handle); if (rc < 0) CAM_ERR(CAM_CSIPHY, "destroying the device hdl"); - if (release.dev_handle == - csiphy_dev->bridge_intf.device_hdl[0]) { - csiphy_dev->bridge_intf.device_hdl[0] = -1; - csiphy_dev->bridge_intf.link_hdl[0] = -1; - csiphy_dev->bridge_intf.session_hdl[0] = -1; - } else { - csiphy_dev->bridge_intf.device_hdl[1] = -1; - csiphy_dev->bridge_intf.link_hdl[1] = -1; - csiphy_dev->bridge_intf.session_hdl[1] = -1; - csiphy_dev->is_acquired_dev_combo_mode = 0; - } + csiphy_dev->csiphy_info[offset].hdl_data.device_hdl = -1; + csiphy_dev->csiphy_info[offset].hdl_data.session_hdl = -1; csiphy_dev->config_count--; - csiphy_dev->acquire_count--; + if (csiphy_dev->acquire_count) { + csiphy_dev->acquire_count--; + CAM_DBG(CAM_CSIPHY, "Acquire_cnt: %d", + csiphy_dev->acquire_count); + } - if (csiphy_dev->acquire_count == 0) + if (csiphy_dev->start_dev_count == 0) { + CAM_DBG(CAM_CSIPHY, "All PHY devices released"); csiphy_dev->csiphy_state = CAM_CSIPHY_INIT; - + } if (csiphy_dev->config_count == 0) { CAM_DBG(CAM_CSIPHY, "reset csiphy_info"); - csiphy_dev->csiphy_info.lane_mask = 0; - csiphy_dev->csiphy_info.lane_cnt = 0; - csiphy_dev->csiphy_info.combo_mode = 0; + csiphy_dev->csiphy_info[offset].lane_cnt = 0; + csiphy_dev->csiphy_info[offset].lane_assign = 0; + csiphy_dev->csiphy_info[offset].csiphy_3phase = -1; + csiphy_dev->combo_mode = 0; } - } break; + } case CAM_CONFIG_DEV: { struct cam_config_dev_cmd config; @@ -920,6 +1102,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, struct cam_axi_vote axi_vote = {0}; struct cam_start_stop_dev_cmd config; int32_t offset; + int clk_vote_level = -1; rc = copy_from_user(&config, (void __user *)cmd->handle, sizeof(config)); @@ -928,18 +1111,86 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } - if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { - csiphy_dev->start_dev_count++; + if ((csiphy_dev->csiphy_state == CAM_CSIPHY_START) && + (csiphy_dev->start_dev_count > + csiphy_dev->session_max_device_support)) { + CAM_ERR(CAM_CSIPHY, + "Invalid start count: %d, Max supported devices: %u", + csiphy_dev->start_dev_count, + csiphy_dev->session_max_device_support); + rc = -EINVAL; goto release_mutex; } offset = cam_csiphy_get_instance_offset(csiphy_dev, config.dev_handle); - if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { - CAM_ERR(CAM_CSIPHY, "Invalid offset"); + if (offset < 0 || + offset >= csiphy_dev->session_max_device_support) { + CAM_ERR(CAM_CSIPHY, "index is invalid: %d", offset); + goto release_mutex; + } + + CAM_INFO(CAM_CSIPHY, + "START_DEV: CSIPHY_IDX: %d, Device_slot: %d, Datarate: %llu, Settletime: %llu", + csiphy_dev->soc_info.index, offset, + csiphy_dev->csiphy_info[offset].data_rate, + csiphy_dev->csiphy_info[offset].settle_time); + + if (csiphy_dev->start_dev_count) { + clk_vote_level = + csiphy_dev->ctrl_reg->getclockvoting( + csiphy_dev, offset); + rc = cam_soc_util_set_clk_rate_level( + &csiphy_dev->soc_info, clk_vote_level); + if (rc) { + CAM_WARN(CAM_CSIPHY, + "Failed to set the clk_rate level: %d", + clk_vote_level); + rc = 0; + } + + if (csiphy_dev->csiphy_info[offset].secure_mode == 1) { + if (cam_cpas_is_feature_supported( + CAM_CPAS_SECURE_CAMERA_ENABLE) != 1) { + CAM_WARN(CAM_CSIPHY, + "sec_cam: camera fuse bit not set"); + rc = 0; + goto release_mutex; + } + + rc = cam_csiphy_notify_secure_mode(csiphy_dev, + CAM_SECURE_MODE_SECURE, offset); + if (rc < 0) { + csiphy_dev->csiphy_info[offset] + .secure_mode = + CAM_SECURE_MODE_NON_SECURE; + CAM_WARN(CAM_CSIPHY, + "sec_cam: notify failed: rc: %d", + rc); + rc = 0; + goto release_mutex; + } + } + if (csiphy_dev->csiphy_info[offset].csiphy_3phase) + cam_csiphy_cphy_data_rate_config( + csiphy_dev, offset); + + rc = cam_csiphy_update_lane(csiphy_dev, offset, true); + if (csiphy_dump == 1) + cam_csiphy_mem_dmp(&csiphy_dev->soc_info); + if (rc) { + CAM_WARN(CAM_CSIPHY, + "csiphy_config_dev failed"); + goto release_mutex; + } + + csiphy_dev->start_dev_count++; goto release_mutex; } + CAM_DBG(CAM_CSIPHY, "Start_dev_cnt: %d", + csiphy_dev->start_dev_count); + ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; @@ -956,7 +1207,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } - if (csiphy_dev->csiphy_info.secure_mode[offset] == 1) { + if (csiphy_dev->csiphy_info[offset].secure_mode == 1) { if (cam_cpas_is_feature_supported( CAM_CPAS_SECURE_CAMERA_ENABLE) != 1) { CAM_ERR(CAM_CSIPHY, @@ -970,20 +1221,20 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_dev, CAM_SECURE_MODE_SECURE, offset); if (rc < 0) { - csiphy_dev->csiphy_info.secure_mode[offset] = + csiphy_dev->csiphy_info[offset].secure_mode = CAM_SECURE_MODE_NON_SECURE; cam_cpas_stop(csiphy_dev->cpas_handle); goto release_mutex; } } - rc = cam_csiphy_enable_hw(csiphy_dev); + rc = cam_csiphy_enable_hw(csiphy_dev, offset); if (rc != 0) { CAM_ERR(CAM_CSIPHY, "cam_csiphy_enable_hw failed"); cam_cpas_stop(csiphy_dev->cpas_handle); goto release_mutex; } - rc = cam_csiphy_config_dev(csiphy_dev); + rc = cam_csiphy_config_dev(csiphy_dev, config.dev_handle); if (csiphy_dump == 1) cam_csiphy_mem_dmp(&csiphy_dev->soc_info); @@ -994,6 +1245,8 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } csiphy_dev->start_dev_count++; + CAM_DBG(CAM_CSIPHY, "START DEV CNT: %d", + csiphy_dev->start_dev_count); csiphy_dev->csiphy_state = CAM_CSIPHY_START; } break; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index d127a70a7b7f..0d031e430db7 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -156,6 +156,7 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) struct cam_cpas_register_params cpas_parms; struct csiphy_device *new_csiphy_dev; int32_t rc = 0; + int i; new_csiphy_dev = devm_kzalloc(&pdev->dev, sizeof(struct csiphy_device), GFP_KERNEL); @@ -208,18 +209,24 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &(new_csiphy_dev->v4l2_dev_str.sd)); - new_csiphy_dev->bridge_intf.device_hdl[0] = -1; - new_csiphy_dev->bridge_intf.device_hdl[1] = -1; - new_csiphy_dev->bridge_intf.ops.get_dev_info = - NULL; - new_csiphy_dev->bridge_intf.ops.link_setup = - NULL; - new_csiphy_dev->bridge_intf.ops.apply_req = - NULL; + for (i = 0; i < CSIPHY_MAX_INSTANCES_PER_PHY; i++) { + new_csiphy_dev->csiphy_info[i].hdl_data.device_hdl = -1; + new_csiphy_dev->csiphy_info[i].hdl_data.session_hdl = -1; + new_csiphy_dev->csiphy_info[i].csiphy_3phase = -1; + new_csiphy_dev->csiphy_info[i].data_rate = 0; + new_csiphy_dev->csiphy_info[i].settle_time = 0; + new_csiphy_dev->csiphy_info[i].lane_cnt = 0; + new_csiphy_dev->csiphy_info[i].lane_assign = 0; + new_csiphy_dev->csiphy_info[i].lane_enable = 0; + new_csiphy_dev->csiphy_info[i].mipi_flags = 0; + } + + new_csiphy_dev->ops.get_dev_info = NULL; + new_csiphy_dev->ops.link_setup = NULL; + new_csiphy_dev->ops.apply_req = NULL; new_csiphy_dev->acquire_count = 0; new_csiphy_dev->start_dev_count = 0; - new_csiphy_dev->is_acquired_dev_combo_mode = 0; new_csiphy_dev->open_cnt = 0; cpas_parms.cam_cpas_client_cb = NULL; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 76bfc441b060..bd2037df863f 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -29,7 +29,7 @@ #include "cam_context.h" #define MAX_CSIPHY 6 -#define MAX_DPHY_DATA_LN 4 + #define MAX_LRME_V4l2_EVENTS 30 #define CSIPHY_NUM_CLK_MAX 16 #define MAX_CSIPHY_REG_ARRAY 70 @@ -55,7 +55,7 @@ #define CSIPHY_3PH_REGS 6 #define CSIPHY_SKEW_CAL 7 -#define CSIPHY_MAX_INSTANCES 2 +#define CSIPHY_MAX_INSTANCES_PER_PHY 2 #define CAM_CSIPHY_MAX_DPHY_LANES 4 #define CAM_CSIPHY_MAX_CPHY_LANES 3 @@ -69,6 +69,17 @@ #define CDBG(fmt, args...) pr_debug(fmt, ##args) #endif +#define DPHY_LANE_0 BIT(0) +#define CPHY_LANE_0 BIT(1) +#define DPHY_LANE_1 BIT(2) +#define CPHY_LANE_1 BIT(3) +#define DPHY_LANE_2 BIT(4) +#define CPHY_LANE_2 BIT(5) +#define DPHY_LANE_3 BIT(6) +#define DPHY_CLK_LN BIT(7) + + + enum cam_csiphy_state { CAM_CSIPHY_INIT, CAM_CSIPHY_ACQUIRE, @@ -123,24 +134,19 @@ struct csiphy_reg_parms_t { }; /** - * struct intf_params + * struct csiphy_hdl_tbl * @device_hdl: Device Handle * @session_hdl: Session Handle - * @ops: KMD operations - * @crm_cb: Callback API pointers */ -struct intf_params { - int32_t device_hdl[CSIPHY_MAX_INSTANCES]; - int32_t session_hdl[CSIPHY_MAX_INSTANCES]; - int32_t link_hdl[CSIPHY_MAX_INSTANCES]; - struct cam_req_mgr_kmd_ops ops; - struct cam_req_mgr_crm_cb *crm_cb; +struct csiphy_hdl_tbl { + int32_t device_hdl; + int32_t session_hdl; }; /** * struct csiphy_reg_t - * @reg_addr: Register address - * @reg_data: Register data + * @reg_addr: Register address + * @reg_data: Register data * @delay: Delay * @csiphy_param_type: CSIPhy parameter type */ @@ -204,38 +210,34 @@ struct csiphy_ctrl_t { struct csiphy_reg_t (*csiphy_2ph_combo_mode_reg)[MAX_SETTINGS_PER_LANE]; struct csiphy_reg_t (*csiphy_3ph_reg)[MAX_SETTINGS_PER_LANE]; struct csiphy_reg_t (*csiphy_2ph_3ph_mode_reg)[MAX_SETTINGS_PER_LANE]; - enum cam_vote_level (*getclockvoting)(struct csiphy_device *phy_dev); + enum cam_vote_level (*getclockvoting)(struct csiphy_device *phy_dev, + int32_t index); struct data_rate_settings_t *data_rates_settings_table; }; -/** - * cam_csiphy_param: Provides cmdbuffer structre - * @lane_mask : Lane mask details - * @lane_assign : Lane sensor will be using +/* + * cam_csiphy_param : Provides cmdbuffer structure + * @lane_assign : Lane sensor will be using * @csiphy_3phase : Mentions DPHY or CPHY - * @combo_mode : Info regarding combo_mode is enable / disable - * @lane_cnt : Total number of lanes - * @reserved - * @3phase : Details whether 3Phase / 2Phase operation - * @settle_time : Settling time in ms - * @settle_time_combo_sensor : Settling time in ms - * @data_rate : Data rate in mbps - * @data_rate_combo_sensor: data rate of combo sensor - * in the the same phy - * @mipi_flags : Mipi flags + * @lane_cnt : Total number of lanes + * @lane_enable : Data Lane selection + * @settle_time : Settling time in ms + * @data_rate : Data rate in mbps + * @csiphy_cpas_cp_reg_mask : CP reg mask for phy instance + * @hdl_data : CSIPHY handle table + * @mipi_flags : Mipi flags */ struct cam_csiphy_param { - uint16_t lane_mask; - uint16_t lane_assign; - uint8_t csiphy_3phase; - uint8_t combo_mode; - uint8_t lane_cnt; - uint8_t secure_mode[CSIPHY_MAX_INSTANCES]; - uint64_t settle_time; - uint64_t settle_time_combo_sensor; - uint64_t data_rate; - uint64_t data_rate_combo_sensor; - uint32_t mipi_flags; + uint16_t lane_assign; + int csiphy_3phase; + uint8_t lane_cnt; + uint8_t secure_mode; + uint32_t lane_enable; + uint64_t settle_time; + uint64_t data_rate; + uint32_t mipi_flags; + uint64_t csiphy_cpas_cp_reg_mask; + struct csiphy_hdl_tbl hdl_data; }; /** @@ -261,40 +263,47 @@ struct cam_csiphy_param { * @clk_lane: Clock lane * @acquire_count: Acquire device count * @start_dev_count: Start count - * @is_acquired_dev_combo_mode: Flag that mentions whether already acquired - * device is for combo mode * @soc_info: SOC information * @cpas_handle: CPAS handle * @config_count: Config reg count - * @csiphy_cpas_cp_reg_mask: CP reg mask for phy instance + * @current_data_rate: Data rate in mbps + * @csiphy_3phase: To identify DPHY or CPHY at top level + * @combo_mode: Info regarding combo_mode is enable / disable + * @ops: KMD operations + * @crm_cb: Callback API pointers */ struct csiphy_device { - char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; - struct mutex mutex; - uint32_t hw_version; - enum cam_csiphy_state csiphy_state; - struct csiphy_ctrl_t *ctrl_reg; - uint32_t csiphy_max_clk; - struct msm_cam_clk_info csiphy_3p_clk_info[2]; - struct clk *csiphy_3p_clk[2]; - unsigned char csi_3phase; - int32_t ref_count; - uint16_t lane_mask[MAX_CSIPHY]; - uint8_t is_csiphy_3phase_hw; - uint8_t is_divisor_32_comp; - uint8_t num_irq_registers; - struct cam_subdev v4l2_dev_str; - struct cam_csiphy_param csiphy_info; - struct intf_params bridge_intf; - uint32_t clk_lane; - uint32_t acquire_count; - uint32_t start_dev_count; - uint32_t is_acquired_dev_combo_mode; - struct cam_hw_soc_info soc_info; - uint32_t cpas_handle; - uint32_t config_count; - uint32_t open_cnt; - uint64_t csiphy_cpas_cp_reg_mask[CSIPHY_MAX_INSTANCES]; + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + struct mutex mutex; + uint32_t hw_version; + enum cam_csiphy_state csiphy_state; + struct csiphy_ctrl_t *ctrl_reg; + uint32_t csiphy_max_clk; + struct msm_cam_clk_info csiphy_3p_clk_info[2]; + struct clk *csiphy_3p_clk[2]; + unsigned char csi_3phase; + int32_t ref_count; + uint16_t lane_mask[MAX_CSIPHY]; + uint8_t is_csiphy_3phase_hw; + uint8_t is_divisor_32_comp; + uint8_t num_irq_registers; + struct cam_subdev v4l2_dev_str; + struct cam_csiphy_param csiphy_info[ + CSIPHY_MAX_INSTANCES_PER_PHY]; + uint32_t clk_lane; + uint32_t acquire_count; + uint32_t start_dev_count; + struct cam_hw_soc_info soc_info; + uint32_t cpas_handle; + uint32_t config_count; + uint32_t open_cnt; + uint64_t csiphy_cpas_cp_reg_mask[ + CSIPHY_MAX_INSTANCES_PER_PHY]; + uint64_t current_data_rate; + uint8_t session_max_device_support; + uint8_t combo_mode; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; }; #endif /* _CAM_CSIPHY_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index d9e8eb94cfa0..293f1b064a07 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -125,26 +125,25 @@ int32_t cam_csiphy_status_dmp(struct csiphy_device *csiphy_dev) return rc; } -enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev) +enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev, + int32_t index) { CAM_DBG(CAM_CSIPHY, "voting for SVS"); return CAM_SVS_VOTE; } -enum cam_vote_level get_clk_voting_dynamic(struct csiphy_device *csiphy_dev) +enum cam_vote_level get_clk_voting_dynamic( + struct csiphy_device *csiphy_dev, int32_t index) { uint32_t cam_vote_level = 0; uint32_t last_valid_vote = 0; struct cam_hw_soc_info *soc_info; - uint64_t phy_data_rate = csiphy_dev->csiphy_info.data_rate; + uint64_t phy_data_rate = csiphy_dev->csiphy_info[index].data_rate; soc_info = &csiphy_dev->soc_info; + phy_data_rate = max(phy_data_rate, csiphy_dev->current_data_rate); - if (csiphy_dev->is_acquired_dev_combo_mode) - phy_data_rate = max(phy_data_rate, - csiphy_dev->csiphy_info.data_rate_combo_sensor); - - if (csiphy_dev->csiphy_info.csiphy_3phase) { + if (csiphy_dev->csiphy_info[index].csiphy_3phase) { if (csiphy_dev->is_divisor_32_comp) do_div(phy_data_rate, CSIPHY_DIVISOR_32); else @@ -155,6 +154,7 @@ enum cam_vote_level get_clk_voting_dynamic(struct csiphy_device *csiphy_dev) /* round off to next integer */ phy_data_rate += 1; + csiphy_dev->current_data_rate = phy_data_rate; for (cam_vote_level = 0; cam_vote_level < CAM_MAX_VOTE; cam_vote_level++) { @@ -176,7 +176,7 @@ enum cam_vote_level get_clk_voting_dynamic(struct csiphy_device *csiphy_dev) return last_valid_vote; } -int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) +int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev, int32_t index) { int32_t rc = 0; struct cam_hw_soc_info *soc_info; @@ -190,7 +190,7 @@ int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) return rc; } - vote_level = csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev); + vote_level = csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev, index); rc = cam_soc_util_enable_platform_resource(soc_info, true, vote_level, ENABLE_IRQ); if (rc < 0) { @@ -396,7 +396,7 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2_3; csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->is_divisor_32_comp = true; - csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->hw_version = CSIPHY_VERSION_V123; csiphy_dev->clk_lane = 0; csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; } else if (of_device_is_compatible(soc_info->dev->of_node, diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index 561d74293e90..8e727704b4a8 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -30,6 +30,7 @@ #define CSIPHY_VERSION_V11 0x11 #define CSIPHY_VERSION_V12 0x12 #define CSIPHY_VERSION_V121 0x121 +#define CSIPHY_VERSION_V123 0x123 #define CSIPHY_VERSION_V20 0x20 /** @@ -53,7 +54,7 @@ int cam_csiphy_parse_dt_info(struct platform_device *pdev, * * This API enables SOC related parameters */ -int cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev); +int cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev, int32_t index); /** * @csiphy_dev: CSIPhy device structure -- GitLab From dcaaa6cd664e317fbd5b229ebb465b40649f06db Mon Sep 17 00:00:00 2001 From: Wei Tan Date: Fri, 3 Jul 2020 15:03:35 +0800 Subject: [PATCH 325/410] msm: camera: ife: Support max 7 cameras streaming on XR2 Increase IFE usecase and max number of session links to support XR2 multi cameras concurrently stream. CRs-Fixed: 2707698 Change-Id: Iaff18e7320ff230daf33b0b21b742796213427c9 Signed-off-by: Wei Tan --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 4 ++++ drivers/cam_req_mgr/cam_req_mgr_core.h | 2 +- include/uapi/media/cam_isp.h | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index e585ced506f4..dc84e9989e7a 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1335,6 +1335,10 @@ static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx) return CAM_ISP_IFE1_LITE_HW; else if (hw_idx == 4) return CAM_ISP_IFE2_LITE_HW; + else if (hw_idx == 5) + return CAM_ISP_IFE3_LITE_HW; + else if (hw_idx == 6) + return CAM_ISP_IFE4_LITE_HW; break; case CAM_CPAS_TITAN_170_V200: if (hw_idx == 0) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 74e3a2448110..2c6fd738ff0d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -31,7 +31,7 @@ #define SYNC_LINK_SOF_CNT_MAX_LMT 1 -#define MAXIMUM_LINKS_PER_SESSION 4 +#define MAXIMUM_LINKS_PER_SESSION 7 #define MAXIMUM_RETRY_ATTEMPTS 2 diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index b773d17a75a5..408d153e944a 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -113,6 +113,8 @@ #define CAM_ISP_IFE0_LITE_HW 0x4 #define CAM_ISP_IFE1_LITE_HW 0x8 #define CAM_ISP_IFE2_LITE_HW 0x10 +#define CAM_ISP_IFE3_LITE_HW 0x20 +#define CAM_ISP_IFE4_LITE_HW 0x40 #define CAM_ISP_IFE2_HW 0x100 #define CAM_ISP_PXL_PATH 0x1 -- GitLab From bee1df8328609746d1439e5b98f9912309a70fdb Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Tue, 7 Jul 2020 16:47:43 +0530 Subject: [PATCH 326/410] msm: camera: isp: Handle Dual VFE incase of event mismatch For dual IFE case if there is mismatch in the number of HW events generated by two cores, then we recover for maximum of 10 HW events mismatch. Beyond this KMD is not recovering. CRs-Fixed: 2731316 Change-Id: Ifa1c932eef3340efbb64ed6d74cfc49581d91f36 Signed-off-by: Wyes Karny --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 59 +++++++++++++++++-- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 3 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 1 + .../isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 4 ++ .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 4 ++ .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 6 ++ .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 44 ++++++++++++++ .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 50 ++++++++++++++++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 17 ++++++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h | 4 ++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 17 ++++++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h | 6 ++ 13 files changed, 212 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index e585ced506f4..730c5042438d 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -4396,6 +4396,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } } + ctx->dual_ife_irq_mismatch_cnt = 0; /* Start IFE root node: do nothing */ CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); @@ -4527,6 +4528,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->dsp_enabled = false; ctx->is_fe_enabled = false; ctx->is_offline = false; + ctx->dual_ife_irq_mismatch_cnt = 0; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; @@ -7175,6 +7177,36 @@ static int cam_ife_hw_mgr_handle_hw_rup( return 0; } +static void cam_ife_mgr_ctx_irq_dump(struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_hw_get_cmd_update cmd_update; + int i = 0; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + cmd_update.res = hw_mgr_res->hw_res[i]; + cmd_update.cmd_type = + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, + &cmd_update, sizeof(cmd_update)); + break; + default: + break; + } + } + } +} + static int cam_ife_hw_mgr_check_irq_for_dual_vfe( struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx, uint32_t hw_event_type) @@ -7214,16 +7246,35 @@ static int cam_ife_hw_mgr_check_irq_for_dual_vfe( } if ((event_cnt[master_hw_idx] && - (event_cnt[master_hw_idx] - event_cnt[slave_hw_idx] > 1)) || + ((int)(event_cnt[master_hw_idx] - event_cnt[slave_hw_idx]) > 1 + )) || (event_cnt[slave_hw_idx] && - (event_cnt[slave_hw_idx] - event_cnt[master_hw_idx] > 1))) { + ((int)(event_cnt[slave_hw_idx] - event_cnt[master_hw_idx]) > 1 + ))) { CAM_ERR_RATE_LIMIT(CAM_ISP, "One of the VFE could not generate hw event %d master[%d] core_cnt %d slave[%d] core_cnt %d", hw_event_type, master_hw_idx, event_cnt[master_hw_idx], slave_hw_idx, event_cnt[slave_hw_idx]); - rc = -1; - return rc; + + if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt > 10) { + rc = -1; + return rc; + } + + if (event_cnt[master_hw_idx] >= 2) { + event_cnt[master_hw_idx]--; + ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++; + } + + if (event_cnt[slave_hw_idx] >= 2) { + event_cnt[slave_hw_idx]--; + ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt++; + } + + if (ife_hw_mgr_ctx->dual_ife_irq_mismatch_cnt == 1) + cam_ife_mgr_ctx_irq_dump(ife_hw_mgr_ctx); + rc = 0; } CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d", diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 7e81bc4bde1e..9233a19a0a76 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -146,6 +146,8 @@ struct cam_ife_hw_mgr_debug { * @ts captured timestamp when the ctx is acquired * @is_offline Indicate whether context is for offline IFE * @dsp_enabled Indicate whether dsp is enabled in this context + * @dual_ife_irq_mismatch_cnt irq mismatch count value per core, used for + * dual VFE */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -197,6 +199,7 @@ struct cam_ife_hw_mgr_ctx { struct timespec64 ts; bool is_offline; bool dsp_enabled; + uint32_t dual_ife_irq_mismatch_cnt; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 7198f3a2f2ef..2c95eaa0b5f0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -111,6 +111,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_DUMP_HW, CAM_ISP_HW_CMD_FE_TRIGGER_CMD, CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index faf36dfb80d0..94ce25da29ab 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -597,6 +597,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_QUERY: case CAM_ISP_HW_CMD_QUERY_DSP_MODE: case CAM_ISP_HW_CMD_CAMIF_DATA: + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h index 84b17694e60e..dfeaf3032bcf 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -295,6 +295,10 @@ static struct cam_vfe_top_ver2_reg_offset_common vfe170_150_top_common_reg = { .three_D_cfg = 0x00000054, .violation_status = 0x0000007C, .reg_update_cmd = 0x000004AC, + .irq_mask_0 = 0x0000005C, + .irq_mask_1 = 0x00000060, + .irq_status_0 = 0x0000006C, + .irq_status_1 = 0x00000070, }; static struct cam_vfe_rdi_ver2_reg vfe170_150_rdi_reg = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index b26592912c93..6d650fe5e711 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -376,6 +376,10 @@ static struct cam_vfe_top_ver2_reg_offset_common vfe175_130_top_common_reg = { .three_D_cfg = 0x00000054, .violation_status = 0x0000007C, .reg_update_cmd = 0x000004AC, + .irq_mask_0 = 0x0000005C, + .irq_mask_1 = 0x00000060, + .irq_status_0 = 0x0000006C, + .irq_status_1 = 0x00000070, }; static struct cam_vfe_rdi_ver2_reg vfe175_130_rdi_reg = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index 18a0071bf0b0..86078e9be08d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -95,6 +95,12 @@ static struct cam_vfe_top_ver3_reg_offset_common vfe480_top_common_reg = { .global_reset_cmd = 0x0000001C, .core_cfg_0 = 0x0000002C, .core_cfg_1 = 0x00000030, + .irq_mask_0 = 0x0000003C, + .irq_mask_1 = 0x00000040, + .irq_mask_2 = 0x00000044, + .irq_status_0 = 0x00000054, + .irq_status_1 = 0x00000058, + .irq_status_2 = 0x0000005C, .reg_update_cmd = 0x00000034, .violation_status = 0x00000074, .core_cgc_ovd_0 = 0x00000020, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index f39cc4d470bb..00813d4a9c7d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -663,6 +663,48 @@ int cam_vfe_camif_dump_timestamps( return 0; } +static int cam_vfe_camif_irq_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments\n"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) { + CAM_ERR(CAM_ISP, "Error! Invalid state\n"); + return 0; + } + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + soc_private = camif_priv->soc_info->soc_private; + + CAM_INFO(CAM_ISP, + "Core Id =%d Mask reg: offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->hw_intf->hw_idx, + camif_priv->common_reg->irq_mask_0, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_mask_0), + camif_priv->common_reg->irq_mask_1, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_mask_1)); + CAM_INFO(CAM_ISP, + "Core Id =%d Status reg: offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->hw_intf->hw_idx, + camif_priv->common_reg->irq_status_0, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_status_0), + camif_priv->common_reg->irq_status_1, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_status_1)); + return rc; +} + static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -689,6 +731,8 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, break; case CAM_ISP_HW_CMD_CAMIF_DATA: rc = cam_vfe_camif_dump_timestamps(rsrc_node, cmd_args); + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_camif_irq_reg_dump(rsrc_node); break; default: CAM_ERR(CAM_ISP, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index de4299a47034..b2e0276ea909 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -784,6 +784,54 @@ int cam_vfe_camif_ver3_dump_timestamps( return 0; } +static int cam_vfe_camif_ver3_irq_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments\n"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) { + CAM_ERR(CAM_ISP, "Error! Invalid state\n"); + return 0; + } + + camif_priv = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; + soc_private = camif_priv->soc_info->soc_private; + + CAM_INFO(CAM_ISP, + "Core Id =%d Mask reg: offset 0x%x val 0x%x offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->hw_intf->hw_idx, + camif_priv->common_reg->irq_mask_0, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_mask_0), + camif_priv->common_reg->irq_mask_1, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_mask_1), + camif_priv->common_reg->irq_mask_2, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_mask_2)); + + CAM_INFO(CAM_ISP, + "Core Id =%d Status reg: offset 0x%x val 0x%x offset 0x%x val 0x%x offset 0x%x val 0x%x", + camif_priv->common_reg->irq_status_0, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_status_0), + camif_priv->common_reg->irq_status_1, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_status_1), + camif_priv->common_reg->irq_status_2, + cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->irq_status_2)); + return rc; +} + static int cam_vfe_camif_ver3_process_cmd( struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) @@ -822,6 +870,8 @@ static int cam_vfe_camif_ver3_process_cmd( break; case CAM_ISP_HW_CMD_CAMIF_DATA: rc = cam_vfe_camif_ver3_dump_timestamps(rsrc_node, cmd_args); + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_camif_ver3_irq_reg_dump(rsrc_node); break; default: CAM_ERR(CAM_ISP, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 828d31c5c81c..b9527e406660 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -654,6 +654,19 @@ int cam_vfe_top_query(struct cam_vfe_top_ver2_priv *top_priv, return rc; } +static int cam_vfe_get_irq_register_dump( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, cmd_args, + arg_size); + return 0; +} + int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -713,6 +726,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_QUERY: rc = cam_vfe_top_query(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_get_irq_register_dump(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h index 65d01da159ec..b4a657227497 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h @@ -41,6 +41,10 @@ struct cam_vfe_top_ver2_reg_offset_common { uint32_t three_D_cfg; uint32_t violation_status; uint32_t reg_update_cmd; + uint32_t irq_mask_0; + uint32_t irq_mask_1; + uint32_t irq_status_0; + uint32_t irq_status_1; }; struct cam_vfe_top_ver2_hw_info { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index 90d23486fb51..b42a8f0a51c1 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -556,6 +556,19 @@ int cam_vfe_top_ver3_query(struct cam_vfe_top_ver3_priv *top_priv, return rc; } +static int cam_vfe_top_ver3_get_irq_register_dump( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, cmd_args, + arg_size); + return 0; +} + int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -616,6 +629,10 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_QUERY: rc = cam_vfe_top_ver3_query(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + rc = cam_vfe_top_ver3_get_irq_register_dump(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h index 4a24ba6ddf76..c4c5725cab73 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h @@ -38,6 +38,12 @@ struct cam_vfe_top_ver3_reg_offset_common { uint32_t bus_cgc_ovd; uint32_t core_cfg_0; uint32_t core_cfg_1; + uint32_t irq_mask_0; + uint32_t irq_mask_1; + uint32_t irq_mask_2; + uint32_t irq_status_0; + uint32_t irq_status_1; + uint32_t irq_status_2; uint32_t reg_update_cmd; uint32_t trigger_cdm_events; uint32_t violation_status; -- GitLab From b8d6aa76f1aeb1ab76ffe1d28ef0e77bf8764104 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Wed, 5 Aug 2020 22:00:32 +0530 Subject: [PATCH 327/410] msm: camera: isp: Reset csid hw after csi rx configuration Reset the CSID hardware after csi rx configuration. This will avoid any false lane overflow errors due to invalid states of input csid lanes. Reset will make clean the csi rx hw states. CRs-Fixed: 2748618 Change-Id: Idb3e8b257caf1cde47051d3378148e2885d1eb7c Signed-off-by: Ravikishore Pampana --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 580143f03ce6..c21a802338e8 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1618,7 +1618,7 @@ static int cam_ife_csid_enable_csi2( const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; struct cam_ife_csid_cid_data *cid_data; - uint32_t val = 0; + uint32_t val = 0, val2; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -1670,6 +1670,19 @@ static int cam_ife_csid_enable_csi2( } } + /* after configuring the csi rx, reset hw once */ + rc = cam_ife_csid_reset_regs(csid_hw, true); + if (rc < 0) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + val2 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_status_addr); + CAM_ERR(CAM_ISP, + "Failed in HW reset csid hw:%d top reset failed csi rx cfg:0x%x CSI RX status:0x%x", + csid_hw->hw_intf->hw_idx, val, val2); + return rc; + } + cam_ife_csid_csi2_irq_ctrl(csid_hw, true); return 0; } @@ -3617,12 +3630,14 @@ int cam_ife_csid_init_hw(void *hw_priv, break; } - rc = cam_ife_csid_reset_regs(csid_hw, true); - if (rc < 0) - CAM_ERR(CAM_ISP, "CSID: Failed in HW reset"); - - if (rc) - cam_ife_csid_disable_hw(csid_hw); + /* csid hw reset done after configuring the csi2 */ + if (res->res_type != CAM_ISP_RESOURCE_CID) { + rc = cam_ife_csid_reset_regs(csid_hw, true); + if (rc) { + CAM_ERR(CAM_ISP, "CSID: Failed in HW reset"); + cam_ife_csid_disable_hw(csid_hw); + } + } end: mutex_unlock(&csid_hw->hw_info->hw_mutex); @@ -4341,10 +4356,14 @@ static int cam_csid_evt_bottom_half_handler( goto end; } - CAM_ERR_RATE_LIMIT(CAM_ISP, "idx %d err %d phy %d cnt %d", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "idx %d err %d phy %d lane type:%d ln num:%d ln cfg:0x%x cnt %d", csid_hw->hw_intf->hw_idx, evt_payload->evt_type, csid_hw->csi2_rx_cfg.phy_sel, + csid_hw->csi2_rx_cfg.lane_type, + csid_hw->csi2_rx_cfg.lane_num, + csid_hw->csi2_rx_cfg.lane_cfg, csid_hw->csi2_cfg_cnt); for (i = 0; i < CAM_IFE_CSID_IRQ_REG_MAX; i++) -- GitLab From 8e50e53a269834cd706d2c1103165a5d7b30f920 Mon Sep 17 00:00:00 2001 From: Chandan Kumar Jha Date: Fri, 7 Aug 2020 11:49:06 +0530 Subject: [PATCH 328/410] msm: camera: memmgr: fix the concurrency issue while accessing the list In corner cases, There is possibility of concurrent access of mapping info list during alloc and map the buffer. To protect that, added mutex lock before accessing the list. CRs-Fixed: 2751906 Change-Id: I6d390a0650095c1056d7e538d28c8c7d530f50d4 Signed-off-by: Chandan Kumar Jha --- drivers/cam_req_mgr/cam_mem_mgr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index e4fdcd284a72..60ff61314ebb 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -657,6 +657,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) goto slot_fail; } + mutex_lock(&tbl.m_lock); if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) || (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) || (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) { @@ -686,10 +687,11 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", cmd->len, cmd->flags, fd, region, cmd->num_hdl, rc); + mutex_unlock(&tbl.m_lock); goto map_hw_fail; } } - + mutex_unlock(&tbl.m_lock); mutex_lock(&tbl.bufq[idx].q_lock); tbl.bufq[idx].fd = fd; tbl.bufq[idx].dma_buf = NULL; @@ -773,6 +775,7 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) return -EINVAL; } + mutex_lock(&tbl.m_lock); if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) || (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) { rc = cam_mem_util_map_hw_va(cmd->flags, @@ -787,9 +790,11 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", cmd->flags, cmd->fd, CAM_SMMU_REGION_IO, cmd->num_hdl, rc); + mutex_unlock(&tbl.m_lock); goto map_fail; } } + mutex_unlock(&tbl.m_lock); idx = cam_mem_get_slot(); if (idx < 0) { -- GitLab From 7a81e093a616a9c319f89b90d94101cd044aa687 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 7 May 2020 17:00:07 +0530 Subject: [PATCH 329/410] msm: camera: sensor: Read using addr and data type Read using address and data type provided in xml CRs-Fixed: 2675042 Change-Id: Ice85f2ce4a6fa38a7de4b1bf4233449c52cd39e2 Signed-off-by: Vishal Verma --- drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index de74112bd3fb..0d4c1ce6d22b 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -131,7 +131,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, csl_packet = (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); - if (cam_packet_util_validate_packet(csl_packet, + if ((csl_packet == NULL) || cam_packet_util_validate_packet(csl_packet, remain_len)) { CAM_ERR(CAM_SENSOR, "Invalid packet params"); rc = -EINVAL; @@ -695,8 +695,9 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) rc = camera_io_dev_read( &(s_ctrl->io_master_info), slave_info->sensor_id_reg_addr, - &chipid, CAMERA_SENSOR_I2C_TYPE_WORD, - CAMERA_SENSOR_I2C_TYPE_WORD); + &chipid, + s_ctrl->sensor_probe_addr_type, + s_ctrl->sensor_probe_data_type); CAM_DBG(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", chipid, slave_info->sensor_id); -- GitLab From 945f45ef7c27f25a860a34ee6ce163ad75155e80 Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Tue, 30 Jun 2020 20:57:56 +0530 Subject: [PATCH 330/410] msm: camera: cci: Fixed CCI Read timeout issue Concurrent CCI read operation could lead to corrupting rd_done variable, so protecting it using queue specific synchronization variable. CRs-Fixed: 2746692 Change-Id: I3ef2188d54196a6eb3f2729b558f263bd04a3c07 Signed-off-by: Anil Kumar Kanakanti --- drivers/cam_sensor_module/cam_cci/cam_cci_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index 6efa77a8d55d..4c28d0fddcbb 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1590,8 +1590,10 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, * THRESHOLD irq's, we reinit the threshold wait before * we load the burst read cmd. */ + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[QUEUE_1]); reinit_completion(&cci_dev->cci_master_info[master].rd_done); reinit_completion(&cci_dev->cci_master_info[master].th_complete); + mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[QUEUE_1]); CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes); do { -- GitLab From 7b9bc4eb278841ce8d07cc70a6362d0eba5db49b Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Mon, 22 Jun 2020 17:23:59 +0530 Subject: [PATCH 331/410] msm: camera: ife: dump bandwidth and clock for cpas and ife At the time of overflow dump bandwidth and axi clock information from cpas along with the ife clock and csid clock. CRs-Fixed: 2761497 Change-Id: I35433a371b77a2c8e7026e8325899131828e823d Signed-off-by: Tejas Prajapati --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 20 +++++++++++++++ .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 16 ++++++++++++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + .../vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c | 25 +++++++++++++++++-- .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 17 +++++++++++++ .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 12 +++++++++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 8 ++++++ 7 files changed, 97 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 730c5042438d..9f1d7d4049f5 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -7018,6 +7018,7 @@ static int cam_ife_hw_mgr_handle_hw_dump_info( struct cam_isp_resource_node *rsrc_node = NULL; struct cam_hw_intf *hw_intf; uint32_t i, out_port_id; + uint64_t dummy_args; int rc = 0; list_for_each_entry(hw_mgr_res, @@ -7041,6 +7042,25 @@ static int cam_ife_hw_mgr_handle_hw_dump_info( } } + list_for_each_entry(hw_mgr_res, + &ife_hw_mgr_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CSID_CLOCK_DUMP, + &dummy_args, + sizeof(uint64_t)); + if (rc) + CAM_ERR(CAM_ISP, + "CSID Clock Dump failed"); + } + } + } + out_port_id = event_info->res_id & 0xFF; hw_mgr_res = &ife_hw_mgr_ctx->res_list_ife_out[out_port_id]; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 580143f03ce6..75dc0807d8da 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -4021,6 +4021,19 @@ static int cam_ife_csid_set_csid_clock( return 0; } +static int cam_ife_csid_dump_csid_clock( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + if (!csid_hw) + return -EINVAL; + + CAM_INFO(CAM_ISP, "CSID:%d clock rate %llu", + csid_hw->hw_intf->hw_idx, + csid_hw->clk_rate); + + return 0; +} + static int cam_ife_csid_set_sensor_dimension( struct cam_ife_csid_hw *csid_hw, void *cmd_args) { @@ -4205,6 +4218,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_CSID_CLOCK_DUMP: + rc = cam_ife_csid_dump_csid_clock(csid_hw, cmd_args); + break; case CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED: rc = cam_ife_csid_set_csid_qcfa(csid_hw, cmd_args); break; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 2c95eaa0b5f0..a82d20f40f40 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -112,6 +112,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_FE_TRIGGER_CMD, CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, + CAM_ISP_HW_CMD_CSID_CLOCK_DUMP, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c index b54c43a145bc..100b00b4f40b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -840,7 +840,7 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, uint32_t violation_mask = 0x3F00, violation_status = 0; uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; struct cam_vfe_soc_private *soc_private = NULL; - uint32_t val0, val1, val2; + uint32_t val0, val1, val2, val3; if (!status) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -878,8 +878,23 @@ static void cam_vfe_camif_lite_print_status(uint32_t *status, if (status_0 & 0x20000000) CAM_INFO(CAM_ISP, "RDI0 OVERFLOW"); - if (status_0 & 0x40000000) + if (status_0 & 0x40000000) { CAM_INFO(CAM_ISP, "PD PIPE OVERFLOW"); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1010, true, &val3); + CAM_INFO(CAM_ISP, "CAMNOC REG ife_linear: 0x%X", + val0); + CAM_INFO(CAM_ISP, "ife_rdi_wr: 0x%X", val1); + CAM_INFO(CAM_ISP, "ife_ubwc_stats: 0x%X", val2); + CAM_INFO(CAM_ISP, "ife_rdi_Rd: 0x%x", val3); + cam_cpas_log_votes(); + } } if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && bus_overflow_status) { @@ -1200,6 +1215,9 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + cam_vfe_camif_lite_print_status(irq_status, ret, camif_lite_priv); @@ -1219,6 +1237,9 @@ static int cam_vfe_camif_lite_handle_irq_bottom_half( ret = CAM_VFE_IRQ_STATUS_VIOLATION; + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + cam_vfe_camif_lite_print_status(irq_status, ret, camif_lite_priv); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 00813d4a9c7d..640eb0bdc23a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -786,6 +786,8 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_mux_camif_data *camif_priv; struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; uint32_t irq_status0; uint32_t irq_status1; uint32_t val; @@ -802,6 +804,9 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + soc_info = camif_priv->soc_info; + soc_private = (struct cam_vfe_soc_private *)soc_info->soc_private; + evt_info.hw_idx = camif_node->hw_intf->hw_idx; evt_info.res_id = camif_node->res_id; evt_info.res_type = camif_node->res_type; @@ -891,6 +896,12 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, payload->irq_reg_val[2]); ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + + cam_cpas_log_votes(); + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) cam_vfe_camif_reg_dump(camif_node->res_priv); } @@ -909,6 +920,12 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, ts.tv_sec, ts.tv_nsec/1000, payload->irq_reg_val[2]); ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + + cam_cpas_log_votes(); + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) cam_vfe_camif_reg_dump(camif_node->res_priv); } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index b2e0276ea909..6dc010d9f6d6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -1345,6 +1345,8 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, struct cam_vfe_mux_camif_ver3_data *camif_priv; struct cam_vfe_top_irq_evt_payload *payload; struct cam_isp_hw_event_info evt_info; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; struct timespec64 ts; uint32_t val = 0; @@ -1361,6 +1363,10 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, camif_priv = camif_node->res_priv; payload = evt_payload_priv; + soc_info = camif_priv->soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; + for (i = 0; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) irq_status[i] = payload->irq_reg_val[i]; @@ -1446,6 +1452,9 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + cam_vfe_camif_ver3_print_status(irq_status, ret, camif_priv); if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) @@ -1475,6 +1484,9 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, ret = CAM_VFE_IRQ_STATUS_VIOLATION; + CAM_INFO(CAM_ISP, "ife_clk_src:%lld", + soc_private->ife_clk_src); + cam_vfe_camif_ver3_print_status(irq_status, ret, camif_priv); if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index b42a8f0a51c1..d7cf1a84f9c4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -116,6 +116,9 @@ static int cam_vfe_top_ver3_set_hw_clk_rate( rc = 0; goto end; } + + soc_private->ife_clk_src = max_clk_rate; + ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = clk_lvl; cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote); @@ -474,6 +477,8 @@ int cam_vfe_top_ver3_stop(void *device_priv, struct cam_vfe_top_ver3_priv *top_priv; struct cam_isp_resource_node *mux_res; struct cam_hw_info *hw_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; int i, rc = 0; if (!device_priv || !stop_args) { @@ -484,6 +489,8 @@ int cam_vfe_top_ver3_stop(void *device_priv, top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; mux_res = (struct cam_isp_resource_node *)stop_args; hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; if (mux_res->res_id < CAM_ISP_HW_VFE_IN_MAX) { rc = mux_res->stop(mux_res); @@ -506,6 +513,7 @@ int cam_vfe_top_ver3_stop(void *device_priv, } } + soc_private->ife_clk_src = 0; return rc; } -- GitLab From 2153a1bdd6cb4384da17fbc5db03b19534adb553 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Fri, 17 Jul 2020 01:00:38 +0530 Subject: [PATCH 332/410] msm: camera: isp: Drop first frame for rdi and pd in dual ife case For dual IFE case drop first frame of RDI and PP path. In dual IFE case first IPP frame is dropped. Therefore dropping the PP and RDI first frame also if usage_type in in_port is set to DUAL_IFE. CRs-Fixed: 2746287 Change-Id: I47e0f0af070750e0216217be181933f1d851d8dd Signed-off-by: Wyes Karny --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 300 ++++++++++++++++-- .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 11 + 2 files changed, 277 insertions(+), 34 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 580143f03ce6..dd52b34dbbd0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -48,6 +48,179 @@ static int cam_ife_csid_reset_regs( struct cam_ife_csid_hw *csid_hw, bool reset_hw); + +static void cam_ife_csid_enable_path_for_init_frame_drop( + struct cam_ife_csid_hw *csid_hw, + int res_id) +{ + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg = NULL; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *res; + uint32_t val; + + if (!csid_hw) { + CAM_WARN(CAM_ISP, "csid_hw cannot be NULL"); + return; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res_id == CAM_IFE_PIX_PATH_RES_IPP) { + res = &csid_hw->ipp_res; + pxl_reg = csid_reg->ipp_reg; + } else if (res_id == CAM_IFE_PIX_PATH_RES_PPP) { + res = &csid_hw->ppp_res; + pxl_reg = csid_reg->ppp_reg; + } else if (res_id >= CAM_IFE_PIX_PATH_RES_RDI_0 && + res_id <= CAM_IFE_PIX_PATH_RES_RDI_3) { + res = &csid_hw->rdi_res[res_id]; + rdi_reg = csid_reg->rdi_reg[res_id]; + } else { + CAM_ERR(CAM_ISP, "Invalid res_id"); + return; + } + + path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; + + if (!path_data || !path_data->init_frame_drop) + return; + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) + return; + + csid_hw->res_sof_cnt[res_id]++; + if ((csid_hw->res_sof_cnt[res_id] + 1) < + csid_hw->res_sof_cnt[res_id]) { + CAM_WARN(CAM_ISP, "Res %d sof count overflow %d", + res_id, csid_hw->res_sof_cnt[res_id]); + return; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id %d SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, res_id, csid_hw->res_sof_cnt[res_id], + path_data->init_frame_drop); + + if ((csid_hw->res_sof_cnt[res_id] == + path_data->init_frame_drop) && + pxl_reg) { + CAM_DBG(CAM_ISP, "Enabling pixel %s Path", + (res_id == CAM_IFE_PIX_PATH_RES_IPP) ? "IPP" : "PPP"); + if (path_data->sync_mode != + CAM_ISP_HW_SYNC_SLAVE) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } else if ((csid_hw->res_sof_cnt[res_id] == + path_data->init_frame_drop) && rdi_reg) { + CAM_DBG(CAM_ISP, "Enabling RDI %d Path", res_id); + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_ctrl_addr); + if (!(csid_hw->csid_debug & + CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + val &= ~(CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + } + } +} + +static bool cam_ife_csid_check_path_active(struct cam_ife_csid_hw *csid_hw) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t i; + uint32_t path_status = 1; + + if (!csid_hw) { + CAM_WARN(CAM_ISP, "csid_hw cannot be NULL"); + return -EINVAL; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* check the IPP path status */ + if (csid_reg->cmn_reg->num_pix) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d IPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + if (csid_reg->cmn_reg->num_ppp) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d PPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + /* Check the RDI path status */ + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d RDI:%d path status:%d", + csid_hw->hw_intf->hw_idx, i, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + +end: + /* if status is 0 then path is active */ + return path_status ? false : true; +} + +static void cam_ife_csid_reset_path_data( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + struct cam_ife_csid_path_cfg *path_data = NULL; + + if (!csid_hw || !res) { + CAM_WARN(CAM_ISP, "csid_hw or res cannot be NULL"); + return; + } + path_data = res->res_priv; + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) + csid_hw->ipp_path_config.measure_enabled = 0; + else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) + csid_hw->ppp_path_config.measure_enabled = 0; + else if (res->res_id >= CAM_IFE_PIX_PATH_RES_RDI_0 && + res->res_id <= CAM_IFE_PIX_PATH_RES_RDI_3) + csid_hw->rdi_path_config[res->res_id].measure_enabled + = 0; + + if (path_data) + path_data->init_frame_drop = 0; +} + static int cam_ife_csid_is_ipp_ppp_format_supported( uint32_t in_format) { @@ -529,6 +702,9 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) csid_hw->prev_boot_timestamp = 0; end: + for (i = 0 ; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; + return rc; } @@ -1128,6 +1304,7 @@ int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, path_data->in_format = reserve->in_port->format; path_data->out_format = reserve->out_port->format; path_data->sync_mode = reserve->sync_mode; + path_data->usage_type = reserve->in_port->usage_type; path_data->height = reserve->in_port->height; path_data->start_line = reserve->in_port->line_start; path_data->end_line = reserve->in_port->line_stop; @@ -1312,6 +1489,9 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) spin_unlock_irqrestore(&csid_hw->lock_state, flags); cam_tasklet_start(csid_hw->tasklet); + for (i = 0; i < CAM_IFE_PIX_PATH_RES_MAX; i++) + csid_hw->res_sof_cnt[i] = 0; + return 0; disable_soc: @@ -2052,8 +2232,9 @@ static int cam_ife_csid_enable_pxl_path( bool is_ipp; uint32_t val = 0; struct cam_isp_sensor_dimension *path_config; + bool path_active = false; - path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -2085,6 +2266,9 @@ static int cam_ife_csid_enable_pxl_path( CAM_DBG(CAM_ISP, "Enable %s path", (is_ipp) ? "IPP" : "PPP"); + if ((!is_ipp) && (path_data->usage_type == CAM_ISP_RES_USAGE_DUAL)) + path_data->init_frame_drop = 1; + /* Set master or slave path */ if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) { @@ -2105,20 +2289,36 @@ static int cam_ife_csid_enable_pxl_path( /* Default is internal halt mode */ val = 0; } - /* - * Resume at frame boundary if Master or No Sync. - * Slave will get resume command from Master. - */ - if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || - path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) - val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + + /* Resume at frame boundary */ + if (!path_data->init_frame_drop) { + CAM_DBG(CAM_ISP, + "CSID:%d Starting %s path", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP"); + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + } else { + path_active = cam_ife_csid_check_path_active(csid_hw); + if (path_active) { + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + } + CAM_DBG(CAM_ISP, + "CSID:%d %s %s path f drop %d val %d", + csid_hw->hw_intf->hw_idx, + path_active ? "Starting" : "Not Starting", + (is_ipp) ? "IPP" : "PPP", + path_data->init_frame_drop, val); + } cam_io_w_mb(val, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_ctrl_addr); CAM_DBG(CAM_ISP, "CSID:%d %s Ctrl val: 0x%x", - csid_hw->hw_intf->hw_idx, - (is_ipp) ? "IPP" : "PPP", val); + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", val); /* Enable the required pxl path interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; @@ -2129,7 +2329,8 @@ static int cam_ife_csid_enable_pxl_path( if (pxl_reg->overflow_ctrl_en) val |= CSID_PATH_OVERFLOW_RECOVERY; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (path_data->init_frame_drop && !path_active)) val |= CSID_PATH_INFO_INPUT_SOF; if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) val |= CSID_PATH_INFO_INPUT_EOF; @@ -2271,6 +2472,9 @@ static int cam_ife_csid_disable_pxl_path( csid_hw->hw_intf->hw_idx, res->res_id, (is_ipp) ? "IPP" : "PPP"); + path_data->init_frame_drop = 0; + csid_hw->res_sof_cnt[res->res_id] = 0; + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_irq_mask_addr); @@ -2312,7 +2516,7 @@ static int cam_ife_csid_init_config_rdi_path( uint32_t format_measure_addr, camera_hw_version; uint32_t packing_fmt = 0, in_bpp = 0; - path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -2778,8 +2982,11 @@ static int cam_ife_csid_enable_rdi_path( { const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; uint32_t id, val; + bool path_active = false; + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; @@ -2794,10 +3001,28 @@ static int cam_ife_csid_enable_rdi_path( return -EINVAL; } + /*Drop one frame extra on RDI for dual IFE use case */ + if (path_data->usage_type == CAM_ISP_RES_USAGE_DUAL) + path_data->init_frame_drop = 1; + /*resume at frame boundary */ - cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + if (!path_data->init_frame_drop) { + CAM_DBG(CAM_ISP, "Start RDI:%d path", id); + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + } else { + path_active = cam_ife_csid_check_path_active(csid_hw); + if (path_active) + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + CAM_DBG(CAM_ISP, + "CSID:%d %s RDI%d path frame drop %d val 0x%x", + csid_hw->hw_intf->hw_idx, + path_active ? "Starting" : "Not Starting", id, + path_data->init_frame_drop); + } /* Enable the required RDI interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; @@ -2808,7 +3033,8 @@ static int cam_ife_csid_enable_rdi_path( if (csid_reg->rdi_reg[id]->overflow_ctrl_en) val |= CSID_PATH_OVERFLOW_RECOVERY; - if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) || + (path_data->init_frame_drop && !path_active)) val |= CSID_PATH_INFO_INPUT_SOF; if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) @@ -2886,10 +3112,12 @@ static int cam_ife_csid_disable_rdi_path( uint32_t id, val = 0; const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; - csid_reg = csid_hw->csid_info->csid_reg; - soc_info = &csid_hw->hw_info->soc_info; - id = res->res_id; + path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; if ((res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3) || (!csid_reg->rdi_reg[res->res_id])) { @@ -2925,6 +3153,9 @@ static int cam_ife_csid_disable_rdi_path( CAM_DBG(CAM_ISP, "CSID:%d res_id:%d", csid_hw->hw_intf->hw_idx, res->res_id); + path_data->init_frame_drop = 0; + csid_hw->res_sof_cnt[id] = 0; + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); @@ -3429,14 +3660,8 @@ int cam_ife_csid_release(void *hw_priv, break; case CAM_ISP_RESOURCE_PIX_PATH: res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; - if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) - csid_hw->ipp_path_config.measure_enabled = 0; - else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) - csid_hw->ppp_path_config.measure_enabled = 0; - else if (res->res_id >= CAM_IFE_PIX_PATH_RES_RDI_0 && - res->res_id <= CAM_IFE_PIX_PATH_RES_RDI_3) - csid_hw->rdi_path_config[res->res_id].measure_enabled - = 0; + cam_ife_csid_reset_path_data(csid_hw, res); + break; default: CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", @@ -4851,15 +5076,19 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) complete(&csid_hw->csid_ppp_complete); } - if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & - CSID_PATH_INFO_INPUT_SOF) && - (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { - CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP SOF received", - csid_hw->hw_intf->hw_idx); + if (irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & + CSID_PATH_INFO_INPUT_SOF) { + cam_ife_csid_enable_path_for_init_frame_drop(csid_hw, + CAM_IFE_PIX_PATH_RES_PPP); + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP SOF received", + csid_hw->hw_intf->hw_idx); if (csid_hw->sof_irq_triggered) csid_hw->irq_debug_cnt++; } + if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) @@ -4919,14 +5148,17 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) complete(&csid_hw->csid_rdin_complete[i]); } - if ((irq_status[i] & CSID_PATH_INFO_INPUT_SOF) && - (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { - CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSID RDI:%d SOF received", i); + if (irq_status[i] & CSID_PATH_INFO_INPUT_SOF) { + cam_ife_csid_enable_path_for_init_frame_drop( + csid_hw, i); + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d SOF received", i); if (csid_hw->sof_irq_triggered) csid_hw->irq_debug_cnt++; } + if ((irq_status[i] & CSID_PATH_INFO_INPUT_EOF) && (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) CAM_INFO_RATE_LIMIT(CAM_ISP, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 4ca5928c3446..8e9eecf48e88 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -514,10 +514,13 @@ struct cam_ife_csid_cid_data { * Reserving the path for master IPP or slave IPP * master (set value 1), Slave ( set value 2) * for RDI, set mode to none + * @usage_type: dual or single IFE information * @master_idx: For Slave reservation, Give master IFE instance Index. * Slave will synchronize with master Start and stop operations * @clk_rate Clock rate * @num_bytes_out: Number of output bytes per cycle + * @init_frame_drop init frame drop value. In dual ife case rdi need to drop one + * more frame than pix. * */ struct cam_ife_csid_path_cfg { @@ -538,11 +541,13 @@ struct cam_ife_csid_path_cfg { uint32_t end_line; uint32_t height; enum cam_isp_hw_sync_mode sync_mode; + uint32_t usage_type; uint32_t master_idx; uint64_t clk_rate; uint32_t horizontal_bin; uint32_t qcfa_bin; uint32_t num_bytes_out; + uint32_t init_frame_drop; }; /** @@ -597,6 +602,9 @@ struct cam_csid_evt_payload { * @irq_debug_cnt: Counter to track sof irq's when above flag is set. * @error_irq_count Error IRQ count, if continuous error irq comes * need to stop the CSID and mask interrupts. + * @device_enabled Device enabled will set once CSID powered on and + * initial configuration are done. + * @lock_state csid spin lock * @binning_enable Flag is set if hardware supports QCFA binning * @binning_supported Flag is set if sensor supports QCFA binning * @first_sof_ts first bootime stamp at the start @@ -604,6 +612,8 @@ struct cam_csid_evt_payload { * @epd_supported Flag is set if sensor supports EPD * @fatal_err_detected flag to indicate fatal errror is reported * @event_cb Callback to hw manager if CSID event reported + * @res_sof_cnt path resource sof count value. it used for initial + * frame drop */ struct cam_ife_csid_hw { struct cam_hw_intf *hw_intf; @@ -650,6 +660,7 @@ struct cam_ife_csid_hw { uint32_t epd_supported; bool fatal_err_detected; cam_hw_mgr_event_cb_func event_cb; + uint32_t res_sof_cnt[CAM_IFE_PIX_PATH_RES_MAX]; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, -- GitLab From adc649ed1448681c182a80f3fedbee749a8e0b93 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Wed, 9 Sep 2020 01:52:40 +0530 Subject: [PATCH 333/410] msm: camera: req_mgr: Add support for static payload in workqueue Few drivers is using static payload for crm workqueue. This change is to prevent release of statically allocated workqueue payload. CRs-Fixed: 2773657 Change-Id: Id96a1dcc4b4b953cfb2ea2b5126a4f215654d8c2 Signed-off-by: Ayush Kumar --- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 2 +- drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 6 +++--- drivers/cam_isp/cam_isp_context.c | 2 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 4 ++-- drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 2 +- drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 2 +- drivers/cam_req_mgr/cam_req_mgr_core.c | 4 ++-- drivers/cam_req_mgr/cam_req_mgr_workq.c | 9 ++++++--- drivers/cam_req_mgr/cam_req_mgr_workq.h | 5 ++++- 10 files changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 88baba383ff4..ba83d4db92a9 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -2086,7 +2086,7 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, } rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK, - &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0, + &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0, true, cam_req_mgr_process_workq_cam_fd_worker); if (rc) { CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc); 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 938e068e6d5d..46eb69da306a 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 @@ -5995,7 +5995,7 @@ static int cam_icp_mgr_create_wq(void) int i; rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, 0, + &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, 0, false, cam_req_mgr_process_workq_icp_command_queue); if (rc) { CAM_ERR(CAM_ICP, "unable to create a command worker"); @@ -6003,7 +6003,7 @@ static int cam_icp_mgr_create_wq(void) } rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0, + &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0, false, cam_req_mgr_process_workq_icp_message_queue); if (rc) { CAM_ERR(CAM_ICP, "unable to create a message worker"); @@ -6011,7 +6011,7 @@ static int cam_icp_mgr_create_wq(void) } rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0, + &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0, false, cam_req_mgr_process_workq_icp_timer_queue); if (rc) { CAM_ERR(CAM_ICP, "unable to create a timer worker"); diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index b5a28320ee46..95c3c805950a 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -4354,7 +4354,7 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, ctx_isp->offline_context = true; rc = cam_req_mgr_workq_create("offline_ife", 20, - &ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0, + &ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0, false, cam_req_mgr_process_workq_offline_ife_worker); if (rc) CAM_ERR(CAM_ISP, diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index cd5276c46d68..f99355b59958 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -7870,7 +7870,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) /* Create Worker for ife_hw_mgr with 10 tasks */ rc = cam_req_mgr_workq_create("cam_ife_worker", 10, - &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0, + &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0, false, cam_req_mgr_process_workq_cam_ife_worker); if (rc < 0) { CAM_ERR(CAM_ISP, "Unable to create worker"); diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index cc900130b47e..f0be4802d197 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1303,7 +1303,7 @@ static int cam_jpeg_setup_workqs(void) "jpeg_command_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_frame, - CRM_WORKQ_USAGE_NON_IRQ, 0, + CRM_WORKQ_USAGE_NON_IRQ, 0, false, cam_req_mgr_process_workq_jpeg_command_queue); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); @@ -1314,7 +1314,7 @@ static int cam_jpeg_setup_workqs(void) "jpeg_message_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_irq_cb, - CRM_WORKQ_USAGE_IRQ, 0, + CRM_WORKQ_USAGE_IRQ, 0, false, cam_req_mgr_process_workq_jpeg_message_queue); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 5cf8c55c0e37..a054d5f84709 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -1073,7 +1073,7 @@ int cam_lrme_mgr_register_device( CAM_DBG(CAM_LRME, "Create submit workq for %s", buf); rc = cam_req_mgr_workq_create(buf, CAM_LRME_WORKQ_NUM_TASK, - &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, 0, + &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, 0, true, cam_req_mgr_process_workq_cam_lrme_device_submit_worker); if (rc) { CAM_ERR(CAM_LRME, diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index a1414da98bfb..d22c9c65ca70 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -118,7 +118,7 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) rc = cam_req_mgr_workq_create("cam_lrme_hw_worker", CAM_LRME_HW_WORKQ_NUM_TASK, - &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0, + &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0, false, cam_req_mgr_process_workq_cam_lrme_hw_worker); if (rc) { CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc); diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index c2359be6ee9f..fbba99d0b0bb 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3455,7 +3455,7 @@ int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) link_info->u.link_info_v1.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, - &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag, false, cam_req_mgr_process_workq_link_worker); if (rc < 0) { CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); @@ -3565,7 +3565,7 @@ int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) link_info->u.link_info_v2.session_hdl, link->link_hdl); wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, - &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag, false, cam_req_mgr_process_workq_link_worker); if (rc < 0) { CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.c b/drivers/cam_req_mgr/cam_req_mgr_workq.c index 0c9ff7c419ca..7b62b859550a 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.c @@ -172,7 +172,7 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, int cam_req_mgr_workq_create(char *name, int32_t num_tasks, struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, - int flags, void (*func)(struct work_struct *w)) + int flags, bool is_static_payload, void (*func)(struct work_struct *w)) { int32_t i, wq_flags = 0, max_active_tasks = 0; struct crm_workq_task *task; @@ -214,6 +214,7 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, INIT_LIST_HEAD(&crm_workq->task.process_head[i]); INIT_LIST_HEAD(&crm_workq->task.empty_head); crm_workq->in_irq = in_irq; + crm_workq->is_static_payload = is_static_payload; crm_workq->task.num_task = num_tasks; crm_workq->task.pool = kcalloc(crm_workq->task.num_task, sizeof(struct crm_workq_task), GFP_KERNEL); @@ -258,8 +259,10 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq) } /* Destroy workq payload data */ - kfree((*crm_workq)->task.pool[0].payload); - (*crm_workq)->task.pool[0].payload = NULL; + if (!((*crm_workq)->is_static_payload)) { + kfree((*crm_workq)->task.pool[0].payload); + (*crm_workq)->task.pool[0].payload = NULL; + } kfree((*crm_workq)->task.pool); kfree(*crm_workq); *crm_workq = NULL; diff --git a/drivers/cam_req_mgr/cam_req_mgr_workq.h b/drivers/cam_req_mgr/cam_req_mgr_workq.h index 6416b66647f4..60a967701254 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_workq.h +++ b/drivers/cam_req_mgr/cam_req_mgr_workq.h @@ -70,6 +70,7 @@ struct crm_workq_task { * task - * @lock_bh : lock for task structs * @in_irq : set true if workque can be used in irq context + * @is_static_payload : set true if payload is statically allocated * @free_cnt : num of free/available tasks * @empty_head : list head of available taska which can be used * or acquired in order to enqueue a task to workq @@ -82,6 +83,7 @@ struct cam_req_mgr_core_workq { struct workqueue_struct *job; spinlock_t lock_bh; uint32_t in_irq; + bool is_static_payload; /* tasks */ struct { @@ -112,13 +114,14 @@ void cam_req_mgr_process_workq(struct work_struct *w); * @in_irq : Set to one if workq might be used in irq context * @flags : Bitwise OR of Flags for workq behavior. * e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL + * @is_static_payload : set to true if payload is statically allocated. * @func : function pointer for cam_req_mgr_process_workq wrapper function * This function will allocate and create workqueue and pass * the workq pointer to caller. */ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, - int flags, void (*func)(struct work_struct *w)); + int flags, bool is_static_payload, void (*func)(struct work_struct *w)); /** * cam_req_mgr_workq_destroy() -- GitLab From ddb51d2959ff63583a45fcbcc91cc0da97272033 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Thu, 13 Aug 2020 17:09:07 +0530 Subject: [PATCH 334/410] msm: camera: isp: Add per frame register support Adding per frame register dump for camera version 2 targets. CRs-Fixed: 2778464 Change-Id: I0f45e021959d1b812807f9e7500645f2d8365f54 Signed-off-by: Wyes Karny --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 640eb0bdc23a..4cba4ce8a7b0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -734,6 +734,12 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: rc = cam_vfe_camif_irq_reg_dump(rsrc_node); break; + case CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA: + camif_priv = (struct cam_vfe_mux_camif_data *) + rsrc_node->res_priv; + *((struct cam_hw_soc_info **)cmd_args) = camif_priv->soc_info; + rc = 0; + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); -- GitLab From 1b2dd06e2da3b773fff5318e29147d132c715aea Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Tue, 25 Aug 2020 21:01:48 +0530 Subject: [PATCH 335/410] msm: camera: reqmgr: Fix for apply stuck issue for pd 1 device In a edge case if there are only pd 1 devices then avoid reset slot if last buf done req if last applied req. If rd_idx is equal to last bufdone index then reset previous slot. Based on max PD in the link calculate max retry attempt before triggering recovery to UMD. Also fill trigger information during notify error. CRs-Fixed: 2776184 Change-Id: Ia38276a44779908104b1952e1986d358838b287c Signed-off-by: Wyes Karny --- drivers/cam_req_mgr/cam_req_mgr_core.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index c2359be6ee9f..e07cf5d63899 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1381,6 +1381,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, struct cam_req_mgr_req_queue *in_q; struct cam_req_mgr_core_session *session; struct cam_req_mgr_connected_device *dev; + uint32_t max_retry = 0; in_q = link->req.in_q; session = (struct cam_req_mgr_core_session *)link->parent; @@ -1496,12 +1497,14 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, if (rc < 0) { /* Apply req failed retry at next sof */ slot->status = CRM_SLOT_STATUS_REQ_PENDING; - link->retry_cnt++; - if (link->retry_cnt == MAXIMUM_RETRY_ATTEMPTS) { + max_retry = MAXIMUM_RETRY_ATTEMPTS; + if (link->max_delay == 1) + max_retry++; + if (link->retry_cnt == max_retry) { CAM_DBG(CAM_CRM, - "Max retry attempts reached on link[0x%x] for req [%lld]", - link->link_hdl, + "Max retry attempts (count: %d) reached on link[0x%x] for req [%lld]", + link->retry_cnt, link->link_hdl, in_q->slot[in_q->rd_idx].req_id); __cam_req_mgr_notify_error_on_link(link, dev); link->retry_cnt = 0; @@ -2570,6 +2573,8 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) if (idx >= 0) { if (idx == in_q->last_applied_idx) in_q->last_applied_idx = -1; + if (idx == in_q->rd_idx) + __cam_req_mgr_dec_idx(&idx, 1, in_q->num_slots); __cam_req_mgr_reset_req_slot(link, idx); } } @@ -2787,6 +2792,7 @@ static int cam_req_mgr_cb_notify_err( notify_err->link_hdl = err_info->link_hdl; notify_err->dev_hdl = err_info->dev_hdl; notify_err->error = err_info->error; + notify_err->trigger = err_info->trigger; task->process_cb = &cam_req_mgr_process_error; rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); -- GitLab From 83e46a81f904f4be59fb569af7e2e8df3ac5a2a0 Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Wed, 26 Aug 2020 11:07:47 +0530 Subject: [PATCH 336/410] msm: camera: cci: Add check for the cci master initialization Multiple Sensor submodules can stream on same CCI master. Currently, there is not any knowledge, whether requested master is already initialized by other submodules. This can result in operation slave in error, while other submodule tries to init the same master. This change adds the boolean variable to notify cci hardware, whether master is already initialized, and perform the operations accordingly. Change-Id: I5fe740cb61d47145b1b63161a1c1ef36cf25187a CRs-Fixed: 2782553 Signed-off-by: Anil Kumar Kanakanti --- .../cam_sensor_module/cam_cci/cam_cci_core.c | 9 +- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 12 +- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 267 ++++++++++-------- .../cam_sensor_module/cam_cci/cam_cci_soc.h | 5 +- 4 files changed, 159 insertions(+), 134 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index 4c28d0fddcbb..3bb399fe4271 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -26,7 +26,7 @@ static int32_t cam_cci_convert_type_to_num_bytes( num_bytes = 4; break; default: - CAM_ERR(CAM_CCI, "failed: %d", type); + CAM_ERR(CAM_CCI, "Wrong Sensor I2c Type: %d", type); num_bytes = 0; break; } @@ -1648,14 +1648,15 @@ static int32_t cam_cci_i2c_set_sync_prms(struct v4l2_subdev *sd, return rc; } -static int32_t cam_cci_release(struct v4l2_subdev *sd) +static int32_t cam_cci_release(struct v4l2_subdev *sd, + enum cci_i2c_master_t master) { uint8_t rc = 0; struct cci_device *cci_dev; cci_dev = v4l2_get_subdevdata(sd); - rc = cam_cci_soc_release(cci_dev); + rc = cam_cci_soc_release(cci_dev, master); if (rc < 0) { CAM_ERR(CAM_CCI, "Failed in releasing the cci: %d", rc); return rc; @@ -1766,7 +1767,7 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, break; case MSM_CCI_RELEASE: mutex_lock(&cci_dev->init_mutex); - rc = cam_cci_release(sd); + rc = cam_cci_release(sd, master); mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_I2C_READ: diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index caa9be1a3be3..410986975e1b 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -39,7 +39,6 @@ #define CCI_TIMEOUT msecs_to_jiffies(1500) -#define NUM_MASTERS 2 #define NUM_QUEUES 2 #define CCI_PINCTRL_STATE_DEFAULT "cci_default" @@ -122,7 +121,7 @@ struct cam_cci_i2c_queue_info { }; struct cam_cci_master_info { - uint32_t status; + int32_t status; atomic_t q_free[NUM_QUEUES]; uint8_t q_lock[NUM_QUEUES]; uint8_t reset_pending; @@ -138,6 +137,7 @@ struct cam_cci_master_info { struct semaphore master_sem; bool is_first_req; uint16_t freq_ref_cnt; + bool is_initilized; }; struct cam_cci_clk_params_t { @@ -172,6 +172,7 @@ enum cam_cci_state_t { * @cci_clk_info: CCI clock information * @cam_cci_i2c_queue_info: CCI queue information * @i2c_freq_mode: I2C frequency of operations + * @master_active_slave: Number of active/connected slaves for master * @cci_clk_params: CCI hw clk params * @cci_gpio_tbl: CCI GPIO table * @cci_gpio_tbl_size: GPIO table size @@ -204,9 +205,10 @@ struct cci_device { uint8_t ref_count; enum cam_cci_state_t cci_state; struct cam_cci_i2c_queue_info - cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; - struct cam_cci_master_info cci_master_info[NUM_MASTERS]; - enum i2c_freq_mode i2c_freq_mode[NUM_MASTERS]; + cci_i2c_queue_info[MASTER_MAX][NUM_QUEUES]; + struct cam_cci_master_info cci_master_info[MASTER_MAX]; + enum i2c_freq_mode i2c_freq_mode[MASTER_MAX]; + uint8_t master_active_slave[MASTER_MAX]; struct cam_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; struct msm_pinctrl_info cci_pinctrl; uint8_t cci_pinctrl_status; diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index ff74be5eb9f9..a8b47120a439 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -1,15 +1,85 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_cci_dev.h" #include "cam_cci_core.h" +static int cam_cci_init_master(struct cci_device *cci_dev, + enum cci_i2c_master_t master) +{ + int i = 0, rc = 0; + void __iomem *base = NULL; + struct cam_hw_soc_info *soc_info = NULL; + uint32_t max_queue_0_size = 0, max_queue_1_size = 0; + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + max_queue_0_size = CCI_I2C_QUEUE_0_SIZE; + max_queue_1_size = CCI_I2C_QUEUE_1_SIZE; + + cci_dev->master_active_slave[master]++; + if (!cci_dev->cci_master_info[master].is_initilized) { + /* Re-initialize the completion */ + reinit_completion( + &cci_dev->cci_master_info[master].reset_complete); + reinit_completion(&cci_dev->cci_master_info[master].rd_done); + + /* reinit the reports for the queue */ + for (i = 0; i < NUM_QUEUES; i++) + reinit_completion( + &cci_dev->cci_master_info[master].report_q[i]); + + /* Set reset pending flag to true */ + cci_dev->cci_master_info[master].reset_pending = true; + cci_dev->cci_master_info[master].status = 0; + if (cci_dev->ref_count == 1) { + cam_io_w_mb(CCI_RESET_CMD_RMSK, + base + CCI_RESET_CMD_ADDR); + cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); + } else { + cam_io_w_mb((master == MASTER_0) ? + CCI_M0_RESET_RMSK : CCI_M1_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + } + if (!wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT)) { + CAM_ERR(CAM_CCI, + "Failed: reset complete timeout for master: %d", + master); + rc = -ETIMEDOUT; + cci_dev->master_active_slave[master]--; + return rc; + } + + flush_workqueue(cci_dev->write_wq[master]); + + /* Setting up the queue size for master */ + cci_dev->cci_i2c_queue_info[master][QUEUE_0].max_queue_size + = max_queue_0_size; + cci_dev->cci_i2c_queue_info[master][QUEUE_1].max_queue_size + = max_queue_1_size; + + CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0: %d Q1: %d", master, + cci_dev->cci_i2c_queue_info[master][QUEUE_0] + .max_queue_size, + cci_dev->cci_i2c_queue_info[master][QUEUE_1] + .max_queue_size); + + cci_dev->cci_master_info[master].status = 0; + cci_dev->cci_master_info[master].is_initilized = true; + } + + return 0; +} + int cam_cci_init(struct v4l2_subdev *sd, struct cam_cci_ctrl *c_ctrl) { - uint8_t i = 0, j = 0; + uint8_t i = 0; int32_t rc = 0; struct cci_device *cci_dev; enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; @@ -20,7 +90,8 @@ int cam_cci_init(struct v4l2_subdev *sd, cci_dev = v4l2_get_subdevdata(sd); if (!cci_dev || !c_ctrl) { - CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + CAM_ERR(CAM_CCI, + "failed: invalid params cci_dev:%pK, c_ctrl:%pK", cci_dev, c_ctrl); rc = -EINVAL; return rc; @@ -30,150 +101,89 @@ int cam_cci_init(struct v4l2_subdev *sd, base = soc_info->reg_map[0].mem_base; if (!soc_info || !base) { - CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + CAM_ERR(CAM_CCI, + "failed: invalid params soc_info:%pK, base:%pK", soc_info, base); rc = -EINVAL; return rc; } - CAM_DBG(CAM_CCI, "Base address %pK", base); + if (master >= MASTER_MAX || master < 0) { + CAM_ERR(CAM_CCI, "Incorrect Master: %d", master); + return -EINVAL; + } + + if (!cci_dev->write_wq[master]) { + CAM_ERR(CAM_CCI, "Null memory for write wq[:%d]", master); + rc = -ENOMEM; + return rc; + } if (cci_dev->ref_count++) { - CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); - CAM_DBG(CAM_CCI, "master %d", master); - if (master < MASTER_MAX && master >= 0) { - mutex_lock(&cci_dev->cci_master_info[master].mutex); - flush_workqueue(cci_dev->write_wq[master]); - /* Re-initialize the completion */ - reinit_completion( - &cci_dev->cci_master_info[master].reset_complete); - reinit_completion( - &cci_dev->cci_master_info[master].rd_done); - for (i = 0; i < NUM_QUEUES; i++) - reinit_completion( - &cci_dev->cci_master_info[master].report_q[i]); - /* Set reset pending flag to true */ - cci_dev->cci_master_info[master].reset_pending = true; - cci_dev->cci_master_info[master].status = 0; - /* Set proper mask to RESET CMD address */ - if (master == MASTER_0) - cam_io_w_mb(CCI_M0_RESET_RMSK, - base + CCI_RESET_CMD_ADDR); - else - cam_io_w_mb(CCI_M1_RESET_RMSK, - base + CCI_RESET_CMD_ADDR); - /* wait for reset done irq */ - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, - CCI_TIMEOUT); - if (rc <= 0) - CAM_ERR(CAM_CCI, "wait failed %d", rc); - cci_dev->cci_master_info[master].status = 0; - mutex_unlock(&cci_dev->cci_master_info[master].mutex); + rc = cam_cci_init_master(cci_dev, master); + if (rc) { + CAM_ERR(CAM_CCI, "Failed to init: Master: %d: rc: %d", + master, rc); + cci_dev->ref_count--; } - return 0; + CAM_DBG(CAM_CCI, "ref_count %d, master: %d", + cci_dev->ref_count, master); + return rc; } ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; - axi_vote.axi_path[0].path_data_type = - CAM_AXI_PATH_DATA_ALL; - axi_vote.axi_path[0].transac_type = - CAM_AXI_TRANSACTION_WRITE; - axi_vote.axi_path[0].camnoc_bw = - CAM_CPAS_DEFAULT_AXI_BW; - axi_vote.axi_path[0].mnoc_ab_bw = - CAM_CPAS_DEFAULT_AXI_BW; - axi_vote.axi_path[0].mnoc_ib_bw = - CAM_CPAS_DEFAULT_AXI_BW; - - rc = cam_cpas_start(cci_dev->cpas_handle, - &ahb_vote, &axi_vote); - if (rc != 0) - CAM_ERR(CAM_CCI, "CPAS start failed"); + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; - cam_cci_get_clk_rates(cci_dev, c_ctrl); + rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_CCI, "CPAS start failed rc= %d", rc); + return rc; + } - /* Re-initialize the completion */ - reinit_completion(&cci_dev->cci_master_info[master].reset_complete); - reinit_completion(&cci_dev->cci_master_info[master].rd_done); - for (i = 0; i < NUM_QUEUES; i++) - reinit_completion( - &cci_dev->cci_master_info[master].report_q[i]); + cam_cci_get_clk_rates(cci_dev, c_ctrl); /* Enable Regulators and IRQ*/ rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_LOWSVS_VOTE, true); if (rc < 0) { - CAM_DBG(CAM_CCI, "request platform resources failed"); + CAM_DBG(CAM_CCI, "request platform resources failed, rc: %d", + rc); goto platform_enable_failed; } - cci_dev->hw_version = cam_io_r_mb(base + - CCI_HW_VERSION_ADDR); + cci_dev->hw_version = cam_io_r_mb(base + CCI_HW_VERSION_ADDR); CAM_DBG(CAM_CCI, "hw_version = 0x%x", cci_dev->hw_version); - cci_dev->payload_size = - MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; + cci_dev->payload_size = MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; cci_dev->support_seq_write = 1; - for (i = 0; i < NUM_MASTERS; i++) { - for (j = 0; j < NUM_QUEUES; j++) { - if (j == QUEUE_0) - cci_dev->cci_i2c_queue_info[i][j].max_queue_size - = CCI_I2C_QUEUE_0_SIZE; - else - cci_dev->cci_i2c_queue_info[i][j].max_queue_size - = CCI_I2C_QUEUE_1_SIZE; - - CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0 : %d Q1 : %d", i, - cci_dev->cci_i2c_queue_info[i][j].max_queue_size, - cci_dev->cci_i2c_queue_info[i][j].max_queue_size); - } - } - - cci_dev->cci_master_info[master].reset_pending = true; - cci_dev->cci_master_info[master].status = 0; - cam_io_w_mb(CCI_RESET_CMD_RMSK, base + - CCI_RESET_CMD_ADDR); - cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, - CCI_TIMEOUT); - if (rc <= 0) { - CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); - if (rc == 0) - rc = -ETIMEDOUT; + rc = cam_cci_init_master(cci_dev, master); + if (rc) { + CAM_ERR(CAM_CCI, "Failed to init: Master: %d, rc: %d", + master, rc); goto reset_complete_failed; } + for (i = 0; i < MASTER_MAX; i++) cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; - cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, - base + CCI_IRQ_MASK_0_ADDR); - cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, - base + CCI_IRQ_CLEAR_0_ADDR); - cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, - base + CCI_IRQ_MASK_1_ADDR); - cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, - base + CCI_IRQ_CLEAR_1_ADDR); - cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); - for (i = 0; i < MASTER_MAX; i++) { - if (!cci_dev->write_wq[i]) { - CAM_ERR(CAM_CCI, "Failed to flush write wq"); - rc = -ENOMEM; - goto reset_complete_failed; - } else { - flush_workqueue(cci_dev->write_wq[i]); - } - } + cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_MASK_0_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_MASK_1_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_CLEAR_1_ADDR); + cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); /* Set RD FIFO threshold for M0 & M1 */ cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, - base + CCI_I2C_M0_RD_THRESHOLD_ADDR); + base + CCI_I2C_M0_RD_THRESHOLD_ADDR); cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, - base + CCI_I2C_M1_RD_THRESHOLD_ADDR); + base + CCI_I2C_M1_RD_THRESHOLD_ADDR); cci_dev->cci_state = CCI_STATE_ENABLED; @@ -181,7 +191,6 @@ int cam_cci_init(struct v4l2_subdev *sd, reset_complete_failed: cam_soc_util_disable_platform_resource(soc_info, 1, 1); - platform_enable_failed: cci_dev->ref_count--; cam_cpas_stop(cci_dev->cpas_handle); @@ -201,9 +210,10 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) { uint8_t i = 0, j = 0; - for (i = 0; i < NUM_MASTERS; i++) { + for (i = 0; i < MASTER_MAX; i++) { new_cci_dev->cci_master_info[i].status = 0; new_cci_dev->cci_master_info[i].is_first_req = true; + new_cci_dev->cci_master_info[i].is_initilized = false; mutex_init(&new_cci_dev->cci_master_info[i].mutex); sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); @@ -382,27 +392,38 @@ int cam_cci_parse_dt_info(struct platform_device *pdev, return 0; } -int cam_cci_soc_release(struct cci_device *cci_dev) +int cam_cci_soc_release(struct cci_device *cci_dev, + enum cci_i2c_master_t master) { uint8_t i = 0, rc = 0; - struct cam_hw_soc_info *soc_info = - &cci_dev->soc_info; + struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; - if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { - CAM_ERR(CAM_CCI, "invalid ref count %d / cci state %d", - cci_dev->ref_count, cci_dev->cci_state); + if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED || + !cci_dev->master_active_slave[master]) { + CAM_ERR(CAM_CCI, + "invalid cci_dev_ref count %u | cci state %d | master_ref_count %u", + cci_dev->ref_count, cci_dev->cci_state, + cci_dev->master_active_slave[master]); return -EINVAL; } + + if (!(--cci_dev->master_active_slave[master])) { + cci_dev->cci_master_info[master].is_initilized = false; + CAM_DBG(CAM_CCI, + "All submodules are released for master: %d", master); + } + if (--cci_dev->ref_count) { - CAM_DBG(CAM_CCI, "ref_count Exit %d", cci_dev->ref_count); + CAM_DBG(CAM_CCI, "Submodule release: Ref_count: %d", + cci_dev->ref_count); return 0; } - for (i = 0; i < MASTER_MAX; i++) + + for (i = 0; i < MASTER_MAX; i++) { if (cci_dev->write_wq[i]) flush_workqueue(cci_dev->write_wq[i]); - - for (i = 0; i < MASTER_MAX; i++) cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; + } rc = cam_soc_util_disable_platform_resource(soc_info, true, true); if (rc) { diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h index f0cdfe822cd3..de1b20e6a74a 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_SOC_H_ @@ -23,7 +23,8 @@ int cam_cci_init(struct v4l2_subdev *sd, * * This API releases the CCI and its SOC resources */ -int cam_cci_soc_release(struct cci_device *cci_dev); +int cam_cci_soc_release(struct cci_device *cci_dev, + enum cci_i2c_master_t master); /** * @pdev: Platform device -- GitLab From 9546e8383ff776c268f97fb89ff963379cb6ba59 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 4 Sep 2020 12:47:50 +0530 Subject: [PATCH 337/410] msm: camera: ife: dump fill level registers on overflow Dump camnoc fill level registers for overflow and violations along with the SOF, EPOCH and EOF timestamps. CRs-Fixed: 2781154 Change-Id: I7e17a128e38a6f4a833314663cefe614d64958cf Signed-off-by: Tejas Prajapati --- drivers/cam_cpas/cam_cpas_intf.c | 20 ++++ drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 93 ++++++++++++++++++- drivers/cam_cpas/cpas_top/cam_cpastop_hw.h | 24 +++++ drivers/cam_cpas/cpas_top/cpastop_v150_100.h | 8 +- drivers/cam_cpas/cpas_top/cpastop_v170_110.h | 8 +- drivers/cam_cpas/cpas_top/cpastop_v170_200.h | 6 ++ drivers/cam_cpas/cpas_top/cpastop_v175_100.h | 8 +- drivers/cam_cpas/cpas_top/cpastop_v175_101.h | 8 +- drivers/cam_cpas/cpas_top/cpastop_v175_120.h | 9 +- drivers/cam_cpas/cpas_top/cpastop_v175_130.h | 9 +- drivers/cam_cpas/cpas_top/cpastop_v480_100.h | 9 +- drivers/cam_cpas/include/cam_cpas_api.h | 30 ++++++ .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 52 +++++------ .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 31 +++++-- .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 5 + 15 files changed, 273 insertions(+), 47 deletions(-) diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index d63ac2263355..bdb81b8f13ec 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -17,6 +17,7 @@ #include "cam_subdev.h" #include "cam_cpas_hw_intf.h" #include "cam_cpas_soc.h" +#include "cam_cpas_api.h" #define CAM_CPAS_DEV_NAME "cam-cpas" #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done) @@ -157,6 +158,25 @@ int cam_cpas_get_cpas_hw_version(uint32_t *hw_version) return 0; } +int cam_cpas_get_camnoc_fifo_fill_level_info( + uint32_t cpas_version, + uint32_t client_handle) +{ + int rc = 0; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + rc = cam_cpas_hw_get_camnoc_fill_level_info(cpas_version, + client_handle); + if (rc) + CAM_ERR(CAM_CPAS, "Failed to dump fifo reg rc %d", rc); + + return rc; +} + int cam_cpas_get_hw_info(uint32_t *camera_family, struct cam_hw_version *camera_version, struct cam_hw_version *cpas_version, diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index c284350e2142..47a4cc64059e 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -709,6 +709,97 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, return 0; } +int cam_cpas_hw_get_camnoc_fill_level_info( + uint32_t cpas_version, + uint32_t client_handle) +{ + struct cam_camnoc_fifo_lvl_info *camnoc_reg_info; + uint32_t val; + + if (!camnoc_info->fill_lvl_register) + return -EFAULT; + + camnoc_reg_info = camnoc_info->fill_lvl_register; + + switch (cpas_version) { + case CAM_CPAS_TITAN_175_V120: + case CAM_CPAS_TITAN_175_V130: + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, + camnoc_reg_info->IFE0_nRDI_maxwr_offset, + true, &val); + CAM_INFO(CAM_CPAS, "IFE0_nRDI_MAXWR_LOW offset 0x%x val 0x%x", + camnoc_reg_info->IFE0_nRDI_maxwr_offset, + val); + + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, + camnoc_reg_info->IFE1_nRDI_maxwr_offset, + true, &val); + CAM_INFO(CAM_CPAS, "IFE1_nRDI_MAXWR_LOW offset 0x%x val 0x%x", + camnoc_reg_info->IFE1_nRDI_maxwr_offset, + val); + + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, + camnoc_reg_info->IFE0123_RDI_maxwr_offset, + true, &val); + CAM_INFO(CAM_CPAS, "IFE0_nRDI_MAXWR_LOW offset 0x%x val 0x%x", + camnoc_reg_info->IFE0123_RDI_maxwr_offset, + val); + break; + case CAM_CPAS_TITAN_480_V100: + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, camnoc_reg_info->ife_linear, + true, &val); + CAM_INFO(CAM_CPAS, "ife_linear offset 0x%x val 0x%x", + camnoc_reg_info->ife_linear, + val); + + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, camnoc_reg_info->ife_rdi_wr, + true, &val); + CAM_INFO(CAM_CPAS, "ife_rdi_wr offset 0x%x val 0x%x", + camnoc_reg_info->ife_rdi_wr, + val); + + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, camnoc_reg_info->ife_ubwc_stats, + true, &val); + CAM_INFO(CAM_CPAS, "ife_ubwc_stats offset 0x%x val 0x%x", + camnoc_reg_info->ife_ubwc_stats, + val); + + break; + case CAM_CPAS_TITAN_150_V100: + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + case CAM_CPAS_TITAN_170_V200: + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, camnoc_reg_info->IFE02_MAXWR_LOW, + true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x%x val 0x%x", + camnoc_reg_info->IFE02_MAXWR_LOW, + val); + + cam_cpas_reg_read(client_handle, + CAM_CPAS_REG_CAMNOC, camnoc_reg_info->IFE13_MAXWR_LOW, + true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x%x val 0x%x", + camnoc_reg_info->IFE13_MAXWR_LOW, + val); + break; + default: + CAM_ERR(CAM_CPAS, "Camera version not supported %d", + cpas_version); + break; + } + return 0; +} + int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops) { if (!internal_ops) { diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h index 873d0f490e88..627e29faaa1b 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -256,6 +256,28 @@ struct cam_camnoc_err_logger_info { uint32_t errlog3_high; }; +/** + * struct cam_camnoc_fifo_lvl_info : Struct for fifo fill level registers + * @IFE0_nRDI_maxwr_offset: Register offset for fill level for IFE0 + * @IFE1_nRDI_maxwr_offset: Register offset for fill level for IFE1 + * @IFE0123_RDI_maxwr_low_offset: Register offset for RDI + * @ife_linear: Register offset for ife linear + * @ife_rdi_wr: Register offset for rdi wr + * @ife_ubwc_stats: Register offset for ubwc stats + * @IFE02_MAXWR_LOW: Register offset for IFE02 + * @IFE13_MAXWR_LOW: Register offset for IFE13 + */ +struct cam_camnoc_fifo_lvl_info { + uint32_t IFE0_nRDI_maxwr_offset; + uint32_t IFE1_nRDI_maxwr_offset; + uint32_t IFE0123_RDI_maxwr_offset; + uint32_t ife_linear; + uint32_t ife_rdi_wr; + uint32_t ife_ubwc_stats; + uint32_t IFE02_MAXWR_LOW; + uint32_t IFE13_MAXWR_LOW; +}; + /** * struct cam_camnoc_info : Overall CAMNOC settings info * @@ -266,6 +288,7 @@ struct cam_camnoc_err_logger_info { * @irq_err_size: Array size of IRQ Error settings * @err_logger: Pointer to CAMNOC IRQ Error logger read registers * @errata_wa_list: HW Errata workaround info + * @fill_level_register: Fill level registers * */ struct cam_camnoc_info { @@ -276,6 +299,7 @@ struct cam_camnoc_info { int irq_err_size; struct cam_camnoc_err_logger_info *err_logger; struct cam_cpas_hw_errata_wa_list *errata_wa_list; + struct cam_camnoc_fifo_lvl_info *fill_lvl_register; }; /** diff --git a/drivers/cam_cpas/cpas_top/cpastop_v150_100.h b/drivers/cam_cpas/cpas_top/cpastop_v150_100.h index df9711e74379..edad15043dda 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v150_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v150_100.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V150_100_H_ @@ -515,6 +515,11 @@ static struct cam_cpas_hw_errata_wa_list cam150_cpas100_errata_wa_list = { }, }; +struct cam_camnoc_fifo_lvl_info cam150_cpas100_camnoc_fifo_info = { + .IFE02_MAXWR_LOW = 0x420, + .IFE13_MAXWR_LOW = 0x820, +}; + static struct cam_camnoc_info cam150_cpas100_camnoc_info = { .specific = &cam_cpas_v150_100_camnoc_specific[0], .specific_size = sizeof(cam_cpas_v150_100_camnoc_specific) / @@ -525,6 +530,7 @@ static struct cam_camnoc_info cam150_cpas100_camnoc_info = { sizeof(cam_cpas_v150_100_irq_err[0]), .err_logger = &cam150_cpas100_err_logger_offsets, .errata_wa_list = &cam150_cpas100_errata_wa_list, + .fill_lvl_register = &cam150_cpas100_camnoc_fifo_info, }; #endif /* _CPASTOP_V150_100_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/cam_cpas/cpas_top/cpastop_v170_110.h index 788f571a3a13..fc986f598e33 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v170_110.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v170_110.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V170_110_H_ @@ -523,6 +523,11 @@ static struct cam_cpas_hw_errata_wa_list cam170_cpas110_errata_wa_list = { }, }; +struct cam_camnoc_fifo_lvl_info cam170_cpas110_camnoc_fifo_info = { + .IFE02_MAXWR_LOW = 0x420, + .IFE13_MAXWR_LOW = 0x820, +}; + static struct cam_camnoc_info cam170_cpas110_camnoc_info = { .specific = &cam_cpas110_camnoc_specific[0], .specific_size = sizeof(cam_cpas110_camnoc_specific) / @@ -533,6 +538,7 @@ static struct cam_camnoc_info cam170_cpas110_camnoc_info = { sizeof(cam_cpas110_irq_err[0]), .err_logger = &cam170_cpas110_err_logger_offsets, .errata_wa_list = &cam170_cpas110_errata_wa_list, + .fill_lvl_register = &cam170_cpas110_camnoc_fifo_info, }; #endif /* _CPASTOP_V170_110_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h index 4d4f3dac4703..d1ff25d9da59 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v170_200.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v170_200.h @@ -521,6 +521,11 @@ static struct cam_cpas_hw_errata_wa_list cam170_cpas200_errata_wa_list = { }, }; +struct cam_camnoc_fifo_lvl_info cam170_cpas200_camnoc_fifo_info = { + .IFE02_MAXWR_LOW = 0x420, + .IFE13_MAXWR_LOW = 0x820, +}; + static struct cam_camnoc_info cam170_cpas200_camnoc_info = { .specific = &cam_cpas_v170_200_camnoc_specific[0], .specific_size = ARRAY_SIZE(cam_cpas_v170_200_camnoc_specific), @@ -529,6 +534,7 @@ static struct cam_camnoc_info cam170_cpas200_camnoc_info = { .irq_err_size = ARRAY_SIZE(cam_cpas_v170_200_irq_err), .err_logger = &cam170_cpas200_err_logger_offsets, .errata_wa_list = &cam170_cpas200_errata_wa_list, + .fill_lvl_register = &cam170_cpas200_camnoc_fifo_info, }; #endif /* _CPASTOP_V170_200_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_100.h b/drivers/cam_cpas/cpas_top/cpastop_v175_100.h index aae26b5a9178..ab20db01cd18 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v175_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_100.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V175_100_H_ @@ -543,6 +543,11 @@ static struct cam_cpas_hw_errata_wa_list cam175_cpas100_errata_wa_list = { }, }; +struct cam_camnoc_fifo_lvl_info cam175_cpas100_camnoc_fifo_info = { + .IFE02_MAXWR_LOW = 0x420, + .IFE13_MAXWR_LOW = 0x820, +}; + static struct cam_camnoc_info cam175_cpas100_camnoc_info = { .specific = &cam_cpas_v175_100_camnoc_specific[0], .specific_size = sizeof(cam_cpas_v175_100_camnoc_specific) / @@ -553,6 +558,7 @@ static struct cam_camnoc_info cam175_cpas100_camnoc_info = { sizeof(cam_cpas_v175_100_irq_err[0]), .err_logger = &cam175_cpas100_err_logger_offsets, .errata_wa_list = &cam175_cpas100_errata_wa_list, + .fill_lvl_register = &cam175_cpas100_camnoc_fifo_info, }; #endif /* _CPASTOP_V175_100_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_101.h b/drivers/cam_cpas/cpas_top/cpastop_v175_101.h index 7ec9bec36fd1..12ed226008e6 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v175_101.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_101.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V175_101_H_ @@ -543,6 +543,11 @@ static struct cam_cpas_hw_errata_wa_list cam175_cpas101_errata_wa_list = { }, }; +struct cam_camnoc_fifo_lvl_info cam175_cpas101_camnoc_fifo_info = { + .IFE02_MAXWR_LOW = 0x420, + .IFE13_MAXWR_LOW = 0x820, +}; + static struct cam_camnoc_info cam175_cpas101_camnoc_info = { .specific = &cam_cpas_v175_101_camnoc_specific[0], .specific_size = sizeof(cam_cpas_v175_101_camnoc_specific) / @@ -553,6 +558,7 @@ static struct cam_camnoc_info cam175_cpas101_camnoc_info = { sizeof(cam_cpas_v175_101_irq_err[0]), .err_logger = &cam175_cpas101_err_logger_offsets, .errata_wa_list = &cam175_cpas101_errata_wa_list, + .fill_lvl_register = &cam175_cpas101_camnoc_fifo_info, }; #endif /* _CPASTOP_V175_101_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_120.h b/drivers/cam_cpas/cpas_top/cpastop_v175_120.h index 5844c38ae52c..83e5fb415472 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v175_120.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_120.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V175_120_H_ @@ -747,6 +747,12 @@ static struct cam_cpas_hw_errata_wa_list cam175_cpas120_errata_wa_list = { }, }; +static struct cam_camnoc_fifo_lvl_info cam175_cpas120_camnoc_fifo_info = { + .IFE0_nRDI_maxwr_offset = 0x3A20, + .IFE1_nRDI_maxwr_offset = 0x5420, + .IFE0123_RDI_maxwr_offset = 0x3620, +}; + static struct cam_camnoc_info cam175_cpas120_camnoc_info = { .specific = &cam_cpas_v175_120_camnoc_specific[0], .specific_size = ARRAY_SIZE(cam_cpas_v175_120_camnoc_specific), @@ -755,6 +761,7 @@ static struct cam_camnoc_info cam175_cpas120_camnoc_info = { .irq_err_size = ARRAY_SIZE(cam_cpas_v175_120_irq_err), .err_logger = &cam175_cpas120_err_logger_offsets, .errata_wa_list = &cam175_cpas120_errata_wa_list, + .fill_lvl_register = &cam175_cpas120_camnoc_fifo_info, }; #endif /* _CPASTOP_V175_120_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h index 769e77fc3d6b..f7acca0f039f 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v175_130.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v175_130.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V175_130_H_ @@ -760,6 +760,12 @@ static struct cam_cpas_hw_errata_wa_list cam175_cpas130_errata_wa_list = { }, }; +static struct cam_camnoc_fifo_lvl_info cam175_cpas130_camnoc_fifo_info = { + .IFE0_nRDI_maxwr_offset = 0x3A20, + .IFE1_nRDI_maxwr_offset = 0x5420, + .IFE0123_RDI_maxwr_offset = 0x3620, +}; + static struct cam_camnoc_info cam175_cpas130_camnoc_info = { .specific = &cam_cpas_v175_130_camnoc_specific[0], .specific_size = ARRAY_SIZE(cam_cpas_v175_130_camnoc_specific), @@ -768,6 +774,7 @@ static struct cam_camnoc_info cam175_cpas130_camnoc_info = { .irq_err_size = ARRAY_SIZE(cam_cpas_v175_130_irq_err), .err_logger = &cam175_cpas130_err_logger_offsets, .errata_wa_list = &cam175_cpas130_errata_wa_list, + .fill_lvl_register = &cam175_cpas130_camnoc_fifo_info, }; #endif /* _CPASTOP_V175_130_H_ */ diff --git a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h index 0d46e0ddcc20..49b1e8fb63a1 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v480_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CPASTOP_V480_100_H_ @@ -698,6 +698,12 @@ static struct cam_cpas_hw_errata_wa_list cam480_cpas100_errata_wa_list = { }, }; +struct cam_camnoc_fifo_lvl_info cam480_cpas100_camnoc_fifo_info = { + .ife_linear = 0xA20, + .ife_rdi_wr = 0x1420, + .ife_ubwc_stats = 0x1A20, +}; + static struct cam_camnoc_info cam480_cpas100_camnoc_info = { .specific = &cam_cpas_v480_100_camnoc_specific[0], .specific_size = ARRAY_SIZE(cam_cpas_v480_100_camnoc_specific), @@ -706,6 +712,7 @@ static struct cam_camnoc_info cam480_cpas100_camnoc_info = { .irq_err_size = ARRAY_SIZE(cam_cpas_v480_100_irq_err), .err_logger = &cam480_cpas100_err_logger_offsets, .errata_wa_list = &cam480_cpas100_errata_wa_list, + .fill_lvl_register = &cam480_cpas100_camnoc_fifo_info, }; #endif /* _CPASTOP_V480_100_H_ */ diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index d36800bd13b8..9256d9624768 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -585,6 +585,21 @@ int cam_cpas_get_hw_info( int cam_cpas_get_cpas_hw_version( uint32_t *hw_version); +/** + * cam_cpas_get_camnoc_fifo_fill_level_info() + * + * @brief: API to get camera camnoc hw version + * + * @cpas_version: hw version + * @client_handle: cpas client handle + * + * @return 0 on success. + * + */ +int cam_cpas_get_camnoc_fifo_fill_level_info( + uint32_t cpas_version, + uint32_t client_handle); + /** * cam_cpas_is_feature_supported() * @@ -635,4 +650,19 @@ const char *cam_cpas_axi_util_trans_type_to_string( */ void cam_cpas_log_votes(void); +/** + * cam_cpas_hw_get_camnoc_fill_level_info() + * + * @brief: API to get camnoc info + * + * @cpas_version: cpas hw version + * @client_handle: cpas client handle + * + * @return 0 on success. + * + */ +int cam_cpas_hw_get_camnoc_fill_level_info( + uint32_t cpas_version, + uint32_t client_handle); + #endif /* _CAM_CPAS_API_H_ */ diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 4cba4ce8a7b0..2de3cc5510e9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -507,7 +507,6 @@ static int cam_vfe_camif_reg_dump( struct cam_isp_resource_node *camif_res) { struct cam_vfe_mux_camif_data *camif_priv; - struct cam_vfe_soc_private *soc_private; uint32_t offset, val, wm_idx; if (!camif_res) { @@ -539,34 +538,6 @@ static int cam_vfe_camif_reg_dump( } } - soc_private = camif_priv->soc_info->soc_private; - if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || - soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); - CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", - val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); - CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", - val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); - CAM_INFO(CAM_ISP, - "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); - - } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x420, true, &val); - CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); - - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x820, true, &val); - CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); - } - return 0; } @@ -898,6 +869,15 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, camif_priv->event_cb(camif_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + CAM_INFO(CAM_ISP, + "SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); + CAM_INFO(CAM_ISP, "Violation status = %x", payload->irq_reg_val[2]); @@ -906,6 +886,9 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, CAM_INFO(CAM_ISP, "ife_clk_src:%lld", soc_private->ife_clk_src); + cam_cpas_get_camnoc_fifo_fill_level_info( + soc_private->cpas_version, + soc_private->cpas_handle); cam_cpas_log_votes(); if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) @@ -915,6 +898,14 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { CAM_DBG(CAM_ISP, "Received ERROR"); + CAM_INFO(CAM_ISP, + "SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); ktime_get_boottime_ts64(&ts); if (camif_priv->event_cb) @@ -930,6 +921,9 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, CAM_INFO(CAM_ISP, "ife_clk_src:%lld", soc_private->ife_clk_src); + cam_cpas_get_camnoc_fifo_fill_level_info( + soc_private->cpas_version, + soc_private->cpas_handle); cam_cpas_log_votes(); if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 6dc010d9f6d6..6a827829a091 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -938,7 +938,6 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, uint32_t violation_mask = 0x3F, module_id = 0; uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; struct cam_vfe_soc_private *soc_private; - uint32_t val0, val1, val2; if (!status) { CAM_ERR(CAM_ISP, "Invalid params"); @@ -1025,15 +1024,11 @@ static void cam_vfe_camif_ver3_print_status(uint32_t *status, CAM_INFO(CAM_ISP, "PDAF BUS OVERFLOW"); soc_private = camif_priv->soc_info->soc_private; - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); - cam_cpas_reg_read(soc_private->cpas_handle, - CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); - CAM_INFO(CAM_ISP, - "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", - val0, val1, val2); + + cam_cpas_get_camnoc_fifo_fill_level_info( + soc_private->cpas_version, + soc_private->cpas_handle); + cam_cpas_log_votes(); return; } @@ -1441,6 +1436,14 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, & camif_priv->reg_data->error_irq_mask0) { CAM_ERR(CAM_ISP, "VFE:%d Overflow", evt_info.hw_idx); + CAM_INFO(CAM_ISP, + "SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); ktime_get_boottime_ts64(&ts); CAM_INFO(CAM_ISP, "current monotonic time stamp seconds %lld:%lld", @@ -1473,6 +1476,14 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); + CAM_INFO(CAM_ISP, + "SOF %lld:%lld EPOCH %lld:%lld EOF %lld:%lld", + camif_priv->sof_ts.tv_sec, + camif_priv->sof_ts.tv_usec, + camif_priv->epoch_ts.tv_sec, + camif_priv->epoch_ts.tv_usec, + camif_priv->eof_ts.tv_sec, + camif_priv->eof_ts.tv_usec); ktime_get_boottime_ts64(&ts); CAM_INFO(CAM_ISP, "current monotonic time stamp seconds %lld:%lld", diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 9649cfedf47b..b932c83b46d0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -14,6 +14,7 @@ #include "cam_cdm_util.h" #include "cam_irq_controller.h" #include "cam_tasklet_util.h" +#include "cam_cpas_api.h" struct cam_vfe_mux_rdi_data { void __iomem *mem_base; @@ -539,6 +540,10 @@ static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, rdi_priv->event_cb(rdi_priv->priv, CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + cam_cpas_get_camnoc_fifo_fill_level_info( + soc_private->cpas_version, + soc_private->cpas_handle); cam_cpas_log_votes(); } end: -- GitLab From 4ae949790322c450a9acdedf73a85b8c88c379ac Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Wed, 26 Aug 2020 23:00:38 +0800 Subject: [PATCH 338/410] msm: camera: reqmgr: Workqueue congestion handling When workqueue is congested, CRM may apply same request to device which will trigger recovery due to apply fails. This change prevent CRM triggering recovery if the current idx is same with last applied idx. CRs-Fixed: 2761601 Change-Id: I6ccf44f050a18e8a2a35916f61513ad852e7bdee Signed-off-by: Depeng Shao --- drivers/cam_req_mgr/cam_req_mgr_core.c | 34 +++++++++++++++----------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 47e9eda4d7a3..dd05424d54a6 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1495,20 +1495,26 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, rc = __cam_req_mgr_send_req(link, link->req.in_q, trigger, &dev); if (rc < 0) { - /* Apply req failed retry at next sof */ - slot->status = CRM_SLOT_STATUS_REQ_PENDING; - link->retry_cnt++; - max_retry = MAXIMUM_RETRY_ATTEMPTS; - if (link->max_delay == 1) - max_retry++; - if (link->retry_cnt == max_retry) { - CAM_DBG(CAM_CRM, - "Max retry attempts (count: %d) reached on link[0x%x] for req [%lld]", - link->retry_cnt, link->link_hdl, - in_q->slot[in_q->rd_idx].req_id); - __cam_req_mgr_notify_error_on_link(link, dev); - link->retry_cnt = 0; - } + if (in_q->last_applied_idx < in_q->rd_idx) { + /* Apply req failed retry at next sof */ + slot->status = CRM_SLOT_STATUS_REQ_PENDING; + link->retry_cnt++; + max_retry = MAXIMUM_RETRY_ATTEMPTS; + if (link->max_delay == 1) + max_retry++; + if (link->retry_cnt == max_retry) { + CAM_DBG(CAM_CRM, + "Max retry attempts (count: %d) reached on link[0x%x] for req [%lld]", + link->retry_cnt, link->link_hdl, + in_q->slot[in_q->rd_idx].req_id); + __cam_req_mgr_notify_error_on_link(link, dev); + link->retry_cnt = 0; + } + } else + CAM_WARN(CAM_CRM, + "workqueue congestion, last applied idx:%d rd idx:%d", + in_q->last_applied_idx, + in_q->rd_idx); } else { if (link->retry_cnt) link->retry_cnt = 0; -- GitLab From f4e828e29f5acc2c36e56d68ae8c897f8561ef4d Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Tue, 15 Sep 2020 17:41:21 +0800 Subject: [PATCH 339/410] msm: camera: reqmgr: Add protection for workqueue congestion When workqueue is congested, CRM may apply same request to device which will trigger recovery due to apply fails. This change prevent CRM triggering recovery if the time interval of continuous applying req less than 5ms. CRs-Fixed: 2775372 Change-Id: I45c2ed76334b1bbf4547bbf21f90cf0a6c169323 Signed-off-by: Depeng Shao --- drivers/cam_req_mgr/cam_req_mgr_core.c | 24 +++++++++++++++++++++--- drivers/cam_req_mgr/cam_req_mgr_core.h | 5 ++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index dd05424d54a6..da1c1a2d5086 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -50,6 +50,7 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) link->sof_timestamp = 0; link->prev_sof_timestamp = 0; link->skip_wd_validation = false; + link->last_applied_jiffies = 0; } void cam_req_mgr_handle_core_shutdown(void) @@ -1376,6 +1377,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, { int rc = 0, idx; int reset_step = 0; + bool check_retry_cnt = false; uint32_t trigger = trigger_data->trigger; struct cam_req_mgr_slot *slot = NULL; struct cam_req_mgr_req_queue *in_q; @@ -1495,9 +1497,15 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, rc = __cam_req_mgr_send_req(link, link->req.in_q, trigger, &dev); if (rc < 0) { - if (in_q->last_applied_idx < in_q->rd_idx) { - /* Apply req failed retry at next sof */ - slot->status = CRM_SLOT_STATUS_REQ_PENDING; + /* Apply req failed retry at next sof */ + slot->status = CRM_SLOT_STATUS_REQ_PENDING; + + if (jiffies_to_msecs(jiffies - link->last_applied_jiffies) > + MINIMUM_WORKQUEUE_SCHED_TIME_IN_MS) + check_retry_cnt = true; + + if ((in_q->last_applied_idx < in_q->rd_idx) && + check_retry_cnt) { link->retry_cnt++; max_retry = MAXIMUM_RETRY_ATTEMPTS; if (link->max_delay == 1) @@ -1563,6 +1571,16 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, } } + /* + * Only update the jiffies of last applied request + * for SOF trigger, since it is used to protect from + * applying fails in ISP which is triggered at SOF. + * And, also don't need to do update for error case + * since error case doesn't check the retry count. + */ + if (trigger == CAM_TRIGGER_POINT_SOF) + link->last_applied_jiffies = jiffies; + mutex_unlock(&session->lock); return rc; error: diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 2c6fd738ff0d..106af51f9c1e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -35,6 +35,8 @@ #define MAXIMUM_RETRY_ATTEMPTS 2 +#define MINIMUM_WORKQUEUE_SCHED_TIME_IN_MS 5 + #define VERSION_1 1 #define VERSION_2 2 #define CAM_REQ_MGR_MAX_TRIGGERS 2 @@ -351,6 +353,7 @@ struct cam_req_mgr_connected_device { * @trigger_cnt : trigger count value per device initiating the trigger * @skip_wd_validation : skip initial frames crm_wd_timer validation in the * case of long exposure use case + * @last_applied_jiffies : Record the jiffies of last applied req */ struct cam_req_mgr_core_link { int32_t link_hdl; @@ -384,7 +387,7 @@ struct cam_req_mgr_core_link { bool dual_trigger; uint32_t trigger_cnt[CAM_REQ_MGR_MAX_TRIGGERS]; bool skip_wd_validation; - + uint64_t last_applied_jiffies; }; /** -- GitLab From 2495d5827243067eeec69a68c592494eb955f59d Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Sat, 12 Sep 2020 00:11:53 +0530 Subject: [PATCH 340/410] msm: camera: cci: Fix logic to update cci clk freq When multiple frequency slaves running on a same I2C bus, then there is a chance of overriding I2C bus frequency even if another I2C operation is running. This could lead to CCI timeout at driver level. Updated synchronization logic, to properly update I2C clock frequency, only when no other I2C operation running. CRs-Fixed: 2800250 Change-Id: Ia341d7cda118497bf1acea8ea59f7f03124f31c3 Signed-off-by: Anil Kumar Kanakanti --- .../cam_sensor_module/cam_cci/cam_cci_core.c | 158 ++++++------------ .../cam_sensor_module/cam_cci/cam_cci_dev.h | 3 +- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 4 +- 3 files changed, 56 insertions(+), 109 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index 3bb399fe4271..f0f91289887f 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -575,19 +575,42 @@ static int32_t cam_cci_set_clk_param(struct cci_device *cci_dev, struct cam_cci_clk_params_t *clk_params = NULL; enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; enum i2c_freq_mode i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; - struct cam_hw_soc_info *soc_info = - &cci_dev->soc_info; - void __iomem *base = soc_info->reg_map[0].mem_base; + void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base; + struct cam_cci_master_info *cci_master = + &cci_dev->cci_master_info[master]; if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { CAM_ERR(CAM_CCI, "invalid i2c_freq_mode = %d", i2c_freq_mode); return -EINVAL; } + /* + * If no change in i2c freq, then acquire semaphore only for the first + * i2c transaction to indicate I2C transaction is in progress, else + * always try to acquire semaphore, to make sure that no other I2C + * transaction is in progress. + */ + mutex_lock(&cci_master->mutex); + if (i2c_freq_mode == cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d", master, + i2c_freq_mode); + spin_lock(&cci_master->freq_cnt_lock); + if (cci_master->freq_ref_cnt == 0) + down(&cci_master->master_sem); + cci_master->freq_ref_cnt++; + spin_unlock(&cci_master->freq_cnt_lock); + mutex_unlock(&cci_master->mutex); + return 0; + } + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], i2c_freq_mode); + down(&cci_master->master_sem); + + spin_lock(&cci_master->freq_cnt_lock); + cci_master->freq_ref_cnt++; + spin_unlock(&cci_master->freq_cnt_lock); clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; - if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode) - return 0; if (master == MASTER_0) { cam_io_w_mb(clk_params->hw_thigh << 16 | clk_params->hw_tlow, @@ -621,6 +644,7 @@ static int32_t cam_cci_set_clk_param(struct cci_device *cci_dev, } cci_dev->i2c_freq_mode[master] = i2c_freq_mode; + mutex_unlock(&cci_master->mutex); return 0; } @@ -899,42 +923,19 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, return -EINVAL; } - soc_info = &cci_dev->soc_info; - base = soc_info->reg_map[0].mem_base; - - mutex_lock(&cci_dev->cci_master_info[master].mutex); - if (cci_dev->cci_master_info[master].is_first_req) { - cci_dev->cci_master_info[master].is_first_req = false; - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - down(&cci_dev->cci_master_info[master].master_sem); - } else if (c_ctrl->cci_info->i2c_freq_mode - != cci_dev->i2c_freq_mode[master]) { - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - down(&cci_dev->cci_master_info[master].master_sem); - } else { - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - spin_lock(&cci_dev->cci_master_info[master].freq_cnt); - cci_dev->cci_master_info[master].freq_ref_cnt++; - spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); - } - /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - goto rel_master; + return rc; } - mutex_unlock(&cci_dev->cci_master_info[master].mutex); mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1146,13 +1147,11 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, rel_mutex_q: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); -rel_master: - spin_lock(&cci_dev->cci_master_info[master].freq_cnt); - if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + + spin_lock(&cci_dev->cci_master_info[master].freq_cnt_lock); + if (--cci_dev->cci_master_info[master].freq_ref_cnt == 0) up(&cci_dev->cci_master_info[master].master_sem); - else - cci_dev->cci_master_info[master].freq_ref_cnt--; - spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt_lock); return rc; } @@ -1177,46 +1176,24 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX || c_ctrl->cci_info->cci_i2c_master < 0) { - CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + CAM_ERR(CAM_CCI, "Invalid I2C master addr:%d", + c_ctrl->cci_info->cci_i2c_master); return -EINVAL; } - soc_info = &cci_dev->soc_info; - base = soc_info->reg_map[0].mem_base; - - mutex_lock(&cci_dev->cci_master_info[master].mutex); - if (cci_dev->cci_master_info[master].is_first_req) { - cci_dev->cci_master_info[master].is_first_req = false; - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - down(&cci_dev->cci_master_info[master].master_sem); - } else if (c_ctrl->cci_info->i2c_freq_mode - != cci_dev->i2c_freq_mode[master]) { - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - down(&cci_dev->cci_master_info[master].master_sem); - } else { - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - spin_lock(&cci_dev->cci_master_info[master].freq_cnt); - cci_dev->cci_master_info[master].freq_ref_cnt++; - spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); - } - /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { - mutex_unlock(&cci_dev->cci_master_info[master].mutex); CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - goto rel_master; + return rc; } - mutex_unlock(&cci_dev->cci_master_info[master].mutex); mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1366,13 +1343,11 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, } rel_mutex_q: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); -rel_master: - spin_lock(&cci_dev->cci_master_info[master].freq_cnt); - if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + + spin_lock(&cci_dev->cci_master_info[master].freq_cnt_lock); + if (--cci_dev->cci_master_info[master].freq_ref_cnt == 0) up(&cci_dev->cci_master_info[master].master_sem); - else - cci_dev->cci_master_info[master].freq_ref_cnt--; - spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt_lock); return rc; } @@ -1396,37 +1371,12 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, c_ctrl->cci_info->id_map); - mutex_lock(&cci_dev->cci_master_info[master].mutex); - if (cci_dev->cci_master_info[master].is_first_req) { - cci_dev->cci_master_info[master].is_first_req = false; - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - down(&cci_dev->cci_master_info[master].master_sem); - } else if (c_ctrl->cci_info->i2c_freq_mode - != cci_dev->i2c_freq_mode[master]) { - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - down(&cci_dev->cci_master_info[master].master_sem); - } else { - CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", - master, cci_dev->i2c_freq_mode[master], - c_ctrl->cci_info->i2c_freq_mode); - spin_lock(&cci_dev->cci_master_info[master].freq_cnt); - cci_dev->cci_master_info[master].freq_ref_cnt++; - spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); - } - /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - goto ERROR; + return rc; } - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); /* * Call validate queue to make sure queue is empty before starting. @@ -1452,12 +1402,10 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, } ERROR: - spin_lock(&cci_dev->cci_master_info[master].freq_cnt); - if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + spin_lock(&cci_dev->cci_master_info[master].freq_cnt_lock); + if (--cci_dev->cci_master_info[master].freq_ref_cnt == 0) up(&cci_dev->cci_master_info[master].master_sem); - else - cci_dev->cci_master_info[master].freq_ref_cnt--; - spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt_lock); return rc; } diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index 410986975e1b..1aee97cf4ee4 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -133,9 +133,8 @@ struct cam_cci_master_info { struct completion report_q[NUM_QUEUES]; atomic_t done_pending[NUM_QUEUES]; spinlock_t lock_q[NUM_QUEUES]; - spinlock_t freq_cnt; struct semaphore master_sem; - bool is_first_req; + spinlock_t freq_cnt_lock; uint16_t freq_ref_cnt; bool is_initilized; }; diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index a8b47120a439..10f274c907eb 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -212,11 +212,11 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) for (i = 0; i < MASTER_MAX; i++) { new_cci_dev->cci_master_info[i].status = 0; - new_cci_dev->cci_master_info[i].is_first_req = true; new_cci_dev->cci_master_info[i].is_initilized = false; + new_cci_dev->cci_master_info[i].freq_ref_cnt = 0; mutex_init(&new_cci_dev->cci_master_info[i].mutex); sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); - spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); + spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt_lock); init_completion( &new_cci_dev->cci_master_info[i].reset_complete); init_completion( -- GitLab From 5cbba7147911689d8810b3ce0a4399b00c3077be Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Fri, 18 Sep 2020 00:25:06 +0530 Subject: [PATCH 341/410] msm: camera: isp: Dump buffer address on page fault This is debug change to dump last consumer address and current consume buffer address on page fault. CRs-Fixed: 2797725 Change-Id: I0b5120982e474962568c98d897d2e1739b8e4b9b Signed-off-by: Ayush Kumar --- drivers/cam_core/cam_hw_mgr_intf.h | 2 + drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 51 +++++++++++++++++-- .../hw_utils/cam_isp_packet_parser.c | 18 +++++++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 2 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 28 +++++++++- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 31 +++++++++-- 6 files changed, 124 insertions(+), 8 deletions(-) diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 2168146a30ca..8339fc9cb24e 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -70,11 +70,13 @@ struct cam_hw_update_entry { * * @resrouce_handle: Resource port id for the buffer * @sync_id: Sync id + * @image_buf_addr: Image buffer address array * */ struct cam_hw_fence_map_entry { uint32_t resource_handle; int32_t sync_id; + int32_t image_buf_addr[CAM_PACKET_MAX_PLANES]; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index f99355b59958..1fe034e31f26 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -39,6 +39,9 @@ #define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ (CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG + 1) +static int cam_ife_hw_mgr_handle_hw_dump_bus_info( + void *ctx, void *evt_info); + static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, CAM_ISP_HW_CMD_CLOCK_UPDATE, @@ -6386,13 +6389,14 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { - int rc = 0; + int i, rc = 0; struct cam_hw_cmd_args *hw_cmd_args = cmd_args; struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_ife_hw_mgr_ctx *ctx = (struct cam_ife_hw_mgr_ctx *) hw_cmd_args->ctxt_to_hw_map; - struct cam_isp_hw_cmd_args *isp_hw_cmd_args = NULL; - struct cam_packet *packet; + struct cam_isp_hw_cmd_args *isp_hw_cmd_args = NULL; + struct cam_packet *packet; + struct cam_isp_hw_event_info event_info; unsigned long rem_jiffies = 0; if (!hw_mgr_priv || !cmd_args) { @@ -6462,6 +6466,15 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_mgr->mgr_common.img_iommu_hdl_secure, hw_cmd_args->u.pf_args.buf_info, hw_cmd_args->u.pf_args.mem_found); + event_info.err_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + event_info.res_type = CAM_ISP_RESOURCE_VFE_OUT; + event_info.hw_idx = 0; + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + event_info.res_id = + CAM_ISP_IFE_OUT_RES_BASE + (i & 0xFF); + cam_ife_hw_mgr_handle_hw_dump_bus_info(ctx, + &event_info); + } break; case CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH: if (ctx->last_dump_flush_req_id == ctx->applied_req_id) @@ -7010,6 +7023,38 @@ static int cam_ife_hw_mgr_handle_csid_event( return 0; } +static int cam_ife_hw_mgr_handle_hw_dump_bus_info( + void *ctx, + void *evt_info) +{ + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = + (struct cam_ife_hw_mgr_ctx *)ctx; + struct cam_isp_hw_event_info *event_info = + (struct cam_isp_hw_event_info *)evt_info; + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_hw_intf *hw_intf; + uint32_t i, out_port_id; + int rc = 0; + + out_port_id = event_info->res_id & 0xFF; + hw_mgr_res = + &ife_hw_mgr_ctx->res_list_ife_out[out_port_id]; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_BUS_INFO, + (void *)event_info, + sizeof(struct cam_isp_hw_event_info)); + } + } + + return rc; +} + static int cam_ife_hw_mgr_handle_hw_dump_info( void *ctx, void *evt_info) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index e1e15dbb76d1..4011c9956b67 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -480,6 +480,8 @@ int cam_isp_add_io_buffers( uint32_t i, j, num_out_buf, num_in_buf; uint32_t res_id_out, res_id_in, plane_id; uint32_t io_cfg_used_bytes, num_ent; + uint32_t *image_buf_addr; + uint32_t *image_buf_offset; uint64_t iova_addr; size_t size; int32_t hdl; @@ -682,6 +684,10 @@ int cam_isp_add_io_buffers( wm_update.num_buf = plane_id; wm_update.io_cfg = &io_cfg[i]; wm_update.frame_header = 0; + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) + wm_update.image_buf_offset[plane_id] = 0; + iova_addr = frame_header_info->frame_header_iova_addr; if ((frame_header_info->frame_header_enable) && !(frame_header_info->frame_header_res_id)) { @@ -714,6 +720,18 @@ int cam_isp_add_io_buffers( return rc; } io_cfg_used_bytes += update_buf.cmd.used_bytes; + image_buf_addr = + out_map_entries->image_buf_addr; + image_buf_offset = + wm_update.image_buf_offset; + if (j == CAM_ISP_HW_SPLIT_LEFT) { + for (plane_id = 0; + plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) + image_buf_addr[plane_id] = + io_addr[plane_id] + + image_buf_offset[plane_id]; + } } for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && io_cfg[i].direction == CAM_BUF_INPUT; j++) { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index a82d20f40f40..ef0d744ba74d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -220,6 +220,7 @@ struct cam_isp_hw_cmd_buf_update { * @Brief: Get cmd buffer for WM updates. * * @ image_buf: image buffer address array + * @ image_buf_offset: image buffer address offset array * @ num_buf: Number of buffers in the image_buf array * @ frame_header: frame header iova * @ local_id: local id for the wm @@ -228,6 +229,7 @@ struct cam_isp_hw_cmd_buf_update { */ struct cam_isp_hw_get_wm_update { dma_addr_t *image_buf; + uint32_t image_buf_offset[CAM_PACKET_MAX_PLANES]; uint32_t num_buf; uint64_t frame_header; uint32_t local_id; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index fa12389f9dd9..62c7089bf95f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -3161,17 +3161,22 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, /* WM Image address */ for (k = 0; k < loop_size; k++) { - if (wm_data->en_ubwc) + if (wm_data->en_ubwc) { CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_addr, update_buf->wm_update->image_buf[i] + io_cfg->planes[i].meta_size + k * frame_inc); - else + update_buf->wm_update->image_buf_offset[i] = + io_cfg->planes[i].meta_size; + } else { CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_addr, update_buf->wm_update->image_buf[i] + wm_data->offset + k * frame_inc); + update_buf->wm_update->image_buf_offset[i] = + wm_data->offset; + } CAM_DBG(CAM_ISP, "WM %d image address 0x%x", wm_data->index, reg_val_pair[j-1]); } @@ -3754,11 +3759,19 @@ int cam_vfe_bus_dump_wm_data(void *priv, void *cmd_args, uint32_t arg_size) struct cam_isp_resource_node *rsrc_node = NULL; struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_vfe_bus_ver2_common_data *common_data = NULL; int i, wm_idx; enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id; + uint32_t addr_status0, addr_status1; vfe_out_res_id = cam_vfe_bus_get_out_res_id(event_info->res_id); rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; + if (!rsrc_node) { + CAM_DBG(CAM_ISP, + "Resource with res id %d is null", + vfe_out_res_id); + return -EINVAL; + } rsrc_data = rsrc_node->res_priv; for (i = 0; i < rsrc_data->num_wm; i++) { wm_idx = cam_vfe_bus_get_wm_idx(vfe_out_res_id, i); @@ -3768,6 +3781,11 @@ int cam_vfe_bus_dump_wm_data(void *priv, void *cmd_args, uint32_t arg_size) return -EINVAL; } wm_data = bus_priv->bus_client[wm_idx].res_priv; + common_data = rsrc_data->common_data; + addr_status0 = cam_io_r_mb(common_data->mem_base + + wm_data->hw_regs->status0); + addr_status1 = cam_io_r_mb(common_data->mem_base + + wm_data->hw_regs->status1); CAM_INFO(CAM_ISP, "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", wm_data->common_data->core_index, wm_idx, @@ -3777,6 +3795,12 @@ int cam_vfe_bus_dump_wm_data(void *priv, void *cmd_args, uint32_t arg_size) wm_data->en_cfg, wm_data->acquired_width, wm_data->acquired_height); + CAM_INFO(CAM_ISP, + "hw:%d WM:%d current client address:0x%x current frame header addr:0x%x", + common_data->hw_intf->hw_idx, + wm_data->index, + addr_status0, + addr_status1); } return 0; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 1b108e51e5a1..29f9e6618cdc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -2455,6 +2455,8 @@ static int cam_vfe_bus_ver3_print_dimensions( struct cam_isp_resource_node *rsrc_node = NULL; struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_vfe_bus_ver3_common_data *common_data = NULL; + uint32_t addr_status0, addr_status1, addr_status2, addr_status3; int i, wm_idx; rsrc_node = &bus_priv->vfe_out[vfe_out_res_id]; @@ -2468,6 +2470,15 @@ static int cam_vfe_bus_ver3_print_dimensions( return -EINVAL; } wm_data = bus_priv->bus_client[wm_idx].res_priv; + common_data = rsrc_data->common_data; + addr_status0 = cam_io_r_mb(common_data->mem_base + + wm_data->hw_regs->addr_status_0); + addr_status1 = cam_io_r_mb(common_data->mem_base + + wm_data->hw_regs->addr_status_1); + addr_status2 = cam_io_r_mb(common_data->mem_base + + wm_data->hw_regs->addr_status_2); + addr_status3 = cam_io_r_mb(common_data->mem_base + + wm_data->hw_regs->addr_status_3); CAM_INFO(CAM_ISP, "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u acquired width:%u height:%u", wm_data->common_data->core_index, wm_idx, @@ -2477,6 +2488,14 @@ static int cam_vfe_bus_ver3_print_dimensions( wm_data->en_cfg, wm_data->acquired_width, wm_data->acquired_height); + CAM_INFO(CAM_ISP, + "hw:%d WM:%d last consumed address:0x%x last frame addr:0x%x fifo cnt:0x%x current client address:0x%x", + common_data->hw_intf->hw_idx, + wm_data->index, + addr_status0, + addr_status1, + addr_status2, + addr_status3); } return 0; } @@ -3144,22 +3163,28 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, /* WM Image address */ for (k = 0; k < loop_size; k++) { - if (wm_data->en_ubwc) + if (wm_data->en_ubwc) { CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_addr, update_buf->wm_update->image_buf[i] + io_cfg->planes[i].meta_size + k * frame_inc); - else if (wm_data->en_cfg & (0x3 << 16)) + update_buf->wm_update->image_buf_offset[i] = + io_cfg->planes[i].meta_size; + } else if (wm_data->en_cfg & (0x3 << 16)) { CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_addr, (update_buf->wm_update->image_buf[i] + wm_data->offset + k * frame_inc)); - else + update_buf->wm_update->image_buf_offset[i] = + wm_data->offset; + } else { CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->image_addr, (update_buf->wm_update->image_buf[i] + k * frame_inc)); + update_buf->wm_update->image_buf_offset[i] = 0; + } CAM_DBG(CAM_ISP, "WM:%d image address 0x%X", wm_data->index, reg_val_pair[j-1]); -- GitLab From 49708f867b28f80dacfdcd928475682cf7ffe05c Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 3 Dec 2020 19:21:16 +0530 Subject: [PATCH 342/410] msm: camera: isp: Increment bubble frame count correctly In certain scenarios due to tasklet congestion, back to back sof were seen and this will lead to wrong bubble frame count. As a result, after moving request from active list, same request will be re-applied. Hence increment bubble frame count only if last sof timestamp is different from current sof timestamp. CRs-Fixed: 2831372 Change-Id: I8977233c001e2f31f4c7bf5e86d95b1849023d86 Signed-off-by: Shravya Samala --- drivers/cam_isp/cam_isp_context.c | 26 +++++++++++++++++++------- drivers/cam_isp/cam_isp_context.h | 2 ++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 95c3c805950a..87affdc3fa37 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1254,13 +1254,25 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else if (req_isp->bubble_detected) { - ctx_isp->bubble_frame_cnt++; - CAM_DBG(CAM_ISP, - "Waiting on bufdone for bubble req: %lld, since frame_cnt = %lld", - req->request_id, ctx_isp->bubble_frame_cnt); + if (ctx_isp->last_sof_timestamp != + ctx_isp->sof_timestamp_val) { + ctx_isp->bubble_frame_cnt++; + CAM_DBG(CAM_ISP, + "Waiting on bufdone bubble req %lld ctx %u frame_cnt %lld link 0x%x", + req->request_id, ctx->ctx_id, + ctx_isp->bubble_frame_cnt, + ctx->link_hdl); + } else { + CAM_DBG(CAM_ISP, + "Possible tasklet delay req %lld ctx %u link 0x%x ts %lld", + req->request_id, ctx->ctx_id, + ctx->link_hdl, + ctx_isp->sof_timestamp_val); + } } else - CAM_DBG(CAM_ISP, "Delayed bufdone for req: %lld", - req->request_id); + CAM_DBG(CAM_ISP, + "Delayed bufdone for req: %lld ctx %u link 0x%x", + req->request_id, ctx->ctx_id, ctx->link_hdl); } if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && @@ -1306,7 +1318,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( ctx->ctx_id); rc = -EFAULT; } - + ctx_isp->last_sof_timestamp = ctx_isp->sof_timestamp_val; return 0; } diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 2e01868f9c94..0d35928d8fec 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -256,6 +256,7 @@ struct cam_isp_context_event_record { * decide whether to apply request in offline ctx * @workq: Worker thread for offline ife * @trigger_id: ID provided by CRM for each ctx on the link + * @last_sof_timestamp: SOF timestamp of the last frame * */ struct cam_isp_context { @@ -298,6 +299,7 @@ struct cam_isp_context { atomic_t rxd_epoch; struct cam_req_mgr_core_workq *workq; int32_t trigger_id; + uint64_t last_sof_timestamp; }; /** -- GitLab From 34cbbdd626b0706db49ad8286794c73255916f6a Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Wed, 2 Dec 2020 13:28:52 +0530 Subject: [PATCH 343/410] msm: camera: isp: Full recovery on CSID fatal error In case, both csid and camif error is seen at same time and if overflow_pending flag is set by camif overflow error processing then csid fatal error will not be processed and request for full recovery has not been notified. This change notify for full recovery in above sceanrio. CRs-Fixed: 2845608 Change-Id: Id711867a42d4fd306c3f3e515a945eff071f28ba Signed-off-by: Ayush Kumar --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 1fe034e31f26..463a05a68953 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6956,12 +6956,18 @@ static int cam_ife_hw_mgr_find_affected_ctx( affected_core, CAM_IFE_HW_NUM_MAX)) continue; + if (error_event_data->error_type == + CAM_ISP_HW_ERROR_CSID_FATAL) { + CAM_DBG(CAM_ISP, "CSID recovery"); + goto skip_overflow; + } + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) { CAM_INFO(CAM_ISP, "CTX:%d already error reported", ife_hwr_mgr_ctx->ctx_index); continue; } - +skip_overflow: atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1); notify_err_cb = ife_hwr_mgr_ctx->common.event_cb[event_type]; -- GitLab From da18d6ecda24d0d540325598d9e6d7b275c5b376 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Thu, 3 Dec 2020 09:55:27 +0530 Subject: [PATCH 344/410] msm: camera: isp: Support UBWC compression disable Support UBWC compression disable via debugfs. When debugfs entry disable_ubwc_comp is set, overwrite the ubwc mode_cfg register for WM to force disable UBWC compression. CRs-Fixed: 2789618 Change-Id: I912f56254ee41f5b6a0e2e1de14c570cd0e5813f Signed-off-by: Wyes Karny --- drivers/cam_icp/fw_inc/hfi_intf.h | 7 ++-- drivers/cam_icp/hfi.c | 9 +++-- drivers/cam_icp/icp_hw/a5_hw/a5_core.c | 26 +++++++++++++-- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 17 ++++++++-- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 4 ++- .../icp_hw/include/cam_icp_hw_mgr_intf.h | 4 ++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 14 +++++++- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 4 ++- .../isp_hw/include/cam_vfe_hw_intf.h | 4 ++- .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 4 ++- .../isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 4 ++- .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 6 +++- .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 6 +++- .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 6 +++- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 33 ++++++++++++++++++- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 4 ++- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 19 ++++++++++- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h | 3 +- 18 files changed, 151 insertions(+), 23 deletions(-) diff --git a/drivers/cam_icp/fw_inc/hfi_intf.h b/drivers/cam_icp/fw_inc/hfi_intf.h index afd42d23b9fb..d804ff7bde44 100644 --- a/drivers/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/cam_icp/fw_inc/hfi_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. */ #ifndef _HFI_INTF_H_ @@ -146,9 +146,10 @@ int hfi_cmd_ubwc_config_ext(uint32_t *ubwc_ipe_cfg, /** * hfi_cmd_ubwc_config() - UBWC configuration to firmware * for older targets - * @ubwc_cfg: UBWC configuration parameters + * @ubwc_cfg: UBWC configuration parameters + * @disable_ubwc_comp: Disable UBWC compression */ -int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg); +int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg, bool disable_ubwc_comp); /** * cam_hfi_resume() - function to resume diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index 89a95aca62e1..7cf22f23dd2b 100644 --- a/drivers/cam_icp/hfi.c +++ b/drivers/cam_icp/hfi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. */ #include @@ -269,7 +269,7 @@ int hfi_read_message(uint32_t *pmsg, uint8_t q_id, return rc; } -int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg) +int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg, bool disable_ubwc_comp) { uint8_t *prop; struct hfi_cmd_prop *dbg_prop; @@ -292,6 +292,11 @@ int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg) dbg_prop->num_prop = 1; dbg_prop->prop_data[0] = HFI_PROP_SYS_UBWC_CFG; dbg_prop->prop_data[1] = ubwc_cfg[0]; + if (disable_ubwc_comp) { + ubwc_cfg[1] &= ~CAM_ICP_UBWC_COMP_EN; + CAM_DBG(CAM_ICP, "UBWC comp force disable, val= 0x%x", + ubwc_cfg[1]); + } dbg_prop->prop_data[2] = ubwc_cfg[1]; hfi_write_cmd(prop); diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index 1ac27511f7ac..4a6d1cec0e73 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -535,6 +535,7 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, break; case CAM_ICP_A5_CMD_UBWC_CFG: { struct a5_ubwc_cfg_ext *ubwc_cfg_ext = NULL; + uint32_t *disable_ubwc_comp; a5_soc = soc_info->soc_private; if (!a5_soc) { @@ -542,6 +543,13 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, return -EINVAL; } + if (!cmd_args) { + CAM_ERR(CAM_ICP, "Invalid args"); + return -EINVAL; + } + + disable_ubwc_comp = (uint32_t *)cmd_args; + if (a5_soc->ubwc_config_ext) { /* Invoke kernel API to determine DDR type */ ddr_type = of_fdt_get_ddrtype(); @@ -558,10 +566,24 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, ubwc_cfg_ext->ubwc_bps_fetch_cfg[index]; ubwc_bps_cfg[1] = ubwc_cfg_ext->ubwc_bps_write_cfg[index]; + + if (*disable_ubwc_comp) { + ubwc_ipe_cfg[1] &= ~CAM_ICP_UBWC_COMP_EN; + ubwc_bps_cfg[1] &= ~CAM_ICP_UBWC_COMP_EN; + CAM_DBG(CAM_ISP, + "UBWC comp force disable, ubwc_ipe_cfg: 0x%x, ubwc_bps_cfg: 0x%x", + ubwc_ipe_cfg[1], ubwc_bps_cfg[1]); + } + rc = hfi_cmd_ubwc_config_ext(&ubwc_ipe_cfg[0], &ubwc_bps_cfg[0]); } else { - rc = hfi_cmd_ubwc_config(a5_soc->uconfig.ubwc_cfg); + if (*disable_ubwc_comp) + rc = hfi_cmd_ubwc_config( + a5_soc->uconfig.ubwc_cfg, true); + else + rc = hfi_cmd_ubwc_config( + a5_soc->uconfig.ubwc_cfg, false); } break; 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 46eb69da306a..40bb64848b39 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -109,6 +109,7 @@ static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) { struct cam_hw_intf *a5_dev_intf = NULL; int rc; + uint32_t disable_ubwc_comp = 0; a5_dev_intf = hw_mgr->a5_dev_intf; if (!a5_dev_intf) { @@ -116,9 +117,12 @@ static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) return -EINVAL; } + disable_ubwc_comp = hw_mgr->disable_ubwc_comp; + rc = a5_dev_intf->hw_ops.process_cmd( a5_dev_intf->hw_priv, - CAM_ICP_A5_CMD_UBWC_CFG, NULL, 0); + CAM_ICP_A5_CMD_UBWC_CFG, (void *)&disable_ubwc_comp, + sizeof(disable_ubwc_comp)); if (rc) CAM_ERR(CAM_ICP, "CAM_ICP_A5_CMD_UBWC_CFG is failed"); @@ -1956,6 +1960,15 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) goto err; } + if (!debugfs_create_bool("disable_ubwc_comp", + 0644, + icp_hw_mgr.dentry, + &icp_hw_mgr.disable_ubwc_comp)) { + CAM_ERR(CAM_ICP, "failed to create disable_ubwc_comp"); + rc = -ENOMEM; + goto err; + } + /* Set default hang dump lvl */ icp_hw_mgr.a5_fw_dump_lvl = HFI_FW_DUMP_ON_FAILURE; return rc; diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index a4b3817680e8..a2d62754c847 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef CAM_ICP_HW_MGR_H @@ -352,6 +352,7 @@ struct cam_icp_clk_info { * @bps_dev_intf: Device interface for BPS * @ipe_clk_state: IPE clock state flag * @bps_clk_state: BPS clock state flag + * @disable_ubwc_comp: Disable UBWC compression * @recovery: Flag to validate if in previous session FW * reported a fatal error or wdt. If set FW is * re-downloaded for new camera session. @@ -401,6 +402,7 @@ struct cam_icp_hw_mgr { struct cam_hw_intf *bps_dev_intf; bool ipe_clk_state; bool bps_clk_state; + bool disable_ubwc_comp; atomic_t recovery; }; diff --git a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index 84129cba7e19..6a1b9c57c193 100644 --- a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef CAM_ICP_HW_MGR_INTF_H @@ -20,6 +20,8 @@ #define CPAS_IPE1_BIT 0x2000 +#define CAM_ICP_UBWC_COMP_EN BIT(1) + #define CAM_IPE_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_IPE_WR_VID #define CAM_IPE_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_WRITE #define CAM_BPS_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 463a05a68953..42ae040c37da 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -1126,6 +1126,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( vfe_acquire.vfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT; vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; vfe_acquire.vfe_out.is_dual = 0; + vfe_acquire.vfe_out.disable_ubwc_comp = + g_ife_hw_mgr.debug_cfg.disable_ubwc_comp; vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; hw_intf = ife_src_res->hw_res[0]->hw_intf; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, @@ -1209,6 +1211,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( vfe_acquire.vfe_out.out_port_info = out_port; vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.vfe_out.disable_ubwc_comp = + g_ife_hw_mgr.debug_cfg.disable_ubwc_comp; vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { @@ -7758,6 +7762,14 @@ static int cam_ife_hw_mgr_debug_register(void) goto err; } + if (!debugfs_create_bool("disable_ubwc_comp", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.disable_ubwc_comp)) { + CAM_ERR(CAM_ISP, "failed to create disable_ubwc_comp entry"); + goto err; + } + g_ife_hw_mgr.debug_cfg.enable_recovery = 0; return 0; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 9233a19a0a76..3fbd9cebff53 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_HW_MGR_H_ @@ -85,6 +85,7 @@ struct ctx_base_info { * @enable_diag_sensor_status: enable sensor diagnosis status * @enable_req_dump: Enable request dump on HW errors * @per_req_reg_dump: Enable per request reg dump + * @disable_ubwc_comp: Disable UBWC compression * */ struct cam_ife_hw_mgr_debug { @@ -95,6 +96,7 @@ struct cam_ife_hw_mgr_debug { uint32_t camif_debug; bool enable_req_dump; bool per_req_reg_dump; + bool disable_ubwc_comp; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index 531e695583a0..55cbda5aa786 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_HW_INTF_H_ @@ -139,6 +139,7 @@ struct cam_vfe_hw_vfe_bus_rd_acquire_args { * (Default is Master in case of Single VFE) * @dual_slave_core: If Master and Slave exists, HW Index of Slave * @cdm_ops: CDM operations + * disable_ubwc_comp: Disable UBWC compression */ struct cam_vfe_hw_vfe_out_acquire_args { struct cam_isp_resource_node *rsrc_node; @@ -149,6 +150,7 @@ struct cam_vfe_hw_vfe_out_acquire_args { uint32_t is_master; uint32_t dual_slave_core; struct cam_cdm_utils_ops *cdm_ops; + bool disable_ubwc_comp; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index a65d7aa966fd..8aa1a471a197 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE170_H_ @@ -238,6 +238,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_3 = { .meta_stride = 0x00002540, .mode_cfg_0 = 0x00002544, .bw_limit = 0x000025A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = { @@ -249,6 +250,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = { .meta_stride = 0x00002640, .mode_cfg_0 = 0x00002644, .bw_limit = 0x000026A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h index dfeaf3032bcf..35f7da004105 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE170_150_H_ @@ -418,6 +418,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client .meta_stride = 0x00002540, .mode_cfg_0 = 0x00002544, .bw_limit = 0x000025A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_client @@ -430,6 +431,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_client .meta_stride = 0x00002640, .mode_cfg_0 = 0x00002644, .bw_limit = 0x000026A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_hw_info vfe170_150_bus_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index 4e9a1e232860..7e7b9c3ffac3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE175_H_ @@ -267,6 +267,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00002544, .mode_cfg_1 = 0x000025A4, .bw_limit = 0x000025A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client @@ -280,6 +281,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00002644, .mode_cfg_1 = 0x000026A4, .bw_limit = 0x000026A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client @@ -293,6 +295,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00003644, .mode_cfg_1 = 0x000036A4, .bw_limit = 0x000036A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client @@ -306,6 +309,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00003744, .mode_cfg_1 = 0x000037A4, .bw_limit = 0x000037A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 6d650fe5e711..c2ce8645de26 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE175_130_H_ @@ -515,6 +515,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00002544, .mode_cfg_1 = 0x000025A4, .bw_limit = 0x000025A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client @@ -528,6 +529,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00002644, .mode_cfg_1 = 0x000026A4, .bw_limit = 0x000026A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client @@ -541,6 +543,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00003644, .mode_cfg_1 = 0x000036A4, .bw_limit = 0x000036A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client @@ -554,6 +557,7 @@ static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client .mode_cfg_0 = 0x00003744, .mode_cfg_1 = 0x000037A4, .bw_limit = 0x000037A0, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_rd_ver1_hw_info vfe175_130_bus_rd_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index 86078e9be08d..f592364fb42e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ @@ -346,6 +346,7 @@ static struct cam_vfe_bus_ver3_reg_offset_ubwc_client .lossy_thresh1 = 0x0000AC58, .off_lossy_var = 0x0000AC5C, .bw_limit = 0x0000AC1C, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver3_reg_offset_ubwc_client @@ -359,6 +360,7 @@ static struct cam_vfe_bus_ver3_reg_offset_ubwc_client .lossy_thresh1 = 0x0000AD58, .off_lossy_var = 0x0000AD5C, .bw_limit = 0x0000AD1C, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver3_reg_offset_ubwc_client @@ -372,6 +374,7 @@ static struct cam_vfe_bus_ver3_reg_offset_ubwc_client .lossy_thresh1 = 0x0000B058, .off_lossy_var = 0x0000B05C, .bw_limit = 0x0000B01C, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver3_reg_offset_ubwc_client @@ -385,6 +388,7 @@ static struct cam_vfe_bus_ver3_reg_offset_ubwc_client .lossy_thresh1 = 0x0000B158, .off_lossy_var = 0x0000B15C, .bw_limit = 0x0000B11C, + .ubwc_comp_en_bit = BIT(1), }; static struct cam_vfe_bus_ver3_hw_info vfe480_bus_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 62c7089bf95f..0207847f7021 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #include @@ -103,6 +103,7 @@ struct cam_vfe_bus_ver2_common_data { cam_hw_mgr_event_cb_func event_cb; bool hw_init; struct cam_vfe_bus_ver2_stats_cfg_info *stats_data; + bool disable_ubwc_comp; }; struct cam_vfe_bus_ver2_wm_resource_data { @@ -1260,6 +1261,13 @@ static int cam_vfe_bus_start_wm( val = cam_io_r_mb(common_data->mem_base + ubwc_regs->mode_cfg_0); val |= 0x1; + if (rsrc_data->common_data->disable_ubwc_comp) { + val &= ~ubwc_regs->ubwc_comp_en_bit; + CAM_DBG(CAM_ISP, + "Force disable UBWC, VFE:%d, WM:%d", + rsrc_data->common_data->core_index, + rsrc_data->index); + } cam_io_w_mb(val, common_data->mem_base + ubwc_regs->mode_cfg_0); } else if ((camera_hw_version == CAM_CPAS_TITAN_175_V100) || @@ -1276,6 +1284,13 @@ static int cam_vfe_bus_start_wm( val = cam_io_r_mb(common_data->mem_base + ubwc_regs->mode_cfg_0); val |= 0x1; + if (rsrc_data->common_data->disable_ubwc_comp) { + val &= ~ubwc_regs->ubwc_comp_en_bit; + CAM_DBG(CAM_ISP, + "Force disable UBWC, VFE:%d, WM:%d", + rsrc_data->common_data->core_index, + rsrc_data->index); + } cam_io_w_mb(val, common_data->mem_base + ubwc_regs->mode_cfg_0); } else { @@ -2266,6 +2281,8 @@ static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args, rsrc_data = rsrc_node->res_priv; rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->common_data->disable_ubwc_comp = + out_acquire_args->disable_ubwc_comp; rsrc_data->priv = acq_args->priv; secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->out_type); @@ -2880,6 +2897,13 @@ static int cam_vfe_bus_update_ubwc_3_regs( CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", wm_data->index, reg_val_pair[*j-1]); + if (wm_data->common_data->disable_ubwc_comp) { + wm_data->ubwc_mode_cfg_0 &= ~ubwc_regs->ubwc_comp_en_bit; + CAM_DBG(CAM_ISP, + "UBWC force disable WM:%d, val= 0x%x", + wm_data->index, wm_data->ubwc_mode_cfg_0); + } + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", @@ -2959,6 +2983,13 @@ static int cam_vfe_bus_update_ubwc_legacy_regs( CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", wm_data->index, reg_val_pair[*j-1]); + if (wm_data->common_data->disable_ubwc_comp) { + wm_data->ubwc_mode_cfg_0 &= ~ubwc_regs->ubwc_comp_en_bit; + CAM_DBG(CAM_ISP, + "UBWC fore disable WM:%d val= 0x%x", + wm_data->index, wm_data->ubwc_mode_cfg_0); + } + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index 0455d10b7367..7ab273a9ceb1 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_BUS_VER2_H_ @@ -129,6 +129,7 @@ struct cam_vfe_bus_ver2_reg_offset_ubwc_client { uint32_t meta_stride; uint32_t mode_cfg_0; uint32_t bw_limit; + uint32_t ubwc_comp_en_bit; }; /* @@ -146,6 +147,7 @@ struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client { uint32_t mode_cfg_0; uint32_t mode_cfg_1; uint32_t bw_limit; + uint32_t ubwc_comp_en_bit; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 29f9e6618cdc..7c07e4ae07b4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ @@ -85,6 +85,7 @@ struct cam_vfe_bus_ver3_common_data { uint32_t comp_done_shift; bool is_lite; bool hw_init; + bool disable_ubwc_comp; cam_hw_mgr_event_cb_func event_cb; int rup_irq_handle[CAM_VFE_BUS_VER3_SRC_GRP_MAX]; }; @@ -1387,6 +1388,13 @@ static int cam_vfe_bus_ver3_start_wm(struct cam_isp_resource_node *wm_res) if (rsrc_data->en_ubwc) { val = cam_io_r_mb(common_data->mem_base + ubwc_regs->mode_cfg); val |= 0x1; + if (rsrc_data->common_data->disable_ubwc_comp) { + val &= ~ubwc_regs->ubwc_comp_en_bit; + CAM_DBG(CAM_ISP, + "UBWC force disable VFE:%d WM:%d val= 0x%x", + rsrc_data->common_data->core_index, + rsrc_data->index, val); + } cam_io_w_mb(val, common_data->mem_base + ubwc_regs->mode_cfg); } @@ -1937,6 +1945,8 @@ static int cam_vfe_bus_ver3_acquire_vfe_out(void *bus_priv, void *acquire_args, rsrc_data = rsrc_node->res_priv; rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->common_data->disable_ubwc_comp = + out_acquire_args->disable_ubwc_comp; rsrc_data->priv = acq_args->priv; secure_caps = cam_vfe_bus_ver3_can_be_secure( @@ -2978,6 +2988,13 @@ static int cam_vfe_bus_ver3_update_ubwc_regs( CAM_DBG(CAM_ISP, "WM:%d meta stride 0x%X", wm_data->index, reg_val_pair[*j-1]); + if (wm_data->common_data->disable_ubwc_comp) { + wm_data->ubwc_mode_cfg &= ~ubwc_regs->ubwc_comp_en_bit; + CAM_DBG(CAM_ISP, + "UBWC force WM:%d val= x%x", + wm_data->index, wm_data->ubwc_mode_cfg); + } + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, ubwc_regs->mode_cfg, wm_data->ubwc_mode_cfg); CAM_DBG(CAM_ISP, "WM:%d ubwc_mode_cfg 0x%X", diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h index c5b4ab69fa9f..1e2d7e093682 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved. */ @@ -113,6 +113,7 @@ struct cam_vfe_bus_ver3_reg_offset_ubwc_client { uint32_t lossy_thresh1; uint32_t off_lossy_var; uint32_t bw_limit; + uint32_t ubwc_comp_en_bit; }; /* -- GitLab From 956a6efc4fc6ea636e316cbd968eaab468cda35f Mon Sep 17 00:00:00 2001 From: Anil Kumar Kanakanti Date: Wed, 10 Feb 2021 18:50:11 +0530 Subject: [PATCH 345/410] msm: camera: sensor: Turn off the i2c flash while flushing Turn off the i2c flash while flushing if the flushed request turns off the flash. CRs-Fixed: 2840575 Change-Id: Ia4734ed2a4957ca4f06fac3ee5eb4681ff354fe8 Signed-off-by: Anil Kumar Kanakanti --- .../cam_flash/cam_flash_core.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index d02057a49fe4..e861fd328951 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -403,6 +403,7 @@ int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, int i = 0; uint32_t cancel_req_id_found = 0; struct i2c_settings_array *i2c_set = NULL; + struct i2c_settings_list *i2c_list; if (!fctrl) { CAM_ERR(CAM_FLASH, "Device data is NULL"); @@ -423,6 +424,20 @@ int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, continue; if (i2c_set->is_settings_valid == 1) { + /* If any flash_off request pending, + * process it before deleting it + */ + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_util_i2c_apply_setting( + &(fctrl->io_master_info), + i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply settings: %d", + rc); + } + } rc = delete_request(i2c_set); if (rc < 0) CAM_ERR(CAM_FLASH, @@ -625,6 +640,7 @@ static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, { int i = 0, rc = 0; uint64_t top = 0, del_req_id = 0; + int frame_offset = 0; if (req_id != 0) { for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { @@ -653,6 +669,9 @@ static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", top, del_req_id); } + /* delete/invalidate the request */ + frame_offset = del_req_id % MAX_PER_FRAME_ARRAY; + fctrl->i2c_data.per_frame[frame_offset].is_settings_valid = false; cam_flash_i2c_flush_nrt(fctrl); -- GitLab From 9040f690df44b1e34523f3bacf893fceef21b142 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Thu, 28 Jan 2021 20:45:54 +0530 Subject: [PATCH 346/410] msm: camera: isp: Handle incorrect bubble frame count In the case of tasklet congession SOF timestamp is same for all scheduled EPOCH tasklets. If SOF timestamp is same do not increment the bubble frame count. CRs-Fixed: 2881777 Change-Id: Ib98ea07f5640c814c87876887cf38aeb53de3e87 Signed-off-by: Wyes Karny --- drivers/cam_isp/cam_isp_context.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 87affdc3fa37..b29680cd8ed3 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -1236,6 +1236,14 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( return rc; } + if (ctx_isp->last_sof_timestamp == + ctx_isp->sof_timestamp_val) { + CAM_DBG(CAM_ISP, + "Tasklet delay detected! Bubble frame check skipped, sof_timestamp: %lld", + ctx_isp->sof_timestamp_val); + goto notify_only; + } + req = list_first_entry(&ctx->active_req_list, struct cam_ctx_request, list); req_isp = (struct cam_isp_ctx_req *) req->req_priv; @@ -1275,6 +1283,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( req->request_id, ctx->ctx_id, ctx->link_hdl); } +notify_only: + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && ctx_isp->active_req_cnt <= 2) { if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { -- GitLab From 78b8ee08990a0a6f71f0ca32621d76b59375bc00 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 18 Feb 2021 12:06:58 +0530 Subject: [PATCH 347/410] msm: camera: isp: Reapply bubble request in RDI path For recovery of the bubble the request from active list should be added back to pending request list. Re-apply bubble request if buf done has not come for two bubble frames. Also before re-submitting the request to CDM check if CDM callback for that request has come or not, if CDM callback is received then wait for buf done else reset CDM and re-submit the request to CDM. CRs-Fixed: 2886414 Change-Id: If7daf738b680ffe651340c014122b15f6beda75c Signed-off-by: Tejas Prajapati --- drivers/cam_core/cam_hw_mgr_intf.h | 21 ++- drivers/cam_isp/cam_isp_context.c | 157 ++++++++++++++++-- drivers/cam_isp/cam_isp_context.h | 39 +++-- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 34 ++++ drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 2 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 15 +- 6 files changed, 221 insertions(+), 47 deletions(-) diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 8339fc9cb24e..80b992817865 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_HW_MGR_INTF_H_ @@ -235,14 +235,16 @@ struct cam_hw_stream_setttings { /** * struct cam_hw_config_args - Payload for config command * - * @ctxt_to_hw_map: HW context from the acquire - * @num_hw_update_entries: Number of hardware update entries - * @hw_update_entries: Hardware update list - * @out_map_entries: Out map info - * @num_out_map_entries: Number of out map entries - * @priv: Private pointer - * @request_id: Request ID - * @reapply True if reapplying after bubble + * @ctxt_to_hw_map: HW context from the acquire + * @num_hw_update_entries: Number of hardware update entries + * @hw_update_entries: Hardware update list + * @out_map_entries: Out map info + * @num_out_map_entries: Number of out map entries + * @priv: Private pointer + * @request_id: Request ID + * @reapply: True if reapplying after bubble + * @cdm_reset_before_apply: True is need to reset CDM before re-apply bubble + * request * */ struct cam_hw_config_args { @@ -255,6 +257,7 @@ struct cam_hw_config_args { uint64_t request_id; bool init_packet; bool reapply; + bool cdm_reset_before_apply; }; /** diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index b29680cd8ed3..6a586372c7aa 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -893,6 +893,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request( req_isp->bubble_detected = false; list_del_init(&req->list); atomic_set(&ctx_isp->process_bubble, 0); + req_isp->cdm_reset_before_apply = false; + ctx_isp->bubble_frame_cnt = 0; if (buf_done_req_id <= ctx->last_flush_req) { for (i = 0; i < req_isp->num_fence_map_out; i++) @@ -926,6 +928,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request( list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); req_isp->reapply = false; + req_isp->cdm_reset_before_apply = false; CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", @@ -1208,6 +1211,10 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( struct cam_context *ctx = ctx_isp->base; struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + uint64_t last_cdm_done_req = 0; + struct cam_isp_hw_epoch_event_data *epoch_done_event_data = (struct cam_isp_hw_epoch_event_data *)evt_data; @@ -1250,17 +1257,46 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( if (ctx_isp->bubble_frame_cnt >= 1 && req_isp->bubble_detected) { - req_isp->num_acked = 0; - ctx_isp->bubble_frame_cnt = 0; - req_isp->bubble_detected = false; - list_del_init(&req->list); - list_add(&req->list, &ctx->pending_req_list); - atomic_set(&ctx_isp->process_bubble, 0); - ctx_isp->active_req_cnt--; - CAM_DBG(CAM_REQ, - "Move active req: %lld to pending list(cnt = %d) [bubble re-apply], ctx %u", - req->request_id, - ctx_isp->active_req_cnt, ctx->ctx_id); + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = + CAM_ISP_HW_MGR_GET_LAST_CDM_DONE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd( + ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, + "HW command failed to get last CDM done"); + return rc; + } + + last_cdm_done_req = isp_hw_cmd_args.u.last_cdm_done; + CAM_DBG(CAM_ISP, "last_cdm_done req: %d", + last_cdm_done_req); + + if (last_cdm_done_req >= req->request_id) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CDM callback detected for req: %lld, possible buf_done delay, waiting for buf_done", + req->request_id); + ctx_isp->bubble_frame_cnt = 0; + } else { + CAM_DBG(CAM_ISP, + "CDM callback not happened for req: %lld, possible CDM stuck or workqueue delay", + req->request_id); + req_isp->num_acked = 0; + ctx_isp->bubble_frame_cnt = 0; + req_isp->bubble_detected = false; + req_isp->cdm_reset_before_apply = true; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->active_req_cnt--; + CAM_DBG(CAM_REQ, + "Move active req: %lld to pending list(cnt = %d) [bubble re-apply],ctx %u", + req->request_id, + ctx_isp->active_req_cnt, ctx->ctx_id); + } } else if (req_isp->bubble_detected) { if (ctx_isp->last_sof_timestamp != ctx_isp->sof_timestamp_val) { @@ -1492,6 +1528,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, req_isp = (struct cam_isp_ctx_req *)req->req_priv; req_isp->bubble_detected = true; req_isp->reapply = true; + req_isp->cdm_reset_before_apply = false; CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld", ctx->ctx_id, req_isp->bubble_report, req->request_id); @@ -1678,6 +1715,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", ctx->ctx_id, req_isp->bubble_report, req->request_id); req_isp->reapply = true; + req_isp->cdm_reset_before_apply = false; if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { @@ -2545,11 +2583,10 @@ static int __cam_isp_ctx_apply_req_in_activated_state( cfg.priv = &req_isp->hw_update_data; cfg.init_packet = 0; cfg.reapply = req_isp->reapply; + cfg.cdm_reset_before_apply = req_isp->cdm_reset_before_apply; rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); - if (rc) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration"); - } else { + if (!rc) { spin_lock_bh(&ctx->lock); ctx_isp->substate_activated = next_state; ctx_isp->last_applied_req_id = apply->request_id; @@ -2565,6 +2602,22 @@ static int __cam_isp_ctx_apply_req_in_activated_state( req->request_id); __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_APPLY, req); + } else if (rc == -EALREADY) { + spin_lock_bh(&ctx->lock); + req_isp->bubble_detected = true; + req_isp->cdm_reset_before_apply = false; + atomic_set(&ctx_isp->process_bubble, 1); + list_del_init(&req->list); + list_add(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_REQ, + "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "ctx_id:%d ,Can not apply (req %lld) the configuration, rc %d", + ctx->ctx_id, apply->request_id, rc); } end: return rc; @@ -2900,6 +2953,7 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, } } req_isp->reapply = false; + req_isp->cdm_reset_before_apply = false; list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); } @@ -3265,6 +3319,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", ctx->ctx_id, req_isp->bubble_report, req->request_id); req_isp->reapply = true; + req_isp->cdm_reset_before_apply = false; if (req_isp->bubble_report && ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { @@ -3285,6 +3340,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( ctx_isp->frame_id, ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); + atomic_set(&ctx_isp->process_bubble, 1); } else { req_isp->bubble_report = 0; } @@ -3330,7 +3386,11 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( struct cam_req_mgr_trigger_notify notify; struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; struct cam_isp_ctx_req *req_isp; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; uint64_t request_id = 0; + uint64_t last_cdm_done_req = 0; + int rc = 0; if (!evt_data) { CAM_ERR(CAM_ISP, "in valid sof event data"); @@ -3342,6 +3402,71 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( ctx_isp->boot_timestamp = sof_event_data->boot_time; CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + + if (atomic_read(&ctx_isp->process_bubble)) { + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_ISP, "No available active req in bubble"); + atomic_set(&ctx_isp->process_bubble, 0); + return -EINVAL; + } + + if (ctx_isp->last_sof_timestamp == + ctx_isp->sof_timestamp_val) { + CAM_DBG(CAM_ISP, + "Tasklet delay detected! Bubble frame check skipped, sof_timestamp: %lld, ctx_id: %d", + ctx_isp->sof_timestamp_val, + ctx->ctx_id); + goto end; + } + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (req_isp->bubble_detected) { + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = + CAM_ISP_HW_MGR_GET_LAST_CDM_DONE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd( + ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, + "HW command failed to get last CDM done"); + return rc; + } + + last_cdm_done_req = isp_hw_cmd_args.u.last_cdm_done; + CAM_DBG(CAM_ISP, "last_cdm_done req: %d ctx_id: %d", + last_cdm_done_req, ctx->ctx_id); + + if (last_cdm_done_req >= req->request_id) { + CAM_DBG(CAM_ISP, + "CDM callback detected for req: %lld, possible buf_done delay, waiting for buf_done", + req->request_id); + goto end; + } else { + CAM_DBG(CAM_ISP, + "CDM callback not happened for req: %lld, possible CDM stuck or workqueue delay", + req->request_id); + req_isp->num_acked = 0; + req_isp->bubble_detected = false; + req_isp->cdm_reset_before_apply = true; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->active_req_cnt--; + CAM_DBG(CAM_REQ, + "Move active req: %lld to pending list(cnt = %d) [bubble re-apply],ctx %u", + req->request_id, + ctx_isp->active_req_cnt, ctx->ctx_id); + } + goto end; + } + } /* * Signal all active requests with error and move the all the active * requests to free list @@ -3363,6 +3488,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( ctx_isp->active_req_cnt--; } +end: /* notify reqmgr with sof signal */ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { notify.link_hdl = ctx->link_hdl; @@ -3393,6 +3519,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( __cam_isp_ctx_substate_val_to_type( ctx_isp->substate_activated)); + ctx_isp->last_sof_timestamp = ctx_isp->sof_timestamp_val; return 0; } @@ -3857,6 +3984,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( req_isp->num_fence_map_in = cfg.num_in_map_entries; req_isp->num_acked = 0; req_isp->bubble_detected = false; + req_isp->cdm_reset_before_apply = false; for (i = 0; i < req_isp->num_fence_map_out; i++) { rc = cam_sync_get_obj_ref(req_isp->fence_map_out[i].sync_id); @@ -4604,6 +4732,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, start_isp.hw_config.priv = &req_isp->hw_update_data; start_isp.hw_config.init_packet = 1; start_isp.hw_config.reapply = 0; + start_isp.hw_config.cdm_reset_before_apply = false; ctx_isp->last_applied_req_id = req->request_id; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index 0d35928d8fec..b85d6f809394 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_CONTEXT_H_ @@ -133,21 +133,23 @@ struct cam_isp_ctx_irq_ops { /** * struct cam_isp_ctx_req - ISP context request object * - * @base: Common request object ponter - * @cfg: ISP hardware configuration array - * @num_cfg: Number of ISP hardware configuration entries - * @fence_map_out: Output fence mapping array - * @num_fence_map_out: Number of the output fence map - * @fence_map_in: Input fence mapping array - * @num_fence_map_in: Number of input fence map - * @num_acked: Count to track acked entried for output. - * If count equals the number of fence out, it means - * the request has been completed. - * @bubble_report: Flag to track if bubble report is active on - * current request - * @hw_update_data: HW update data for this request - * @event_timestamp: Timestamp for different stage of request - * @reapply: True if reapplying after bubble + * @base: Common request object ponter + * @cfg: ISP hardware configuration array + * @num_cfg: Number of ISP hardware configuration entries + * @fence_map_out: Output fence mapping array + * @num_fence_map_out: Number of the output fence map + * @fence_map_in: Input fence mapping array + * @num_fence_map_in: Number of input fence map + * @num_acked: Count to track acked entried for output. + * If count equals the number of fence out, it means + * the request has been completed. + * @bubble_report: Flag to track if bubble report is active on + * current request + * @hw_update_data: HW update data for this request + * @event_timestamp: Timestamp for different stage of request + * @reapply: True if reapplying after bubble + * @cdm_reset_before_apply: For bubble re-apply when buf done not coming set + * to True * */ struct cam_isp_ctx_req { @@ -167,6 +169,7 @@ struct cam_isp_ctx_req { [CAM_ISP_CTX_EVENT_MAX]; bool bubble_detected; bool reapply; + bool cdm_reset_before_apply; }; /** @@ -238,6 +241,7 @@ struct cam_isp_context_event_record { * @subscribe_event: The irq event mask that CRM subscribes to, IFE * will invoke CRM cb at those event. * @last_applied_req_id: Last applied request id + * @last_sof_timestamp: SOF timestamp of the last frame * @state_monitor_head: Write index to the state monitoring array * @req_info Request id information about last buf done * @cam_isp_ctx_state_monitor: State monitoring array @@ -256,7 +260,6 @@ struct cam_isp_context_event_record { * decide whether to apply request in offline ctx * @workq: Worker thread for offline ife * @trigger_id: ID provided by CRM for each ctx on the link - * @last_sof_timestamp: SOF timestamp of the last frame * */ struct cam_isp_context { @@ -280,6 +283,7 @@ struct cam_isp_context { int64_t reported_req_id; uint32_t subscribe_event; int64_t last_applied_req_id; + uint64_t last_sof_timestamp; atomic64_t state_monitor_head; struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; @@ -299,7 +303,6 @@ struct cam_isp_context { atomic_t rxd_epoch; struct cam_req_mgr_core_workq *workq; int32_t trigger_id; - uint64_t last_sof_timestamp; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 42ae040c37da..2defa0cb44f1 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2710,6 +2710,7 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { complete_all(&ctx->config_done_complete); atomic_set(&ctx->cdm_done, 1); + ctx->last_cdm_done_req = cookie; if (g_ife_hw_mgr.debug_cfg.per_req_reg_dump) cam_ife_mgr_handle_reg_dump(ctx, hw_update_data->reg_dump_buf_desc, @@ -3016,6 +3017,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) ife_ctx->cdm_handle = cdm_acquire.handle; ife_ctx->cdm_ops = cdm_acquire.ops; atomic_set(&ife_ctx->cdm_done, 1); + ife_ctx->last_cdm_done_req = 0; acquire_hw_info = (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; @@ -3225,6 +3227,7 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) ife_ctx->cdm_handle = cdm_acquire.handle; ife_ctx->cdm_ops = cdm_acquire.ops; atomic_set(&ife_ctx->cdm_done, 1); + ife_ctx->last_cdm_done_req = 0; isp_resource = (struct cam_isp_resource *)acquire_args->acquire_info; @@ -3662,6 +3665,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, struct cam_ife_hw_mgr_ctx *ctx; struct cam_isp_prepare_hw_update_data *hw_update_data; unsigned long rem_jiffies = 0; + bool cdm_hang_detect = false; if (!hw_mgr_priv || !config_hw_args) { CAM_ERR(CAM_ISP, @@ -3697,6 +3701,31 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld, init_packet=%d", ctx, ctx->ctx_index, cfg->request_id, cfg->init_packet); + if (cfg->reapply && cfg->cdm_reset_before_apply) { + if (ctx->last_cdm_done_req < cfg->request_id) { + cdm_hang_detect = + cam_cdm_detect_hang_error(ctx->cdm_handle); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CDM callback not received for req: %lld, last_cdm_done_req: %lld, cdm_hang_detect: %d", + cfg->request_id, ctx->last_cdm_done_req, + cdm_hang_detect); + rc = cam_cdm_reset_hw(ctx->cdm_handle); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CDM reset unsuccessful for req: %lld. ctx: %d, rc: %d", + cfg->request_id, ctx->ctx_index, rc); + ctx->last_cdm_done_req = 0; + return rc; + } + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CDM callback received, should wait for buf done for req: %lld", + cfg->request_id); + return -EALREADY; + } + ctx->last_cdm_done_req = 0; + } + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { if (hw_update_data->bw_config_valid[i] == true) { @@ -4540,6 +4569,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->is_fe_enabled = false; ctx->is_offline = false; ctx->dual_ife_irq_mismatch_cnt = 0; + ctx->last_cdm_done_req = 0; atomic_set(&ctx->overflow_pending, 0); for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { ctx->sof_cnt[i] = 0; @@ -6523,6 +6553,10 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) case CAM_HW_MGR_CMD_DUMP_ACQ_INFO: cam_ife_hw_mgr_dump_acq_data(ctx); break; + case CAM_ISP_HW_MGR_GET_LAST_CDM_DONE: + isp_hw_cmd_args->u.last_cdm_done = + ctx->last_cdm_done_req; + break; default: CAM_ERR(CAM_ISP, "Invalid cmd"); } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 3fbd9cebff53..0875be666893 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -133,6 +133,7 @@ struct cam_ife_hw_mgr_debug { * context * @cdm_done flag to indicate cdm has finished writing shadow * registers + * @last_cdm_done_req: Last cdm done request * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete * @reg_dump_buf_desc: cmd buffer descriptors for reg dump @@ -185,6 +186,7 @@ struct cam_ife_hw_mgr_ctx { uint32_t eof_cnt[CAM_IFE_HW_NUM_MAX]; atomic_t overflow_pending; atomic_t cdm_done; + uint64_t last_cdm_done_req; uint32_t is_rdi_only_context; struct completion config_done_complete; struct cam_cmd_buf_desc reg_dump_buf_desc[ diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index a1868fcc599a..4ae0d8b5e8f1 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_MGR_INTF_H_ @@ -231,6 +231,7 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_SOF_DEBUG, CAM_ISP_HW_MGR_CMD_CTX_TYPE, CAM_ISP_HW_MGR_GET_PACKET_OPCODE, + CAM_ISP_HW_MGR_GET_LAST_CDM_DONE, CAM_ISP_HW_MGR_CMD_MAX, }; @@ -244,11 +245,12 @@ enum cam_isp_ctx_type { /** * struct cam_isp_hw_cmd_args - Payload for hw manager command * - * @cmd_type HW command type - * @cmd_data command data - * @sof_irq_enable To debug if SOF irq is enabled - * @ctx_type RDI_ONLY, PIX and RDI, or FS2 - * @packet_op_code packet opcode + * @cmd_type: HW command type + * @cmd_data: Command data + * @sof_irq_enable: To debug if SOF irq is enabled + * @ctx_type: RDI_ONLY, PIX and RDI, or FS2 + * @packet_op_code: Packet opcode + * @last_cdm_done: Last cdm done request */ struct cam_isp_hw_cmd_args { uint32_t cmd_type; @@ -257,6 +259,7 @@ struct cam_isp_hw_cmd_args { uint32_t sof_irq_enable; uint32_t ctx_type; uint32_t packet_op_code; + uint64_t last_cdm_done; } u; }; -- GitLab From 9750fff59b479300394522796d58d5768571a353 Mon Sep 17 00:00:00 2001 From: Shankar Ravi Date: Thu, 11 Mar 2021 12:28:28 +0530 Subject: [PATCH 348/410] msm: camera: csiphy: Dump CSIPHY Status Reg at SOF freeze PHY status dump analysis need to be done to check issue with transmitter when SOF freeze occurs as recommended by PHY HW team. CRs-Fixed: 2890861 Change-Id: Ibaabe1c7e5968aa384313619e8a21f589f1d880e Signed-off-by: Shankar Ravi --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index eaf7a7caa6e5..2d1cace0e75f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #include @@ -4241,6 +4241,13 @@ static int cam_ife_csid_sof_irq_debug( CAM_INFO(CAM_ISP, "SOF freeze: CSID SOF irq %s", (sof_irq_enable == true) ? "enabled" : "disabled"); + CAM_INFO(CAM_ISP, "Notify CSIPHY: %d", + csid_hw->csi2_rx_cfg.phy_sel); + + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_IRQ_ERR, + csid_hw->csi2_rx_cfg.phy_sel); + return 0; } -- GitLab From 7729f60f6536a57602a32bc4a11bc31f5f8a6aa3 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Mon, 26 Apr 2021 14:52:13 +0530 Subject: [PATCH 349/410] msm: camera: ife: Get last CDM done under internal command Get last CDM done is an internal command, moved to correct switch case. CRs-Fixed: 2939681 Change-Id: I72f72864bd52012e15a6bdbde279c9990aee405c Signed-off-by: Tejas Prajapati --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 2defa0cb44f1..8a82dd4f76d7 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6486,6 +6486,10 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) isp_hw_cmd_args->u.packet_op_code = CAM_ISP_PACKET_UPDATE_DEV; break; + case CAM_ISP_HW_MGR_GET_LAST_CDM_DONE: + isp_hw_cmd_args->u.last_cdm_done = + ctx->last_cdm_done_req; + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); @@ -6553,10 +6557,6 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) case CAM_HW_MGR_CMD_DUMP_ACQ_INFO: cam_ife_hw_mgr_dump_acq_data(ctx); break; - case CAM_ISP_HW_MGR_GET_LAST_CDM_DONE: - isp_hw_cmd_args->u.last_cdm_done = - ctx->last_cdm_done_req; - break; default: CAM_ERR(CAM_ISP, "Invalid cmd"); } -- GitLab From 2b505520fc7c93a9745c7f31d7155a04962214a1 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Mon, 3 May 2021 11:29:41 +0530 Subject: [PATCH 350/410] msm: camera: ife: Program image addr for once in RDI batch mode For RDI only batch mode use case the image address needs to be programmed only once the consecutive image address is taken from the frame increament address and image address we have provided. CRs-Fixed: 2948881 Change-Id: If6513ff4ac1c6df5daff549bc4418f839318f9d0 Signed-off-by: Tejas Prajapati --- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 56 ++++++++----------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 7c07e4ae07b4..6db7717d561c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -3041,9 +3041,8 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_client = NULL; uint32_t *reg_val_pair; - uint32_t i, j, k, size = 0; + uint32_t i, j, size = 0; uint32_t frame_inc = 0, val; - uint32_t loop_size = 0; bool frame_header_enable = false; bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; @@ -3172,41 +3171,32 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, wm_data->index, reg_val_pair[j-1]); } - if ((!bus_priv->common_data.is_lite && wm_data->index > 22) || - bus_priv->common_data.is_lite) - loop_size = wm_data->irq_subsample_period + 1; - else - loop_size = 1; - /* WM Image address */ - for (k = 0; k < loop_size; k++) { - if (wm_data->en_ubwc) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - update_buf->wm_update->image_buf[i] + - io_cfg->planes[i].meta_size + - k * frame_inc); - update_buf->wm_update->image_buf_offset[i] = - io_cfg->planes[i].meta_size; - } else if (wm_data->en_cfg & (0x3 << 16)) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - (update_buf->wm_update->image_buf[i] + - wm_data->offset + k * frame_inc)); - update_buf->wm_update->image_buf_offset[i] = - wm_data->offset; - } else { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - (update_buf->wm_update->image_buf[i] + - k * frame_inc)); - update_buf->wm_update->image_buf_offset[i] = 0; - } - CAM_DBG(CAM_ISP, "WM:%d image address 0x%X", - wm_data->index, reg_val_pair[j-1]); + if (wm_data->en_ubwc) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size); + update_buf->wm_update->image_buf_offset[i] = + io_cfg->planes[i].meta_size; + } else if (wm_data->en_cfg & (0x3 << 16)) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + wm_data->offset)); + update_buf->wm_update->image_buf_offset[i] = + wm_data->offset; + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i]); + update_buf->wm_update->image_buf_offset[i] = 0; } + CAM_DBG(CAM_ISP, "WM:%d image address 0x%X", + wm_data->index, reg_val_pair[j-1]); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->frame_incr, frame_inc); CAM_DBG(CAM_ISP, "WM:%d frame_inc %d", -- GitLab From 3944d27fee27cf43140db11188387dfa1cd2e77d Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Mon, 26 Apr 2021 14:07:23 +0530 Subject: [PATCH 351/410] msm: camera: isp: Add convert RAW10 to RAW8 support in CSID For some sensors input stream can be of format MIPI_RAW_10 but the output of CSID should be 8 bit. This adds support to preserve the 8 MSB and truncate 2 LSBs. CRs-Fixed: 2940817 Change-Id: I097593bac27ee4ae8859a682c0564f8fdd8c7e91 Signed-off-by: Gaurav Jindal --- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 2d1cace0e75f..372af1eb6a0f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -297,6 +297,12 @@ static int cam_ife_csid_get_format_rdi( break; case CAM_FORMAT_MIPI_RAW_10: switch (out_format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN8: + *plain_fmt = 0x0; + *decode_fmt = 0x2; + *packing_fmt = 0; + break; case CAM_FORMAT_MIPI_RAW_10: case CAM_FORMAT_PLAIN128: *decode_fmt = 0xf; -- GitLab From 05df09c8e526ef170ead93cc4f628259dbab3087 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Mon, 5 Apr 2021 10:21:18 +0530 Subject: [PATCH 352/410] msm: camera: isp: Check ife out res validity This change adds validity check for ife out res. If ife out res is NULL we can run into crash or issues. CRs-Fixed: 2915741 Change-Id: I8722b2a4e2634bda42f0080e00bf09050bbd6b91 Signed-off-by: Vikram Sharma --- .../isp_hw_mgr/hw_utils/cam_isp_packet_parser.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 4011c9956b67..2f1ad4d82f46 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -140,6 +140,14 @@ static int cam_isp_update_dual_config( } hw_mgr_res = &res_list_isp_out[i]; + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, + "Invalid isp out resource i %d num_out_res %d", + i, dual_config->num_ports); + rc = -EINVAL; + goto end; + } + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { if (!hw_mgr_res->hw_res[j]) continue; -- GitLab From daf6faa13f345fe2962d65dad40d2dbf1b0ab011 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Fri, 28 May 2021 16:45:27 +0530 Subject: [PATCH 353/410] msm: camera: ife: BW vote only for the acquired path At the time of VFE init the voting should be done based on the acquired ports instead of video port; in corner cases where only RDI port is acquired in IFE the initial vote will go to IFE_UBWC_STATS path which is for IFE_VIDEO but incoming votes will never have the voting for IFE_VIDEO since only IFE_RDI has been acquired, to make sure the vote is going to correct path at init time voting should be based on acquired paths. CRs-Fixed: 2977797 Change-Id: Ibd5e29fa126eb05c29f75d3489c3edbff3487b26 Signed-off-by: Tejas Prajapati --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 23 ++++++++++ .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 4 +- .../isp_hw/include/cam_vfe_hw_intf.h | 13 ++++++ .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 19 ++++++-- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c | 19 ++++++-- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h | 11 ++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 44 ++++++++++++++++++- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 43 +++++++++++++++++- 8 files changed, 163 insertions(+), 13 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 8a82dd4f76d7..e57269bdefbc 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -669,6 +669,8 @@ static void cam_ife_hw_mgr_print_acquire_info( struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; struct cam_isp_resource_node *hw_res = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_vfe_num_of_acquired_resources num_rsrc; int hw_idx[CAM_ISP_HW_SPLIT_MAX] = {-1, -1}; int i = 0; @@ -688,6 +690,27 @@ static void cam_ife_hw_mgr_print_acquire_info( if (acquire_failed) goto fail; + hw_mgr_res = list_first_entry(&hw_mgr_ctx->res_list_ife_src, + struct cam_ife_hw_mgr_res, list); + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + + if (hw_intf->hw_ops.process_cmd) { + num_rsrc.num_pix_rsrc = num_pix_port; + num_rsrc.num_pd_rsrc = num_pd_port; + num_rsrc.num_rdi_rsrc = num_rdi_port; + + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_SET_NUM_OF_ACQUIRED_RESOURCE, + &num_rsrc, + sizeof( + struct cam_vfe_num_of_acquired_resources)); + } + } + CAM_INFO(CAM_ISP, "Successfully acquire %s IFE[%d %d] with [%u pix] [%u pd] [%u rdi] ports for ctx:%u", (hw_mgr_ctx->is_dual) ? "dual" : "single", diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index ef0d744ba74d..4ca376f34f06 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_ISP_HW_H_ @@ -113,6 +113,8 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE, CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, CAM_ISP_HW_CMD_CSID_CLOCK_DUMP, + CAM_ISP_HW_CMD_SET_NUM_OF_ACQUIRED_RESOURCE, + CAM_ISP_HW_CMD_GET_NUM_OF_ACQUIRED_RESOURCE, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index 55cbda5aa786..e9fb2618b6bd 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -253,6 +253,19 @@ struct cam_vfe_bw_update_args { uint64_t external_bw_bytes; }; +/* + * struct cam_vfe_num_of_acquired_resources: + * + * @num_pix_rsrc: Number of pix resources acquired in context + * @num_pd_rsrc: Number of pd resources acquired in context + * @num_rdi_rsrc: Number of rdi resources acquired in context + */ +struct cam_vfe_num_of_acquired_resources { + uint32_t num_pix_rsrc; + uint32_t num_pd_rsrc; + uint32_t num_rdi_rsrc; +}; + /* * struct cam_vfe_fe_update_args: * diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 94ce25da29ab..ad726b86da73 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -147,6 +147,7 @@ int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) struct cam_hw_soc_info *soc_info = NULL; struct cam_vfe_hw_core_info *core_info = NULL; struct cam_isp_resource_node *isp_res = NULL; + struct cam_vfe_num_of_acquired_resources num_rsrc; int rc = 0; uint32_t reset_core_args = CAM_VFE_HW_RESET_HW_AND_REG; @@ -169,16 +170,26 @@ int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) soc_info = &vfe_hw->soc_info; core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *)init_hw_args; + + rc = core_info->vfe_top->hw_ops.process_cmd( + core_info->vfe_top->top_priv, + CAM_ISP_HW_CMD_GET_NUM_OF_ACQUIRED_RESOURCE, + &num_rsrc, + sizeof(struct cam_vfe_num_of_acquired_resources)); + if (rc) + CAM_ERR(CAM_ISP, "Failed to get the port information rc=%d", + rc); /* Turn ON Regulators, Clocks and other SOC resources */ - rc = cam_vfe_enable_soc_resources(soc_info); + rc = cam_vfe_enable_soc_resources(soc_info, num_rsrc.num_pix_rsrc, + num_rsrc.num_pd_rsrc, num_rsrc.num_rdi_rsrc); if (rc) { CAM_ERR(CAM_ISP, "Enable SOC failed"); rc = -EFAULT; goto decrement_open_cnt; } - isp_res = (struct cam_isp_resource_node *)init_hw_args; if (isp_res && isp_res->init) { rc = isp_res->init(isp_res, NULL, 0); if (rc) { @@ -598,6 +609,8 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_QUERY_DSP_MODE: case CAM_ISP_HW_CMD_CAMIF_DATA: case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: + case CAM_ISP_HW_CMD_SET_NUM_OF_ACQUIRED_RESOURCE: + case CAM_ISP_HW_CMD_GET_NUM_OF_ACQUIRED_RESOURCE: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c index 0d204b7a2400..4a4b4149da8d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -220,7 +220,8 @@ int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) return rc; } -int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) +int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info, + int num_pix_rsrc, int num_pd_rsrc, int num_rdi_rsrc) { int rc = 0; struct cam_vfe_soc_private *soc_private; @@ -242,8 +243,18 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_IFE_RDI1; } else { - axi_vote.axi_path[0].path_data_type = - CAM_AXI_PATH_DATA_IFE_VID; + if (num_pix_rsrc) + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; + else if (num_pd_rsrc) + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_PDAF; + else if (num_rdi_rsrc) + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_RDI0; + else + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; } axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h index 34ae02bce011..4a87529218b6 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_SOC_H_ @@ -73,10 +73,17 @@ int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info); * * @soc_info: Device soc information * + * @num_pix_rsrc: Number of pix resource in input port + * + * @num_pd_rsrc: Number of pdaf resource in input port + * + * @num_rdi_rsrc: Number of rdi resource in input port + * * @Return: 0: Success * Non-zero: Failure */ -int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info); +int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info, + int num_pix_rsrc, int num_pd_rsrc, int num_rdi_rsrc); /* * cam_vfe_disable_soc_resources() diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index b9527e406660..c34398f0b361 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -28,6 +28,9 @@ struct cam_vfe_top_ver2_priv { unsigned long req_clk_rate[ CAM_VFE_TOP_MUX_MAX]; struct cam_vfe_top_priv_common top_common; + uint32_t num_pix_rsrc; + uint32_t num_pd_rsrc; + uint32_t num_rdi_rsrc; }; static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv, @@ -410,7 +413,6 @@ int cam_vfe_top_reserve(void *device_priv, args = (struct cam_vfe_acquire_args *)reserve_args; acquire_args = &args->vfe_in; - for (i = 0; i < top_priv->top_common.num_mux; i++) { if (top_priv->top_common.mux_rsrc[i].res_id == acquire_args->res_id && @@ -485,6 +487,10 @@ int cam_vfe_top_release(void *device_priv, top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; mux_res = (struct cam_isp_resource_node *)release_args; + top_priv->num_pix_rsrc = 0; + top_priv->num_pd_rsrc = 0; + top_priv->num_rdi_rsrc = 0; + CAM_DBG(CAM_ISP, "Resource in state %d", mux_res->res_state); if (mux_res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) { CAM_ERR(CAM_ISP, "Error! Resource in Invalid res_state :%d", @@ -667,6 +673,32 @@ static int cam_vfe_get_irq_register_dump( return 0; } +static int cam_vfe_set_num_of_acquired_resource( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_num_of_acquired_resources *num_rsrc = cmd_args; + + top_priv->num_pix_rsrc = num_rsrc->num_pix_rsrc; + top_priv->num_pd_rsrc = num_rsrc->num_pd_rsrc; + top_priv->num_rdi_rsrc = num_rsrc->num_rdi_rsrc; + + return 0; +} + +static int cam_vfe_get_num_of_acquired_resource( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_num_of_acquired_resources *num_rsrc = cmd_args; + + num_rsrc->num_pix_rsrc = top_priv->num_pix_rsrc; + num_rsrc->num_pd_rsrc = top_priv->num_pd_rsrc; + num_rsrc->num_rdi_rsrc = top_priv->num_rdi_rsrc; + + return 0; +} + int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -730,6 +762,14 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_get_irq_register_dump(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_SET_NUM_OF_ACQUIRED_RESOURCE: + rc = cam_vfe_set_num_of_acquired_resource(top_priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_NUM_OF_ACQUIRED_RESOURCE: + rc = cam_vfe_get_num_of_acquired_resource(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index d7cf1a84f9c4..8e5248fa9b11 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -29,6 +29,9 @@ struct cam_vfe_top_ver3_priv { unsigned long req_clk_rate[ CAM_VFE_TOP_MUX_MAX]; struct cam_vfe_top_priv_common top_common; + uint32_t num_pix_rsrc; + uint32_t num_pd_rsrc; + uint32_t num_rdi_rsrc; }; static int cam_vfe_top_ver3_mux_get_base(struct cam_vfe_top_ver3_priv *top_priv, @@ -403,6 +406,10 @@ int cam_vfe_top_ver3_release(void *device_priv, top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; mux_res = (struct cam_isp_resource_node *)release_args; + top_priv->num_pix_rsrc = 0; + top_priv->num_pd_rsrc = 0; + top_priv->num_rdi_rsrc = 0; + CAM_DBG(CAM_ISP, "Resource in state %d", mux_res->res_state); if (mux_res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) { CAM_ERR(CAM_ISP, "Error, Resource in Invalid res_state :%d", @@ -577,6 +584,32 @@ static int cam_vfe_top_ver3_get_irq_register_dump( return 0; } +static int cam_vfe_top_ver3_set_num_of_acquired_resource( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_num_of_acquired_resources *num_rsrc = cmd_args; + + top_priv->num_pix_rsrc = num_rsrc->num_pix_rsrc; + top_priv->num_pd_rsrc = num_rsrc->num_pd_rsrc; + top_priv->num_rdi_rsrc = num_rsrc->num_rdi_rsrc; + + return 0; +} + +static int cam_vfe_top_ver3_get_num_of_acquired_resource( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_num_of_acquired_resources *num_rsrc = cmd_args; + + num_rsrc->num_pix_rsrc = top_priv->num_pix_rsrc; + num_rsrc->num_pd_rsrc = top_priv->num_pd_rsrc; + num_rsrc->num_rdi_rsrc = top_priv->num_rdi_rsrc; + + return 0; +} + int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -641,6 +674,14 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_ver3_get_irq_register_dump(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_SET_NUM_OF_ACQUIRED_RESOURCE: + rc = cam_vfe_top_ver3_set_num_of_acquired_resource(top_priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_NUM_OF_ACQUIRED_RESOURCE: + rc = cam_vfe_top_ver3_get_num_of_acquired_resource(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type); -- GitLab From 807609c322d3303082ee12a21581cbe266ecff36 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Tue, 10 Aug 2021 06:47:52 +0000 Subject: [PATCH 354/410] msm: camera: sync: Prevent OOB access of sync name Issue: strlcpy calls strlen on src ptr. If src is not NULL terminated then OOB access will occur in below stack. strlen strlcpy cam_sync_init_row cam_sync_handle_create cam_sync_dev_ioctl Fix: Pad user-space supplied name with NULL. CRs-Fixed: 3010262 Change-Id: Ib5c2fbfe395025ec05e0bb2980f86111e95ff54c Signed-off-by: Trishansh Bhardwaj --- drivers/cam_sync/cam_sync.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync.c b/drivers/cam_sync/cam_sync.c index dfb8ac10ee22..691f4113012b 100644 --- a/drivers/cam_sync/cam_sync.c +++ b/drivers/cam_sync/cam_sync.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -469,6 +469,7 @@ static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; + sync_create.name[SYNC_DEBUG_NAME_LEN] = '\0'; result = cam_sync_create(&sync_create.sync_obj, sync_create.name); -- GitLab From 9ff57cf57a441e6ff1b0ed45f87c2580ae76e2a2 Mon Sep 17 00:00:00 2001 From: Om Parkash Date: Fri, 27 Aug 2021 00:35:32 +0530 Subject: [PATCH 355/410] msm: camera: sensor: Add support to write sensor registers in probe Few sensors needs to unlock register bank for reading sensor ID from sensor register for probe. This change adds support to write sensor registers in probe cmd just after power on and before reading the sensor ID. CRs-Fixed: 3034934 Change-Id: I42ad13921c8510fb5a6dde361d62b442688a99b4 Signed-off-by: Om Parkash --- .../cam_sensor/cam_sensor_core.c | 97 ++++++++++++++++++- .../cam_sensor/cam_sensor_dev.c | 6 +- .../cam_sensor_utils/cam_sensor_cmn_header.h | 6 +- 3 files changed, 103 insertions(+), 6 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 0d4c1ce6d22b..3c6830de4ca6 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -58,6 +58,31 @@ static void cam_sensor_release_stream_rsc( } } +static void cam_sensor_free_power_reg_rsc( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int rc; + + i2c_set = &(s_ctrl->i2c_data.poweron_reg_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting PowerOnReg settings"); + } + + i2c_set = &(s_ctrl->i2c_data.poweroff_reg_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting PowerOffReg settings"); + } +} + static void cam_sensor_release_per_frame_resource( struct cam_sensor_ctrl_t *s_ctrl) { @@ -462,7 +487,8 @@ int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, struct cam_sensor_ctrl_t *s_ctrl, - int32_t cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len) + int32_t cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len, + struct cam_cmd_buf_desc *cmd_desc) { int32_t rc = 0; @@ -505,6 +531,42 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, } } break; + case 2: { + struct i2c_settings_array *i2c_reg_settings = NULL; + struct i2c_data_settings *i2c_data = NULL; + struct cam_buf_io_cfg *io_cfg = NULL; + + CAM_DBG(CAM_SENSOR, "poweron_reg_settings"); + i2c_data = &(s_ctrl->i2c_data); + i2c_reg_settings = &i2c_data->poweron_reg_settings; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser(&s_ctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in updating power register settings"); + return rc; + } + } + break; + case 3: { + struct i2c_settings_array *i2c_reg_settings = NULL; + struct i2c_data_settings *i2c_data = NULL; + struct cam_buf_io_cfg *io_cfg = NULL; + + CAM_DBG(CAM_SENSOR, "poweroff_reg_settings"); + i2c_data = &(s_ctrl->i2c_data); + i2c_reg_settings = &i2c_data->poweroff_reg_settings; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser(&s_ctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in updating power register settings"); + return rc; + } + } + break; default: CAM_ERR(CAM_SENSOR, "Invalid command buffer"); break; @@ -552,7 +614,7 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) rc = -EINVAL; goto end; } - if (pkt->num_cmd_buf != 2) { + if (pkt->num_cmd_buf < 2) { CAM_ERR(CAM_SENSOR, "Expected More Command Buffers : %d", pkt->num_cmd_buf); rc = -EINVAL; @@ -587,7 +649,7 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) ptr = (void *) cmd_buf; rc = cam_handle_cmd_buffers_for_probe(ptr, s_ctrl, - i, cmd_desc[i].length, remain_len); + i, cmd_desc[i].length, remain_len, &cmd_desc[i]); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to parse the command Buffer Header"); @@ -783,6 +845,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "power up failed"); goto free_power_settings; } + if (s_ctrl->i2c_data.poweron_reg_settings.is_settings_valid) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_POWERON_REG); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "PowerOn REG_WR failed"); + goto free_power_settings; + } + } /* Match sensor ID */ rc = cam_sensor_match_id(s_ctrl); @@ -792,12 +862,22 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto free_power_settings; } + if (s_ctrl->i2c_data.poweroff_reg_settings.is_settings_valid) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_POWEROFF_REG); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "PowerOff REG_WR failed"); + goto free_power_settings; + } + } + CAM_INFO(CAM_SENSOR, "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x", s_ctrl->soc_info.index, s_ctrl->sensordata->slave_info.sensor_slave_addr, s_ctrl->sensordata->slave_info.sensor_id); + cam_sensor_free_power_reg_rsc(s_ctrl); rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); @@ -1099,6 +1179,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, power_info->power_down_setting = NULL; power_info->power_down_setting_size = 0; power_info->power_setting_size = 0; + cam_sensor_free_power_reg_rsc(s_ctrl); mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return rc; } @@ -1285,6 +1366,14 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, i2c_set = &s_ctrl->i2c_data.read_settings; break; } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_POWERON_REG: { + i2c_set = &s_ctrl->i2c_data.poweron_reg_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_POWEROFF_REG: { + i2c_set = &s_ctrl->i2c_data.poweroff_reg_settings; + break; + } case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: case CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE: default: diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index c1b661638d05..ed6b17b7bea3 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_sensor_dev.h" @@ -210,6 +210,8 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.poweron_reg_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.poweroff_reg_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.read_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) @@ -347,6 +349,8 @@ static int32_t cam_sensor_driver_platform_probe( INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.poweron_reg_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.poweroff_reg_settings.list_head)); INIT_LIST_HEAD(&(s_ctrl->i2c_data.read_settings.list_head)); for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 43734ace9c9d..9c4025a789af 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SENSOR_CMN_HEADER_ @@ -153,6 +153,8 @@ enum cam_sensor_packet_opcodes { CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF, CAM_SENSOR_PACKET_OPCODE_SENSOR_READ, + CAM_SENSOR_PACKET_OPCODE_SENSOR_POWERON_REG, + CAM_SENSOR_PACKET_OPCODE_SENSOR_POWEROFF_REG, CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP = 127 }; @@ -306,6 +308,8 @@ struct i2c_data_settings { struct i2c_settings_array streamon_settings; struct i2c_settings_array streamoff_settings; struct i2c_settings_array read_settings; + struct i2c_settings_array poweron_reg_settings; + struct i2c_settings_array poweroff_reg_settings; struct i2c_settings_array *per_frame; }; -- GitLab From 6ae2412f41497e5007bac465bfaafa241c056ea5 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Mon, 6 Sep 2021 21:12:00 +0530 Subject: [PATCH 356/410] msm: camera: jpeg: Ensure in/out map entries are within allowed range Added checks to make sure in_map /out_map entries of packet io configs are within expected maximum value. CRs-Fixed: 3007258 Change-Id: I7e5a652cd8f9ae104a10a2af551fe49930849b2d Signed-off-by: Shravya Samala --- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index f0be4802d197..e30033d1169b 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -728,10 +728,12 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, } if ((packet->num_cmd_buf > 5) || !packet->num_patches || - !packet->num_io_configs) { - CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u", - packet->num_cmd_buf, - packet->num_patches); + !packet->num_io_configs || + (packet->num_io_configs > CAM_JPEG_IMAGE_MAX)) { + CAM_ERR(CAM_JPEG, + "wrong number of cmd/patch/io_configs info: %u %u %u", + packet->num_cmd_buf, packet->num_patches, + packet->num_io_configs); return -EINVAL; } -- GitLab From 923271ed7aeca9c696898f21d366c8ec7daa39aa Mon Sep 17 00:00:00 2001 From: Cullum Baldwin Date: Tue, 14 Sep 2021 10:59:09 -0700 Subject: [PATCH 357/410] msm: camera: ife: use universal qtime-to-boottime offset for all cams Modify IFE timestamp calculation to use a single qtime-to-boottime offset value for all cameras. This will allow more precise timestamp comparison between cameras. CRs-Fixed: 3050973 Change-Id: Ia401ac05ba4020dbc9bf62ecd33eaa8f6fcefba0 Signed-off-by: Cullum Baldwin --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 372af1eb6a0f..f5fc6a84c722 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -46,6 +46,9 @@ /* Max CSI Rx irq error count threshold value */ #define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 +/* factor to conver qtime to boottime */ +static int64_t qtime_to_boottime; + static int cam_ife_csid_reset_regs( struct cam_ife_csid_hw *csid_hw, bool reset_hw); @@ -3394,7 +3397,6 @@ static int cam_ife_csid_get_time_stamp( const struct cam_ife_csid_udi_reg_offset *udi_reg; struct timespec64 ts; uint32_t time_32, id; - uint64_t time_delta; time_stamp = (struct cam_csid_get_time_stamp_args *)cmd_args; res = time_stamp->node_res; @@ -3466,20 +3468,19 @@ static int cam_ife_csid_get_time_stamp( CAM_IFE_CSID_QTIMER_MUL_FACTOR, CAM_IFE_CSID_QTIMER_DIV_FACTOR); - if (!csid_hw->prev_boot_timestamp) { + /* use a universal qtime-2-boottime offset for all cameras + * this enables uniform timestamp comparision between cameras + */ + if (qtime_to_boottime == 0) { get_monotonic_boottime64(&ts); - time_stamp->boot_timestamp = - (uint64_t)((ts.tv_sec * 1000000000) + - ts.tv_nsec); - csid_hw->prev_qtimer_ts = 0; - CAM_DBG(CAM_ISP, "timestamp:%lld", - time_stamp->boot_timestamp); - } else { - time_delta = time_stamp->time_stamp_val - - csid_hw->prev_qtimer_ts; - time_stamp->boot_timestamp = - csid_hw->prev_boot_timestamp + time_delta; + qtime_to_boottime = + (int64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec) - + (int64_t)time_stamp->time_stamp_val; + CAM_DBG(CAM_ISP, "qtime_to_boottime:%lld", qtime_to_boottime); } + + time_stamp->boot_timestamp = time_stamp->time_stamp_val + + qtime_to_boottime; csid_hw->prev_qtimer_ts = time_stamp->time_stamp_val; csid_hw->prev_boot_timestamp = time_stamp->boot_timestamp; -- GitLab From c9c62bcd7e4ef53a7e070dfe276cfa22cc59e804 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Wed, 11 Aug 2021 11:06:27 +0530 Subject: [PATCH 358/410] msm: camera: cdm: Acquire mutex lock before accessing client data There is a chance of use after release of client data in cdm internal operation calls. Hence acquire mutex lock whenever accessing client data to avoid use after release scenario. CRs-Fixed: 3010261 Change-Id: Iaf7f41d56301299a6f63a5dc1090334063019881 Signed-off-by: Shravya Samala --- drivers/cam_cdm/cam_cdm_core_common.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index ee9f4942950f..56c915cceb97 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -201,6 +201,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { if (core->clients[i] != NULL) { + mutex_lock(&cdm_hw->hw_mutex); client = core->clients[i]; mutex_lock(&client->lock); CAM_DBG(CAM_CDM, "Found client slot %d", i); @@ -221,6 +222,7 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, client->handle); } mutex_unlock(&client->lock); + mutex_unlock(&cdm_hw->hw_mutex); } } } @@ -239,35 +241,34 @@ int cam_cdm_stream_ops_internal(void *hw_priv, return -EINVAL; core = (struct cam_cdm *)cdm_hw->core_info; + mutex_lock(&cdm_hw->hw_mutex); client_idx = CAM_CDM_GET_CLIENT_IDX(*handle); client = core->clients[client_idx]; if (!client) { CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, *handle); + mutex_unlock(&cdm_hw->hw_mutex); return -EINVAL; } cam_cdm_get_client_refcount(client); if (*handle != client->handle) { CAM_ERR(CAM_CDM, "client id given handle=%x invalid", *handle); - cam_cdm_put_client_refcount(client); - return -EINVAL; + rc = -EINVAL; + goto end; } if (operation == true) { if (true == client->stream_on) { CAM_ERR(CAM_CDM, "Invalid CDM client is already streamed ON"); - cam_cdm_put_client_refcount(client); - return rc; + goto end; } } else { if (client->stream_on == false) { CAM_ERR(CAM_CDM, "Invalid CDM client is already streamed Off"); - cam_cdm_put_client_refcount(client); - return rc; + goto end; } } - mutex_lock(&cdm_hw->hw_mutex); if (operation == true) { if (!cdm_hw->open_count) { struct cam_ahb_vote ahb_vote; -- GitLab From 84b63b606c963c77115d3b43e5fc5e19616012ce Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 21 Oct 2021 15:19:08 +0530 Subject: [PATCH 359/410] msm: camera: reqmgr: update timer even after skip frame If Nth request has additional exposure timeout, after applying sensor settings for Nth request; CRM watchdog timer should be updated with the Nth requests additional timeout on next frame irrespective of skip frame to avoid sof freeze. CRs-Fixed: 3075875 Change-Id: Icc568fc0e169fed9c6a588ab2c2cbff7ec6c0d8a Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_req_mgr_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index da1c1a2d5086..1ec15c41883e 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1491,6 +1491,12 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, rc = -EPERM; } spin_unlock_bh(&link->link_state_spin_lock); + /* + * Update wd timer so in next frame if the request + * packet is available request can be applied, SOF + * freeze will hit otherwise. + */ + __cam_req_mgr_validate_crm_wd_timer(link); goto error; } } -- GitLab From c3547a2716052cc8564d3747b853bbeb7f9afc40 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 25 Mar 2021 23:28:22 +0530 Subject: [PATCH 360/410] msm: camera: isp: Dont enable Wm configurations during HW start There is a chance that during acquire time while updating write master, for few resources io buffers are not allocated. If Wm configurations are enabled without receiving io buffers then there is a chance of hitting page fault issues. This commit takes care of enabling Wm configurations for each client only if io buffers are allocated. CRs-Fixed: 2887053 Change-Id: I868bd01dbd896dd86eeec4fc92a8a62e746f79cf Signed-off-by: Shravya Samala --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 0207847f7021..30024f6a23d3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1299,10 +1299,9 @@ static int cam_vfe_bus_start_wm( return -EINVAL; } } - - /* Enable WM */ - cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + - rsrc_data->hw_regs->cfg); + /* enabling Wm configuratons are taken care in update_wm(). + * i.e enable wm only if io buffers are allocated + */ CAM_DBG(CAM_ISP, "WM res %d width = %d, height = %d", rsrc_data->index, rsrc_data->width, rsrc_data->height); -- GitLab From 74b976742099b7739a34551681d139230bd8e049 Mon Sep 17 00:00:00 2001 From: Shravya Samala Date: Thu, 1 Apr 2021 17:01:50 +0530 Subject: [PATCH 361/410] msm: camera: isp: Change logic of acquiring dual composite group There is a possibility of composite groups in free dual composite group list are not in sequential order. In case of dual ife use case, if composite groups are not in sequential manner then we landed into a scenario where two different IFE with same resource have two different composite group index, which is not expected. This commit ensures if it is dual IFE usecase then at the time of acquiring composite group, both IFEs have same composite group ID for same resource. CRs-Fixed: 2912721 Change-Id: I734d1d1660c1e70e0480e2dc0b8377a1c441c634 Signed-off-by: Shravya Samala --- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 67 ++++++++++++++++++- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 0207847f7021..e6e21771335a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -261,6 +261,28 @@ static enum cam_vfe_bus_comp_grp_id } } +static enum cam_vfe_bus_ver2_comp_grp_type + cam_vfe_bus_dual_comp_grp_id_convert(uint32_t comp_grp) +{ + switch (comp_grp) { + case CAM_VFE_BUS_COMP_GROUP_ID_0: + return CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0; + case CAM_VFE_BUS_COMP_GROUP_ID_1: + return CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1; + case CAM_VFE_BUS_COMP_GROUP_ID_2: + return CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2; + case CAM_VFE_BUS_COMP_GROUP_ID_3: + return CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3; + case CAM_VFE_BUS_COMP_GROUP_ID_4: + return CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4; + case CAM_VFE_BUS_COMP_GROUP_ID_5: + return CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5; + case CAM_VFE_BUS_COMP_GROUP_NONE: + default: + return CAM_VFE_BUS_VER2_COMP_GRP_MAX; + } +} + static int cam_vfe_bus_put_evt_payload( struct cam_vfe_bus_ver2_common_data *common_data, struct cam_vfe_bus_irq_evt_payload **evt_payload) @@ -1784,6 +1806,39 @@ static void cam_vfe_bus_match_comp_grp( *comp_grp = NULL; } +static int cam_vfe_bus_get_free_dual_comp_grp( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_resource_node **comp_grp, + uint32_t comp_grp_local_idx) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + struct cam_isp_resource_node *dual_comp_grp_local = NULL; + struct cam_isp_resource_node *dual_comp_grp_local_temp = NULL; + int32_t dual_comp_grp_idx = 0; + int rc = -EINVAL; + + dual_comp_grp_idx = + cam_vfe_bus_dual_comp_grp_id_convert(comp_grp_local_idx); + + CAM_DBG(CAM_ISP, "dual_comp_grp_idx :%d", dual_comp_grp_idx); + + list_for_each_entry_safe(dual_comp_grp_local, dual_comp_grp_local_temp, + &ver2_bus_priv->free_dual_comp_grp, list) { + rsrc_data = dual_comp_grp_local->res_priv; + CAM_DBG(CAM_ISP, "current grp type : %d expected :%d", + rsrc_data->comp_grp_type, dual_comp_grp_idx); + if (dual_comp_grp_idx != rsrc_data->comp_grp_type) { + continue; + } else { + list_del_init(&dual_comp_grp_local->list); + *comp_grp = dual_comp_grp_local; + return 0; + } + } + + return rc; +} + static int cam_vfe_bus_acquire_comp_grp( struct cam_vfe_bus_ver2_priv *ver2_bus_priv, struct cam_isp_out_port_generic_info *out_port_info, @@ -1816,9 +1871,15 @@ static int cam_vfe_bus_acquire_comp_grp( CAM_ERR(CAM_ISP, "No Free Composite Group"); return -ENODEV; } - comp_grp_local = list_first_entry( - &ver2_bus_priv->free_dual_comp_grp, - struct cam_isp_resource_node, list); + rc = cam_vfe_bus_get_free_dual_comp_grp( + ver2_bus_priv, &comp_grp_local, + bus_comp_grp_id); + if (rc || !comp_grp_local) { + CAM_ERR(CAM_ISP, + "failed to acquire dual comp grp for :%d rc :%d", + bus_comp_grp_id, rc); + return rc; + } rsrc_data = comp_grp_local->res_priv; rc = cam_vfe_bus_ver2_get_intra_client_mask( dual_slave_core, -- GitLab From cef777c9063e8d7ea2a3abd0e493695731091d78 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 18 Nov 2021 17:07:47 +0530 Subject: [PATCH 362/410] msm: camera: reqmgr: reader writer locks to avoid memory faults Shared memory is initialized by CRM and used by other drivers; with CRM not active other drivers would fail to access the shared memory if memory manager is deinit. Reader Writer locks can prevent the open/close/ioctl calls from other drivers if CRM open/close is already being processed. Issue observed with the below sequence if drivers are opened from UMD directly without this change. CRM Open successful,ICP open successful, CRM close in progress, ICP open successful, mem mgr deinit and CRM close successful, ICP tries to access HFI memory and result in crash. This change helps to serialze the calls and prevents issue. CRs-Fixed: 3019488 Change-Id: Ifdf198c2e3593050573c66aeba69d50d131435b9 Signed-off-by: Tejas Prajapati --- drivers/cam_core/cam_subdev.c | 2 + drivers/cam_fd/cam_fd_dev.c | 5 ++ drivers/cam_icp/cam_icp_subdev.c | 3 ++ drivers/cam_isp/cam_isp_dev.c | 4 ++ drivers/cam_jpeg/cam_jpeg_dev.c | 2 + drivers/cam_lrme/cam_lrme_dev.c | 5 ++ drivers/cam_req_mgr/cam_req_mgr_dev.c | 50 ++++++++++++++++++- drivers/cam_req_mgr/cam_req_mgr_dev.h | 2 + drivers/cam_req_mgr/cam_req_mgr_util.c | 9 ++++ drivers/cam_req_mgr/cam_subdev.h | 29 +++++++++++ .../cam_actuator/cam_actuator_core.c | 5 ++ .../cam_csiphy/cam_csiphy_core.c | 6 +++ .../cam_eeprom/cam_eeprom_core.c | 4 ++ .../cam_flash/cam_flash_dev.c | 5 ++ .../cam_sensor_module/cam_ois/cam_ois_core.c | 4 ++ .../cam_sensor/cam_sensor_core.c | 5 ++ 16 files changed, 139 insertions(+), 1 deletion(-) diff --git a/drivers/cam_core/cam_subdev.c b/drivers/cam_core/cam_subdev.c index 1a81a4d59e99..15b5fd84bbc4 100644 --- a/drivers/cam_core/cam_subdev.c +++ b/drivers/cam_core/cam_subdev.c @@ -53,8 +53,10 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, switch (cmd) { case VIDIOC_CAM_CONTROL: + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); rc = cam_node_handle_ioctl(node, (struct cam_control *) arg); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); break; default: CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd, diff --git a/drivers/cam_fd/cam_fd_dev.c b/drivers/cam_fd/cam_fd_dev.c index ddf6cf3843de..e68ba141fee4 100644 --- a/drivers/cam_fd/cam_fd_dev.c +++ b/drivers/cam_fd/cam_fd_dev.c @@ -43,8 +43,11 @@ static int cam_fd_dev_open(struct v4l2_subdev *sd, { struct cam_fd_dev *fd_dev = &g_fd_dev; + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + if (!fd_dev->probe_done) { CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return -ENODEV; } @@ -53,6 +56,8 @@ static int cam_fd_dev_open(struct v4l2_subdev *sd, CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); mutex_unlock(&fd_dev->lock); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); + return 0; } diff --git a/drivers/cam_icp/cam_icp_subdev.c b/drivers/cam_icp/cam_icp_subdev.c index bdb2ed5f900b..128b171f8659 100644 --- a/drivers/cam_icp/cam_icp_subdev.c +++ b/drivers/cam_icp/cam_icp_subdev.c @@ -75,6 +75,8 @@ static int cam_icp_subdev_open(struct v4l2_subdev *sd, struct cam_node *node = v4l2_get_subdevdata(sd); int rc = 0; + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_icp_dev.icp_lock); if (g_icp_dev.open_cnt >= 1) { CAM_ERR(CAM_ICP, "ICP subdev is already opened"); @@ -97,6 +99,7 @@ static int cam_icp_subdev_open(struct v4l2_subdev *sd, g_icp_dev.open_cnt++; end: mutex_unlock(&g_icp_dev.icp_lock); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return rc; } diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c index 9c3f33181ae6..2e28232e91be 100644 --- a/drivers/cam_isp/cam_isp_dev.c +++ b/drivers/cam_isp/cam_isp_dev.c @@ -50,10 +50,14 @@ static const struct of_device_id cam_isp_dt_match[] = { static int cam_isp_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_isp_dev.isp_mutex); g_isp_dev.open_cnt++; mutex_unlock(&g_isp_dev.isp_mutex); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); + return 0; } diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c index 85da82cea7ba..b123ebe8059a 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/cam_jpeg/cam_jpeg_dev.c @@ -49,10 +49,12 @@ static const struct of_device_id cam_jpeg_dt_match[] = { static int cam_jpeg_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); mutex_lock(&g_jpeg_dev.jpeg_mutex); g_jpeg_dev.open_cnt++; mutex_unlock(&g_jpeg_dev.jpeg_mutex); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return 0; } diff --git a/drivers/cam_lrme/cam_lrme_dev.c b/drivers/cam_lrme/cam_lrme_dev.c index 7c09f2b435f5..656a4dbd726b 100644 --- a/drivers/cam_lrme/cam_lrme_dev.c +++ b/drivers/cam_lrme/cam_lrme_dev.c @@ -58,9 +58,12 @@ static int cam_lrme_dev_open(struct v4l2_subdev *sd, { struct cam_lrme_dev *lrme_dev = g_lrme_dev; + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK); + if (!lrme_dev) { CAM_ERR(CAM_LRME, "LRME Dev not initialized, dev=%pK", lrme_dev); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); return -ENODEV; } @@ -68,6 +71,8 @@ static int cam_lrme_dev_open(struct v4l2_subdev *sd, lrme_dev->open_cnt++; mutex_unlock(&lrme_dev->lock); + cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK); + return 0; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 81693e0d9d9e..c783aa0fc519 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include @@ -30,6 +32,8 @@ static struct cam_req_mgr_device g_dev; struct kmem_cache *g_cam_req_mgr_timer_cachep; +DECLARE_RWSEM(rwsem_lock); + static int cam_media_device_setup(struct device *dev) { int rc; @@ -95,10 +99,28 @@ static void cam_v4l2_device_cleanup(void) g_dev.v4l2_dev = NULL; } +void cam_req_mgr_rwsem_read_op(enum cam_subdev_rwsem lock) +{ + if (lock == CAM_SUBDEV_LOCK) + down_read(&rwsem_lock); + else if (lock == CAM_SUBDEV_UNLOCK) + up_read(&rwsem_lock); +} + +static void cam_req_mgr_rwsem_write_op(enum cam_subdev_rwsem lock) +{ + if (lock == CAM_SUBDEV_LOCK) + down_write(&rwsem_lock); + else if (lock == CAM_SUBDEV_UNLOCK) + up_write(&rwsem_lock); +} + static int cam_req_mgr_open(struct file *filep) { int rc; + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_LOCK); + mutex_lock(&g_dev.cam_lock); if (g_dev.open_cnt >= 1) { rc = -EALREADY; @@ -125,12 +147,14 @@ static int cam_req_mgr_open(struct file *filep) } mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); return rc; mem_mgr_init_fail: v4l2_fh_release(filep); end: mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); return rc; } @@ -157,11 +181,15 @@ static int cam_req_mgr_close(struct file *filep) struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); CAM_WARN(CAM_CRM, - "release invoked associated userspace process has died"); + "release invoked associated userspace process has died, open_cnt: %d", + g_dev.open_cnt); + + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_LOCK); mutex_lock(&g_dev.cam_lock); if (g_dev.open_cnt <= 0) { mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); return -EINVAL; } @@ -195,6 +223,8 @@ static int cam_req_mgr_close(struct file *filep) cam_mem_mgr_deinit(); mutex_unlock(&g_dev.cam_lock); + cam_req_mgr_rwsem_write_op(CAM_SUBDEV_UNLOCK); + return 0; } @@ -660,6 +690,24 @@ void cam_subdev_notify_message(u32 subdev_type, } EXPORT_SYMBOL(cam_subdev_notify_message); +bool cam_req_mgr_is_open(void) +{ + bool crm_status = false; + + mutex_lock(&g_dev.cam_lock); + crm_status = g_dev.open_cnt ? true : false; + mutex_unlock(&g_dev.cam_lock); + + return crm_status; +} +EXPORT_SYMBOL(cam_req_mgr_is_open); + +bool cam_req_mgr_is_shutdown(void) +{ + return g_dev.shutdown_state; +} +EXPORT_SYMBOL(cam_req_mgr_is_shutdown); + int cam_register_subdev(struct cam_subdev *csd) { struct v4l2_subdev *sd; diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.h b/drivers/cam_req_mgr/cam_req_mgr_dev.h index 48ad09ce5ee2..ccf4854a03d2 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.h +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.h @@ -19,6 +19,7 @@ * @cam_lock: per file handle lock * @cam_eventq: event queue * @cam_eventq_lock: lock for event queue + * @shutdown_state: shutdown state */ struct cam_req_mgr_device { struct video_device *video; @@ -31,6 +32,7 @@ struct cam_req_mgr_device { struct mutex cam_lock; struct v4l2_fh *cam_eventq; spinlock_t cam_eventq_lock; + bool shutdown_state; }; #define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \ diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index 88b6bf079e9c..77bec80006be 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -14,6 +14,7 @@ #include #include "cam_req_mgr_util.h" #include "cam_debug_util.h" +#include "cam_subdev.h" static struct cam_req_mgr_util_hdl_tbl *hdl_tbl; static DEFINE_SPINLOCK(hdl_tbl_lock); @@ -159,6 +160,14 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) int idx; int rand = 0; int32_t handle; + bool crm_active; + + crm_active = cam_req_mgr_is_open(); + if (!crm_active) { + CAM_ERR(CAM_ICP, "CRM is not ACTIVE"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } spin_lock_bh(&hdl_tbl_lock); if (!hdl_tbl) { diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h index 5a0ef2ef5ecf..b4e5580c1b49 100644 --- a/drivers/cam_req_mgr/cam_subdev.h +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -20,6 +20,11 @@ enum cam_subdev_message_type_t { CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1 }; +enum cam_subdev_rwsem { + CAM_SUBDEV_LOCK = 1, + CAM_SUBDEV_UNLOCK, +}; + /** * struct cam_subdev - describes a camera sub-device * @@ -128,4 +133,28 @@ int cam_register_subdev(struct cam_subdev *sd); */ int cam_unregister_subdev(struct cam_subdev *sd); +/** + * cam_req_mgr_rwsem_read_op() + * + * @brief : API to acquire read semaphore lock to platform framework. + * + * @lock : value indicates to lock or unlock the read lock + */ +void cam_req_mgr_rwsem_read_op(enum cam_subdev_rwsem lock); + +/** + * cam_req_mgr_is_open() + * + * @brief: This common utility function returns the crm active status + * + */ +bool cam_req_mgr_is_open(void); + +/** + * cam_req_mgr_is_shutdown() + * + * @brief: This common utility function returns the shutdown state + */ +bool cam_req_mgr_is_shutdown(void); + #endif /* _CAM_SUBDEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index 0b6e25572e90..8ee158472765 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -825,6 +825,11 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, actuator_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (actuator_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_ACTUATOR, "Can not create device handle"); + goto release_mutex; + } a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle; a_ctrl->bridge_intf.session_hdl = actuator_acq_dev.session_handle; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index c091c3e5cef3..b4ebae694ef3 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -915,6 +915,12 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, index = csiphy_dev->acquire_count; csiphy_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (csiphy_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_CSIPHY, "Can not create device handle"); + goto release_mutex; + } + csiphy_dev->csiphy_info[index].hdl_data.device_hdl = csiphy_acq_dev.device_handle; csiphy_dev->csiphy_info[index].hdl_data.session_hdl = diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index caf5132b3df2..2d4f986dbf47 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -354,6 +354,10 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, eeprom_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (eeprom_acq_dev.device_handle <= 0) { + CAM_ERR(CAM_EEPROM, "Can not create device handle"); + return -EFAULT; + } e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; e_ctrl->bridge_intf.session_hdl = eeprom_acq_dev.session_handle; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index d47149455526..c8b5a4fb85cf 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -66,6 +66,11 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, flash_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (flash_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_FLASH, "Can not create device handle"); + goto release_mutex; + } fctrl->bridge_intf.device_hdl = flash_acq_dev.device_handle; fctrl->bridge_intf.session_hdl = diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 6a1ccbd4aa11..4520139fa001 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -85,6 +85,10 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, ois_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (ois_acq_dev.device_handle <= 0) { + CAM_ERR(CAM_OIS, "Can not create device handle"); + return -EFAULT; + } o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle; o_ctrl->bridge_intf.session_hdl = ois_acq_dev.session_handle; diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 3c6830de4ca6..a6cbd20d62af 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -925,6 +925,11 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, sensor_acq_dev.device_handle = cam_create_device_hdl(&bridge_params); + if (sensor_acq_dev.device_handle <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_SENSOR, "Can not create device handle"); + goto release_mutex; + } s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; s_ctrl->bridge_intf.session_hdl = sensor_acq_dev.session_handle; -- GitLab From 4d2d48aa1eb6e04893aa64266143e8aee188a4d0 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Mon, 20 Dec 2021 14:44:36 +0530 Subject: [PATCH 363/410] msm: camera: reqmgr: check if link handle is correctly passed Instead of the link handle if the dev handle is passed for dumping the request information, this can lead to accessing invalid data structure. To avodi accessing invalid data structure based on the dev handle, first check if the link handle passed in IOCTL is matchting with looked up link handle. CRs-Fixed: 3097336 Change-Id: I815457ff96e3b26fe9fa886bd984d53d209e4edb Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_req_mgr_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 1ec15c41883e..ffd5381ac706 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -4061,7 +4061,7 @@ int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) link = (struct cam_req_mgr_core_link *) cam_get_device_priv(dump_req->link_hdl); - if (!link) { + if (!link || link->link_hdl != dump_req->link_hdl) { CAM_DBG(CAM_CRM, "link ptr NULL %x", dump_req->link_hdl); rc = -EINVAL; goto end; -- GitLab From cb712bc2b33d6188da79a831e9f5245bbc66f493 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 3 Mar 2022 16:01:22 +0530 Subject: [PATCH 364/410] msm: camera: memmgr: update correct length in bufq In a corner case, race condition to free the original ion buf allocated and new ion buffer with same fd but different size after freeing the origianl ion buf might result into mismatches in the real ion buf size assigned in bufq. To avoid this update length in bufq with local variable. CRs-Fixed: 3142221 Change-Id: I8241544dba7609662d01f8d765e8d171b8288baa Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_mem_mgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 60ff61314ebb..359004f68900 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, 2022 The Linux Foundation. All rights reserved. */ #include @@ -685,7 +685,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) if (rc) { CAM_ERR(CAM_MEM, "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", - cmd->len, cmd->flags, fd, region, + len, cmd->flags, fd, region, cmd->num_hdl, rc); mutex_unlock(&tbl.m_lock); goto map_hw_fail; @@ -712,7 +712,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) tbl.bufq[idx].kmdvaddr = kvaddr; tbl.bufq[idx].vaddr = hw_vaddr; tbl.bufq[idx].dma_buf = dmabuf; - tbl.bufq[idx].len = cmd->len; + tbl.bufq[idx].len = len; tbl.bufq[idx].num_hdl = cmd->num_hdl; memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls, sizeof(int32_t) * cmd->num_hdl); -- GitLab From ea7908535a1bde5cb57e58eac90b1b09b88cad79 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Tue, 23 Jun 2020 22:17:18 +0800 Subject: [PATCH 365/410] msm: camera: isp: Handling IRQ delays Check the BUS write client last consumed address, if it matches with next request port io buffer address, then irq delay detected. We can signal port fence for both active request. CRs-Fixed: 2684890 Change-Id: I8265c06a2284897d43e9a24511ad2c13c9690186 Signed-off-by: Depeng Shao Signed-off-by: Nirmal Abraham --- drivers/cam_core/cam_hw_mgr_intf.h | 3 + drivers/cam_isp/cam_isp_context.c | 395 ++++++++++++++---- drivers/cam_isp/cam_isp_context.h | 3 + drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 39 +- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 4 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 8 +- .../isp_hw/include/cam_vfe_hw_intf.h | 7 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe170.h | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe175.h | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe480.h | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h | 2 + .../isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h | 3 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 11 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 3 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 45 ++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h | 15 +- .../vfe_hw/vfe_top/cam_vfe_camif_ver3.c | 9 +- 20 files changed, 461 insertions(+), 98 deletions(-) diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 80b992817865..2a3abdda3a3a 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_HW_MGR_INTF_H_ @@ -106,6 +107,7 @@ struct cam_hw_done_event_data { * @ctxt_to_hw_map: HW context (returned) * @custom_enabled: ctx has custom enabled * @use_frame_header_ts: Use frame header for qtimer ts + * @support_consumed_addr: The platform has last consumed addr register * @acquired_hw_id: Acquired hardware mask * @acquired_hw_path: Acquired path mask for an input * if input splits into multiple paths, @@ -123,6 +125,7 @@ struct cam_hw_acquire_args { void *ctxt_to_hw_map; bool custom_enabled; bool use_frame_header_ts; + bool support_consumed_addr; uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 6a586372c7aa..bfa19dcfd7e2 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -738,6 +739,70 @@ static void __cam_isp_ctx_handle_buf_done_fail_log( } } +static int __cam_isp_ctx_handle_buf_done_for_req_list( + struct cam_isp_context *ctx_isp, + struct cam_ctx_request *req) +{ + int rc = 0, i; + uint64_t buf_done_req_id; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + ctx_isp->active_req_cnt--; + buf_done_req_id = req->request_id; + + if (req_isp->bubble_detected && req_isp->bubble_report) { + req_isp->num_acked = 0; + req_isp->bubble_detected = false; + list_del_init(&req->list); + atomic_set(&ctx_isp->process_bubble, 0); + + if (buf_done_req_id <= ctx->last_flush_req) { + for (i = 0; i < req_isp->num_fence_map_out; i++) + rc = cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", + buf_done_req_id, ctx_isp->active_req_cnt, + ctx->ctx_id); + } else { + list_add(&req->list, &ctx->pending_req_list); + CAM_DBG(CAM_REQ, + "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", + req->request_id, ctx_isp->active_req_cnt, + ctx->ctx_id); + } + } else { + if (!ctx_isp->use_frame_header_ts) { + if (ctx_isp->reported_req_id < buf_done_req_id) { + ctx_isp->reported_req_id = buf_done_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + buf_done_req_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + req_isp->reapply = false; + + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", + buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); + ctx_isp->req_info.last_bufdone_req_id = req->request_id; + } + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); + + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_BUFDONE, req); + return rc; +} + static int __cam_isp_ctx_handle_buf_done_for_request( struct cam_isp_context *ctx_isp, struct cam_ctx_request *req, @@ -749,7 +814,6 @@ static int __cam_isp_ctx_handle_buf_done_for_request( int i, j; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; - uint64_t buf_done_req_id; trace_cam_buf_done("ISP", ctx, req); @@ -758,10 +822,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request( CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", bubble_state, req_isp->bubble_detected); - if (done_next_req) { - done_next_req->num_handles = 0; - done_next_req->timestamp = done->timestamp; - } + done_next_req->num_handles = 0; + done_next_req->timestamp = done->timestamp; for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { @@ -771,28 +833,21 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } if (j == req_isp->num_fence_map_out) { - if (done_next_req) { - /* - * If not found in current request, it could be - * belonging to next request, This can happen if - * IRQ delay happens. - */ - CAM_WARN(CAM_ISP, - "BUF_DONE for res 0x%x not found in Req %lld ", - __cam_isp_resource_handle_id_to_type( - done->resource_handle[i]), - req->request_id); + /* + * If not found in current request, it could be + * belonging to next request, this can happen if + * IRQ delay happens. It is only valid when the + * platform doesn't have last consumed address. + */ + CAM_WARN(CAM_ISP, + "BUF_DONE for res %s not found in Req %lld ", + __cam_isp_resource_handle_id_to_type( + done->resource_handle[i]), + req->request_id); - done_next_req->resource_handle - [done_next_req->num_handles++] = - done->resource_handle[i]; - } else { - CAM_ERR(CAM_ISP, - "Can not find matching lane handle 0x%x! in Req %lld", - done->resource_handle[i], - req->request_id); - rc = -EINVAL; - } + done_next_req->resource_handle + [done_next_req->num_handles++] = + done->resource_handle[i]; continue; } @@ -807,12 +862,9 @@ static int __cam_isp_ctx_handle_buf_done_for_request( done->resource_handle[i]), req->request_id, ctx->ctx_id); - if (done_next_req) { - done_next_req->resource_handle - [done_next_req->num_handles++] = - done->resource_handle[i]; - } - + done_next_req->resource_handle + [done_next_req->num_handles++] = + done->resource_handle[i]; continue; } @@ -885,72 +937,151 @@ static int __cam_isp_ctx_handle_buf_done_for_request( if (req_isp->num_acked != req_isp->num_fence_map_out) return rc; - ctx_isp->active_req_cnt--; - buf_done_req_id = req->request_id; + rc = __cam_isp_ctx_handle_buf_done_for_req_list(ctx_isp, req); + return rc; +} - if (req_isp->bubble_detected && req_isp->bubble_report) { - req_isp->num_acked = 0; - req_isp->bubble_detected = false; - list_del_init(&req->list); - atomic_set(&ctx_isp->process_bubble, 0); - req_isp->cdm_reset_before_apply = false; - ctx_isp->bubble_frame_cnt = 0; +static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( + struct cam_isp_context *ctx_isp, + struct cam_ctx_request *req, + struct cam_isp_hw_done_event_data *done, + uint32_t bubble_state, + bool verify_consumed_addr) +{ + int rc = 0; + int i, j; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + const char *handle_type; - if (buf_done_req_id <= ctx->last_flush_req) { - for (i = 0; i < req_isp->num_fence_map_out; i++) - cam_sync_signal( - req_isp->fence_map_out[i].sync_id, - CAM_SYNC_STATE_SIGNALED_ERROR); + trace_cam_buf_done("ISP", ctx, req); - list_add_tail(&req->list, &ctx->free_req_list); - CAM_DBG(CAM_REQ, - "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", - buf_done_req_id, ctx_isp->active_req_cnt, + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", + bubble_state, req_isp->bubble_detected); + + for (i = 0; i < done->num_handles; i++) { + for (j = 0; j < req_isp->num_fence_map_out; j++) { + if (verify_consumed_addr && + (done->last_consumed_addr[i] != + req_isp->fence_map_out[j].image_buf_addr[0])) + continue; + + if (done->resource_handle[i] == + req_isp->fence_map_out[j].resource_handle) + break; + } + + if (j == req_isp->num_fence_map_out) { + /* + * If not found in current request, it could be + * belonging to next request, this can happen if + * IRQ delay happens. It is only valid when the + * platform doesn't have last consumed address. + */ + CAM_DBG(CAM_ISP, + "BUF_DONE for res %s not found in Req %lld ", + __cam_isp_resource_handle_id_to_type( + done->resource_handle[i]), + req->request_id); + continue; + } + + if (req_isp->fence_map_out[j].sync_id == -1) { + handle_type = + __cam_isp_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle); + + CAM_WARN(CAM_ISP, + "Duplicate BUF_DONE for req %lld : i=%d, j=%d, res=%s", + req->request_id, i, j, handle_type); + + trace_cam_log_event("Duplicate BufDone", + handle_type, req->request_id, ctx->ctx_id); + continue; + } + + if (!req_isp->bubble_detected) { + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, ctx->ctx_id); - } else { - list_add(&req->list, &ctx->pending_req_list); - ctx_isp->bubble_frame_cnt = 0; - CAM_DBG(CAM_REQ, - "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", - req->request_id, ctx_isp->active_req_cnt, + + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_SUCCESS); + if (rc) + CAM_DBG(CAM_ISP, "Sync failed with rc = %d", + rc); + } else if (!req_isp->bubble_report) { + CAM_ERR(CAM_ISP, + "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, ctx->ctx_id); + + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc) + CAM_ERR(CAM_ISP, "Sync failed with rc = %d", + rc); + } else { + /* + * Ignore the buffer done if bubble detect is on + * Increment the ack number here, and queue the + * request back to pending list whenever all the + * buffers are done. + */ + req_isp->num_acked++; + CAM_DBG(CAM_ISP, + "buf done with bubble state %d recovery %d", + bubble_state, req_isp->bubble_report); + continue; } - } else { - if (!ctx_isp->use_frame_header_ts) { - if (ctx_isp->reported_req_id < buf_done_req_id) { - ctx_isp->reported_req_id = buf_done_req_id; - __cam_isp_ctx_send_sof_timestamp(ctx_isp, - buf_done_req_id, - CAM_REQ_MGR_SOF_EVENT_SUCCESS); - } + CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u", + req->request_id, + req_isp->fence_map_out[j].sync_id, ctx->ctx_id); + if (!rc) { + req_isp->num_acked++; + req_isp->fence_map_out[j].sync_id = -1; } - list_del_init(&req->list); - list_add_tail(&req->list, &ctx->free_req_list); - req_isp->reapply = false; - req_isp->cdm_reset_before_apply = false; - CAM_DBG(CAM_REQ, - "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", - buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); - ctx_isp->req_info.last_bufdone_req_id = req->request_id; + if ((ctx_isp->use_frame_header_ts) && + (req_isp->hw_update_data.frame_header_res_id == + req_isp->fence_map_out[j].resource_handle)) + __cam_isp_ctx_send_sof_timestamp_frame_header( + ctx_isp, + req_isp->hw_update_data.frame_header_cpu_addr, + req->request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } - __cam_isp_ctx_update_state_monitor_array(ctx_isp, - CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); + if (req_isp->num_acked > req_isp->num_fence_map_out) { + /* Should not happen */ + CAM_ERR(CAM_ISP, + "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u", + req->request_id, req_isp->num_acked, + req_isp->num_fence_map_out, ctx->ctx_id); + WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); + } - __cam_isp_ctx_update_event_record(ctx_isp, - CAM_ISP_CTX_EVENT_BUFDONE, req); + if (req_isp->num_acked != req_isp->num_fence_map_out) + return rc; + + rc = __cam_isp_ctx_handle_buf_done_for_req_list(ctx_isp, req); return rc; } -static int __cam_isp_ctx_handle_buf_done_in_activated_state( +static int __cam_isp_ctx_handle_buf_done( struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state) { int rc = 0; - struct cam_ctx_request *req; + struct cam_ctx_request *req; struct cam_context *ctx = ctx_isp->base; struct cam_isp_hw_done_event_data done_next_req; @@ -1008,6 +1139,111 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( return rc; } +static void __cam_isp_ctx_buf_done_match_req( + struct cam_ctx_request *req, + struct cam_isp_hw_done_event_data *done, + bool *irq_delay_detected) +{ + int i, j; + uint32_t match_count = 0; + struct cam_isp_ctx_req *req_isp; + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + for (i = 0; i < done->num_handles; i++) { + for (j = 0; j < req_isp->num_fence_map_out; j++) { + if ((done->resource_handle[i] == + req_isp->fence_map_out[j].resource_handle) && + (done->last_consumed_addr[i] == + req_isp->fence_map_out[j].image_buf_addr[0])) { + match_count++; + break; + } + } + } + + if (match_count > 0) + *irq_delay_detected = true; + else + *irq_delay_detected = false; + + CAM_DBG(CAM_ISP, + "buf done num handles %d match count %d for next req:%lld", + done->num_handles, match_count, req->request_id); +} + +static int __cam_isp_ctx_handle_buf_done_verify_addr( + struct cam_isp_context *ctx_isp, + struct cam_isp_hw_done_event_data *done, + uint32_t bubble_state) +{ + int rc = 0; + bool irq_delay_detected = false; + struct cam_ctx_request *req; + struct cam_ctx_request *next_req = NULL; + struct cam_context *ctx = ctx_isp->base; + + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "Buf done with no active request"); + return 0; + } + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + + if (ctx_isp->active_req_cnt > 1) { + next_req = list_last_entry( + &ctx->active_req_list, + struct cam_ctx_request, list); + + if (next_req->request_id != req->request_id) + __cam_isp_ctx_buf_done_match_req(next_req, done, + &irq_delay_detected); + else + CAM_WARN(CAM_ISP, + "Req %lld only active request, spurious buf_done rxd", + req->request_id); + } + + /* + * If irq delay isn't detected, then we need to verify + * the consumed address for current req, otherwise, we + * can't verify the consumed address. + */ + rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( + ctx_isp, req, done, bubble_state, + !irq_delay_detected); + + /* + * Verify the consumed address for next req all the time, + * since the reported buf done event may belong to current + * req, then we can't signal this event for next req. + */ + if (!rc && irq_delay_detected) + rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( + ctx_isp, next_req, done, + bubble_state, true); + + return rc; +} + +static int __cam_isp_ctx_handle_buf_done_in_activated_state( + struct cam_isp_context *ctx_isp, + struct cam_isp_hw_done_event_data *done, + uint32_t bubble_state) +{ + int rc = 0; + + if (ctx_isp->support_consumed_addr) + rc = __cam_isp_ctx_handle_buf_done_verify_addr( + ctx_isp, done, bubble_state); + else + rc = __cam_isp_ctx_handle_buf_done( + ctx_isp, done, bubble_state); + + return rc; +} + static int __cam_isp_ctx_apply_req_offline( void *priv, void *data) { @@ -3773,6 +4009,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; + ctx_isp->support_consumed_addr = false; ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); @@ -4450,6 +4687,8 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, */ ctx_isp->custom_enabled = param.custom_enabled; ctx_isp->use_frame_header_ts = param.use_frame_header_ts; + ctx_isp->support_consumed_addr = + param.support_consumed_addr; /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index b85d6f809394..f3e2b3c25f9f 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_ISP_CONTEXT_H_ @@ -255,6 +256,7 @@ struct cam_isp_context_event_record { * @split_acquire: Indicate whether a separate acquire is expected * @custom_enabled: Custom HW enabled for this ctx * @use_frame_header_ts: Use frame header for qtimer ts + * @support_consumed_addr: Indicate whether HW has last consumed addr reg * @init_timestamp: Timestamp at which this context is initialized * @rxd_epoch: Indicate whether epoch has been received. Used to * decide whether to apply request in offline ctx @@ -299,6 +301,7 @@ struct cam_isp_context { bool split_acquire; bool custom_enabled; bool use_frame_header_ts; + bool support_consumed_addr; unsigned int init_timestamp; atomic_t rxd_epoch; struct cam_req_mgr_core_workq *workq; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index e57269bdefbc..21a9d8d2f75d 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2974,6 +2975,32 @@ static int cam_ife_mgr_acquire_get_unified_structure( return 0; } +static bool cam_ife_mgr_is_consumed_addr_supported( + struct cam_ife_hw_mgr_ctx *ctx) +{ + bool support_consumed_addr = false; + struct cam_ife_hw_mgr_res *isp_hw_res = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_hw_res = &ctx->res_list_ife_out[0]; + + if (!isp_hw_res || !isp_hw_res->hw_res[0]) { + CAM_ERR(CAM_ISP, "Invalid ife out res."); + goto end; + } + + hw_intf = isp_hw_res->hw_res[0]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT, + &support_consumed_addr, + sizeof(support_consumed_addr)); + } + +end: + return support_consumed_addr; +} + /* entry function: acquire_hw */ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { @@ -3110,6 +3137,9 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) goto free_res; } + acquire_args->support_consumed_addr = + cam_ife_mgr_is_consumed_addr_supported(ife_ctx); + acquire_args->ctxt_to_hw_map = ife_ctx; acquire_args->custom_enabled = ife_ctx->custom_enabled; acquire_args->use_frame_header_ts = ife_ctx->use_frame_header_ts; @@ -7447,7 +7477,7 @@ static int cam_ife_hw_mgr_handle_hw_epoch( CAM_ISP_HW_EVENT_EPOCH); if (!rc) { epoch_done_event_data.frame_id_meta = - event_info->th_reg_val; + event_info->reg_val; ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); } @@ -7622,6 +7652,8 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( buf_done_event_data.num_handles = 1; buf_done_event_data.resource_handle[0] = event_info->res_id; + buf_done_event_data.last_consumed_addr[0] = + event_info->reg_val; if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) return 0; @@ -7632,8 +7664,9 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( CAM_ISP_HW_EVENT_DONE, &buf_done_event_data); } - CAM_DBG(CAM_ISP, "Buf done for VFE:%d out_res->res_id: 0x%x", - event_info->hw_idx, event_info->res_id); + CAM_DBG(CAM_ISP, + "Buf done for VFE:%d res_id: 0x%x last consumed addr: 0x%x", + event_info->hw_idx, event_info->res_id, event_info->reg_val); return 0; } diff --git a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 4ae0d8b5e8f1..1d7e529f4448 100644 --- a/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_ISP_HW_MGR_INTF_H_ @@ -187,6 +188,7 @@ struct cam_isp_hw_epoch_event_data { * * @num_handles: Number of resource handeles * @resource_handle: Resource handle array + * @last_consumed_addr: Last consumed addr * @timestamp: Timestamp for the buf done event * */ @@ -194,6 +196,8 @@ struct cam_isp_hw_done_event_data { uint32_t num_handles; uint32_t resource_handle[ CAM_NUM_OUT_PER_COMP_IRQ_MAX]; + uint32_t last_consumed_addr[ + CAM_NUM_OUT_PER_COMP_IRQ_MAX]; uint64_t timestamp; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 4ca376f34f06..3323597f65ad 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_ISP_HW_H_ @@ -115,6 +116,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_CSID_CLOCK_DUMP, CAM_ISP_HW_CMD_SET_NUM_OF_ACQUIRED_RESOURCE, CAM_ISP_HW_CMD_GET_NUM_OF_ACQUIRED_RESOURCE, + CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT, CAM_ISP_HW_CMD_MAX, }; @@ -189,7 +191,7 @@ struct cam_isp_resource_node { * @res_id: Unique resource ID * @hw_idx: IFE hw index * @err_type: Error type if any - * @th_reg_val: Any critical register value captured during th + * @reg_val: Any critical register value captured during irq handling * */ struct cam_isp_hw_event_info { @@ -197,7 +199,7 @@ struct cam_isp_hw_event_info { uint32_t res_id; uint32_t hw_idx; uint32_t err_type; - uint32_t th_reg_val; + uint32_t reg_val; }; /* @@ -219,7 +221,7 @@ struct cam_isp_hw_cmd_buf_update { /* * struct cam_isp_hw_get_wm_update: * - * @Brief: Get cmd buffer for WM updates. + * @Brief: Get cmd buffer for WM updates. * * @ image_buf: image buffer address array * @ image_buf_offset: image buffer address offset array diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index e9fb2618b6bd..dbf61f5d6f55 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE_HW_INTF_H_ @@ -303,15 +304,15 @@ struct cam_vfe_bw_control_args { * @list: list_head node for the payload * @irq_reg_val: IRQ and Error register values, read when IRQ was * handled - * @th_reg_val: Value of any critical register that needs to be - * read at th to avoid any latencies in bh processing + * @reg_val: Value of any critical register that needs to be + * read at during irq handling * * @ts: Timestamp */ struct cam_vfe_top_irq_evt_payload { struct list_head list; uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; - uint32_t th_reg_val; + uint32_t reg_val; struct cam_isp_timestamp ts; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index ad726b86da73..dc5c6229ae0d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -623,6 +624,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: case CAM_ISP_HW_CMD_DUMP_BUS_INFO: + case CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 8aa1a471a197..58c3a0c3c7be 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE170_H_ @@ -860,6 +861,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .max_height = -1, }, }, + .support_consumed_addr = false, }; struct cam_vfe_hw_info cam_vfe170_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h index 35f7da004105..c40650fe58fa 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170_150.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE170_150_H_ @@ -1043,6 +1044,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_150_bus_hw_info = { .max_height = -1, }, }, + .support_consumed_addr = false, }; struct cam_vfe_hw_info cam_vfe170_150_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index 7e7b9c3ffac3..4d9bcf24a5f3 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE175_H_ @@ -1023,6 +1024,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { .max_height = 1080, }, }, + .support_consumed_addr = false, }; struct cam_vfe_hw_info cam_vfe175_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index c2ce8645de26..0277b9464ca0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE175_130_H_ @@ -1316,6 +1317,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { }, }, .stats_data = &stats_175_130_info, + .support_consumed_addr = false, }; struct cam_vfe_hw_info cam_vfe175_130_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h index f592364fb42e..5b676ae8cf2a 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -1323,6 +1324,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe480_bus_hw_info = { }, .comp_done_shift = 6, .top_irq_shift = 7, + .support_consumed_addr = true, }; static struct cam_irq_register_set vfe480_bus_rd_irq_reg[1] = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h index 7ea461b21dbd..ce7a4fb6711e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE_LITE17X_H_ @@ -331,6 +332,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe17x_bus_hw_info = { .max_height = -1, }, }, + .support_consumed_addr = false, }; static struct cam_vfe_hw_info cam_vfe_lite17x_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h index c19ade50bec9..9601eb6ee1a5 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_VFE_LITE48x_H_ @@ -394,6 +394,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe48x_bus_hw_info = { }, .comp_done_shift = 4, .top_irq_shift = 4, + .support_consumed_addr = true, }; static struct cam_vfe_hw_info cam_vfe_lite48x_hw_info = { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 0207847f7021..f16b147d2039 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -104,6 +105,7 @@ struct cam_vfe_bus_ver2_common_data { bool hw_init; struct cam_vfe_bus_ver2_stats_cfg_info *stats_data; bool disable_ubwc_comp; + bool support_consumed_addr; }; struct cam_vfe_bus_ver2_wm_resource_data { @@ -3842,6 +3844,7 @@ static int cam_vfe_bus_process_cmd( { int rc = -EINVAL; struct cam_vfe_bus_ver2_priv *bus_priv; + bool *support_consumed_addr; if (!priv || !cmd_args) { CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); @@ -3880,6 +3883,12 @@ static int cam_vfe_bus_process_cmd( case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: rc = cam_vfe_bus_update_ubwc_config_v2(cmd_args); break; + case CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT: + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + support_consumed_addr = (bool *)cmd_args; + *support_consumed_addr = + bus_priv->common_data.support_consumed_addr; + break; default: CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", cmd_type); @@ -3942,6 +3951,8 @@ int cam_vfe_bus_ver2_init( CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL; bus_priv->common_data.hw_init = false; bus_priv->common_data.stats_data = ver2_hw_info->stats_data; + bus_priv->common_data.support_consumed_addr = + ver2_hw_info->support_consumed_addr; mutex_init(&bus_priv->common_data.bus_mutex); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index 7ab273a9ceb1..6f27a40908d0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE_BUS_VER2_H_ @@ -222,6 +223,7 @@ struct cam_vfe_bus_ver2_reg_data { * @bus_client_reg: Bus client register info * @comp_reg_grp: Composite group register info * @vfe_out_hw_info: VFE output capability + * @support_consumed_addr: Indicate if bus support consumed address */ struct cam_vfe_bus_ver2_hw_info { struct cam_vfe_bus_ver2_reg_offset_common common_reg; @@ -235,6 +237,7 @@ struct cam_vfe_bus_ver2_hw_info { vfe_out_hw_info[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; struct cam_vfe_bus_ver2_reg_data reg_data; struct cam_vfe_bus_ver2_stats_cfg_info *stats_data; + bool support_consumed_addr; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 6db7717d561c..6fe77637e037 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -86,6 +87,7 @@ struct cam_vfe_bus_ver3_common_data { bool is_lite; bool hw_init; bool disable_ubwc_comp; + bool support_consumed_addr; cam_hw_mgr_event_cb_func event_cb; int rup_irq_handle[CAM_VFE_BUS_VER3_SRC_GRP_MAX]; }; @@ -153,6 +155,7 @@ struct cam_vfe_bus_ver3_vfe_out_data { uint32_t out_type; uint32_t source_group; struct cam_vfe_bus_ver3_common_data *common_data; + struct cam_vfe_bus_ver3_priv *bus_priv; uint32_t num_wm; struct cam_isp_resource_node *wm_res[PLANE_MAX]; @@ -1948,6 +1951,7 @@ static int cam_vfe_bus_ver3_acquire_vfe_out(void *bus_priv, void *acquire_args, rsrc_data->common_data->disable_ubwc_comp = out_acquire_args->disable_ubwc_comp; rsrc_data->priv = acq_args->priv; + rsrc_data->bus_priv = ver3_bus_priv; secure_caps = cam_vfe_bus_ver3_can_be_secure( rsrc_data->out_type); @@ -2314,6 +2318,34 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, return rc; } +static uint32_t cam_vfe_bus_ver3_get_last_consumed_addr( + struct cam_vfe_bus_ver3_priv *bus_priv, + uint32_t res_type) +{ + uint32_t val = 0; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_rsrc_data = NULL; + enum cam_vfe_bus_ver3_vfe_out_type res_id; + + res_id = cam_vfe_bus_ver3_get_out_res_id(res_type); + + if (res_id >= CAM_VFE_BUS_VER3_VFE_OUT_MAX) { + CAM_ERR(CAM_ISP, "invalid res id:%u", res_id); + return 0; + } + + rsrc_node = &bus_priv->vfe_out[res_id]; + rsrc_data = rsrc_node->res_priv; + wm_rsrc_data = rsrc_data->wm_res[PLANE_Y]->res_priv; + + val = cam_io_r_mb( + wm_rsrc_data->common_data->mem_base + + wm_rsrc_data->hw_regs->addr_status_0); + + return val; +} + static int cam_vfe_bus_ver3_handle_vfe_out_done_bottom_half( void *handler_priv, void *evt_payload_priv) @@ -2348,6 +2380,10 @@ static int cam_vfe_bus_ver3_handle_vfe_out_done_bottom_half( rsrc_data->common_data->is_lite); for (i = 0; i < num_out; i++) { evt_info.res_id = out_list[i]; + evt_info.reg_val = + cam_vfe_bus_ver3_get_last_consumed_addr( + rsrc_data->bus_priv, + evt_info.res_id); if (rsrc_data->common_data->event_cb) rsrc_data->common_data->event_cb(ctx, evt_id, (void *)&evt_info); @@ -3720,6 +3756,7 @@ static int cam_vfe_bus_ver3_process_cmd( { int rc = -EINVAL; struct cam_vfe_bus_ver3_priv *bus_priv; + bool *support_consumed_addr; if (!priv || !cmd_args) { CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); @@ -3769,6 +3806,12 @@ static int cam_vfe_bus_ver3_process_cmd( case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: rc = cam_vfe_bus_ver3_update_wm_config(cmd_args); break; + case CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT: + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + support_consumed_addr = (bool *)cmd_args; + *support_consumed_addr = + bus_priv->common_data.support_consumed_addr; + break; default: CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", cmd_type); @@ -3841,6 +3884,8 @@ int cam_vfe_bus_ver3_init( bus_priv->common_data.hw_init = false; bus_priv->common_data.is_lite = soc_private->is_ife_lite; + bus_priv->common_data.support_consumed_addr = + ver3_hw_info->support_consumed_addr; for (i = 0; i < CAM_VFE_BUS_VER3_SRC_GRP_MAX; i++) bus_priv->common_data.rup_irq_handle[i] = 0; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h index 1e2d7e093682..fea8a2cc7827 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -167,12 +168,13 @@ struct cam_vfe_bus_ver3_vfe_out_hw_info { * * @Brief: HW register info for entire Bus * - * @common_reg: Common register details - * @num_client: Total number of write clients - * @bus_client_reg: Bus client register info - * @vfe_out_hw_info: VFE output capability - * @comp_done_shift: Mask shift for comp done mask - * @top_irq_shift: Mask shift for top level BUS WR irq + * @common_reg: Common register details + * @num_client: Total number of write clients + * @bus_client_reg: Bus client register info + * @vfe_out_hw_info: VFE output capability + * @comp_done_shift: Mask shift for comp done mask + * @top_irq_shift: Mask shift for top level BUS WR irq + * @support_consumed_addr: Indicate if bus support consumed address */ struct cam_vfe_bus_ver3_hw_info { struct cam_vfe_bus_ver3_reg_offset_common common_reg; @@ -184,6 +186,7 @@ struct cam_vfe_bus_ver3_hw_info { vfe_out_hw_info[CAM_VFE_BUS_VER3_VFE_OUT_MAX]; uint32_t comp_done_shift; uint32_t top_irq_shift; + bool support_consumed_addr; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c index 6a827829a091..5523177a6999 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1290,7 +1291,7 @@ static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, } cam_isp_hw_get_timestamp(&evt_payload->ts); - evt_payload->th_reg_val = 0; + evt_payload->reg_val = 0; for (i = 0; i < th_payload->num_registers; i++) evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; @@ -1300,7 +1301,7 @@ static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, & camif_priv->reg_data->epoch0_irq_mask) { if ((camif_priv->common_reg->custom_frame_idx) && (camif_priv->cam_common_cfg.input_mux_sel_pp & 0x3)) - evt_payload->th_reg_val = cam_io_r_mb( + evt_payload->reg_val = cam_io_r_mb( camif_priv->mem_base + camif_priv->common_reg->custom_frame_idx); } @@ -1368,7 +1369,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, evt_info.hw_idx = camif_node->hw_intf->hw_idx; evt_info.res_id = camif_node->res_id; evt_info.res_type = camif_node->res_type; - evt_info.th_reg_val = 0; + evt_info.reg_val = 0; if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->sof_irq_mask) { @@ -1404,7 +1405,7 @@ static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] & camif_priv->reg_data->epoch0_irq_mask) { CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); - evt_info.th_reg_val = payload->th_reg_val; + evt_info.reg_val = payload->reg_val; camif_priv->epoch_ts.tv_sec = payload->ts.mono_time.tv_sec; camif_priv->epoch_ts.tv_usec = -- GitLab From 610dcae87f732835258c45d64d33fb661933be74 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Fri, 7 Aug 2020 14:54:24 +0800 Subject: [PATCH 366/410] msm: camera: ife: Get consumed address info during hw_mgr init This change checks whether the context supports last consumed address during hw_mgr init. CRs-Fixed: 2749254 Change-Id: I238893eb2d661014a2a51758bcf71c3e4d00f2d5 Signed-off-by: Depeng Shao --- drivers/cam_isp/cam_isp_context.c | 2 + drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 41 +++++++-------------- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 2 + 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index bfa19dcfd7e2..d890af0ba824 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1170,6 +1170,8 @@ static void __cam_isp_ctx_buf_done_match_req( CAM_DBG(CAM_ISP, "buf done num handles %d match count %d for next req:%lld", done->num_handles, match_count, req->request_id); + CAM_DBG(CAM_ISP, + "irq_delay_detected %d", *irq_delay_detected); } static int __cam_isp_ctx_handle_buf_done_verify_addr( diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 21a9d8d2f75d..74e6149c2074 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2975,32 +2975,6 @@ static int cam_ife_mgr_acquire_get_unified_structure( return 0; } -static bool cam_ife_mgr_is_consumed_addr_supported( - struct cam_ife_hw_mgr_ctx *ctx) -{ - bool support_consumed_addr = false; - struct cam_ife_hw_mgr_res *isp_hw_res = NULL; - struct cam_hw_intf *hw_intf = NULL; - - isp_hw_res = &ctx->res_list_ife_out[0]; - - if (!isp_hw_res || !isp_hw_res->hw_res[0]) { - CAM_ERR(CAM_ISP, "Invalid ife out res."); - goto end; - } - - hw_intf = isp_hw_res->hw_res[0]->hw_intf; - if (hw_intf && hw_intf->hw_ops.process_cmd) { - hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, - CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT, - &support_consumed_addr, - sizeof(support_consumed_addr)); - } - -end: - return support_consumed_addr; -} - /* entry function: acquire_hw */ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { @@ -3138,7 +3112,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) } acquire_args->support_consumed_addr = - cam_ife_mgr_is_consumed_addr_supported(ife_ctx); + g_ife_hw_mgr.support_consumed_addr; acquire_args->ctxt_to_hw_map = ife_ctx; acquire_args->custom_enabled = ife_ctx->custom_enabled; @@ -7878,6 +7852,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) { int rc = -EFAULT; int i, j; + bool support_consumed_addr = false; struct cam_iommu_handle cdm_handles; struct cam_ife_hw_mgr_ctx *ctx_pool; struct cam_ife_hw_mgr_res *res_list_ife_out; @@ -7898,11 +7873,19 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) { rc = cam_vfe_hw_init(&g_ife_hw_mgr.ife_devices[i], i); if (!rc) { + struct cam_hw_intf *ife_device = + g_ife_hw_mgr.ife_devices[i]; struct cam_hw_info *vfe_hw = (struct cam_hw_info *) - g_ife_hw_mgr.ife_devices[i]->hw_priv; + ife_device->hw_priv; struct cam_hw_soc_info *soc_info = &vfe_hw->soc_info; + if (j == 0) + ife_device->hw_ops.process_cmd( + vfe_hw, + CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT, + &support_consumed_addr, + sizeof(support_consumed_addr)); j++; g_ife_hw_mgr.cdm_reg_map[i] = &soc_info->reg_map[0]; @@ -7919,6 +7902,8 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) return -EINVAL; } + g_ife_hw_mgr.support_consumed_addr = support_consumed_addr; + /* fill csid hw intf information */ for (i = 0, j = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { rc = cam_ife_csid_hw_init(&g_ife_hw_mgr.csid_devices[i], i); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 0875be666893..7786027a0fae 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -222,6 +222,7 @@ struct cam_ife_hw_mgr_ctx { * @ife_dev_caps ife device capability per core * @work q work queue for IFE hw manager * @debug_cfg debug configuration + * @support_consumed_addr indicate whether hw supports last consumed address */ struct cam_ife_hw_mgr { struct cam_isp_hw_mgr mgr_common; @@ -241,6 +242,7 @@ struct cam_ife_hw_mgr { struct cam_req_mgr_core_workq *workq; struct cam_ife_hw_mgr_debug debug_cfg; spinlock_t ctx_lock; + bool support_consumed_addr; }; /** -- GitLab From 5abe1e4ab3f72948c0cdd3b26005242c016f9a62 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Thu, 3 Feb 2022 12:09:19 +0530 Subject: [PATCH 367/410] msm: camera: reqmgr: Avoid freeing subdev twice The 'l_device' pointer in __cam_req_mgr_destroy_subdev is set to NULL after freeing but this is done on a local copy of the variable in stack. This results in double-free when this function is called again. To avoid this, pass 'l_device' pointer by reference and assign it to NULL after freeing. CRs-Fixed: 3120468 Change-Id: If2dde6f1c702bee26a3c8a68c2f45bafbf0f7cd6 Signed-off-by: Nirmal Abraham Signed-off-by: Sridhar Gujje --- drivers/cam_req_mgr/cam_req_mgr_core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index ffd5381ac706..7f893cc6086f 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1886,10 +1887,13 @@ static int __cam_req_mgr_create_subdevs( * */ static void __cam_req_mgr_destroy_subdev( - struct cam_req_mgr_connected_device *l_device) + struct cam_req_mgr_connected_device **l_device) { - kfree(l_device); - l_device = NULL; + CAM_DBG(CAM_CRM, "*l_device %pK", *l_device); + if (*(l_device) != NULL) { + kfree(*(l_device)); + *l_device = NULL; + } } /** @@ -3340,7 +3344,7 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) __cam_req_mgr_destroy_link_info(link); /* Free memory holding data of linked devs */ - __cam_req_mgr_destroy_subdev(link->l_dev); + __cam_req_mgr_destroy_subdev(&link->l_dev); /* Destroy the link handle */ rc = cam_destroy_device_hdl(link->link_hdl); @@ -3511,7 +3515,7 @@ int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) mutex_unlock(&g_crm_core_dev->crm_lock); return rc; setup_failed: - __cam_req_mgr_destroy_subdev(link->l_dev); + __cam_req_mgr_destroy_subdev(&link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); link_info->u.link_info_v1.link_hdl = -1; @@ -3621,7 +3625,7 @@ int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) mutex_unlock(&g_crm_core_dev->crm_lock); return rc; setup_failed: - __cam_req_mgr_destroy_subdev(link->l_dev); + __cam_req_mgr_destroy_subdev(&link->l_dev); create_subdev_failed: cam_destroy_device_hdl(link->link_hdl); link_info->u.link_info_v2.link_hdl = -1; -- GitLab From 7811469f79ccc3124ef9eaf79d1edeb32c6a87ec Mon Sep 17 00:00:00 2001 From: Yash Upadhyay Date: Mon, 21 Feb 2022 10:07:23 +0530 Subject: [PATCH 368/410] msm: camera: reqmgr: Validate the link handle Instead of correct link handle, if some other handle like dev handle is passed then it may access some other data space. To avoid such scenario, need to check whether link handle passed by ioctl is same as retrieved link handle. CRs-Fixed: 3120454 Change-Id: Idff2e3c25b60563788ffb426c7cabc367c3c97f8 Signed-off-by: Yash Upadhyay --- drivers/cam_req_mgr/cam_req_mgr_core.c | 105 ++++++++++++++++++------- drivers/cam_req_mgr/cam_req_mgr_core.h | 2 + drivers/cam_utils/cam_debug_util.h | 4 + 3 files changed, 81 insertions(+), 30 deletions(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index ffd5381ac706..ccef815a4fa4 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -3371,8 +3371,12 @@ int cam_req_mgr_destroy_session( mutex_lock(&g_crm_core_dev->crm_lock); cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(ses_info->session_hdl); - if (!cam_session) { - CAM_ERR(CAM_CRM, "failed to get session priv"); + if (!cam_session || + (cam_session->session_hdl != ses_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s ses_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), ses_info->session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); rc = -ENOENT; goto end; @@ -3437,8 +3441,13 @@ int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(link_info->u.link_info_v1.session_hdl); - if (!cam_session) { - CAM_DBG(CAM_CRM, "NULL pointer"); + if (!cam_session || (cam_session->session_hdl != + link_info->u.link_info_v1.session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s link_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), + link_info->u.link_info_v1.session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } @@ -3547,8 +3556,13 @@ int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(link_info->u.link_info_v2.session_hdl); - if (!cam_session) { - CAM_DBG(CAM_CRM, "NULL pointer"); + if (!cam_session || (cam_session->session_hdl != + link_info->u.link_info_v2.session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s link_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), + link_info->u.link_info_v2.session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } @@ -3650,16 +3664,23 @@ int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(unlink_info->session_hdl); - if (!cam_session) { - CAM_ERR(CAM_CRM, "NULL pointer"); + if (!cam_session || + (cam_session->session_hdl != unlink_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s unlink->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), + unlink_info->session_hdl, + (!cam_session) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : + cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } /* link hdl's priv data is core_link struct */ link = cam_get_device_priv(unlink_info->link_hdl); - if (!link) { - CAM_ERR(CAM_CRM, "NULL pointer"); + if (!link || (link->link_hdl != unlink_info->link_hdl)) { + CAM_ERR(CAM_CRM, "link:%s unlink->lnk_hdl:%x link->lnk_hdl:%x", + CAM_IS_NULL_TO_STR(link), unlink_info->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto done; } @@ -3691,8 +3712,10 @@ int cam_req_mgr_schedule_request( mutex_lock(&g_crm_core_dev->crm_lock); link = (struct cam_req_mgr_core_link *) cam_get_device_priv(sched_req->link_hdl); - if (!link) { - CAM_DBG(CAM_CRM, "link ptr NULL %x", sched_req->link_hdl); + if (!link || (link->link_hdl != sched_req->link_hdl)) { + CAM_ERR(CAM_CRM, "lnk:%s schd_req->lnk_hdl:%x lnk->lnk_hdl:%x", + CAM_IS_NULL_TO_STR(link), sched_req->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto end; } @@ -3803,8 +3826,12 @@ int cam_req_mgr_sync_config( /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(sync_info->session_hdl); - if (!cam_session) { - CAM_ERR(CAM_CRM, "NULL pointer"); + if (!cam_session || + (cam_session->session_hdl != sync_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses:%s sync_info->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(cam_session), sync_info->session_hdl, + (!cam_session) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : cam_session->session_hdl); mutex_unlock(&g_crm_core_dev->crm_lock); return -EINVAL; } @@ -3816,15 +3843,21 @@ int cam_req_mgr_sync_config( /* only two links existing per session in dual cam use case*/ link1 = cam_get_device_priv(sync_info->link_hdls[0]); - if (!link1) { - CAM_ERR(CAM_CRM, "link1 NULL pointer"); + if (!link1 || (link1->link_hdl != sync_info->link_hdls[0])) { + CAM_ERR(CAM_CRM, "lnk:%s sync_info->lnk_hdl[0]:%x lnk1_hdl:%x", + CAM_IS_NULL_TO_STR(link1), sync_info->link_hdls[0], + (!link1) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : link1->link_hdl); rc = -EINVAL; goto done; } link2 = cam_get_device_priv(sync_info->link_hdls[1]); - if (!link2) { - CAM_ERR(CAM_CRM, "link2 NULL pointer"); + if (!link2 || (link2->link_hdl != sync_info->link_hdls[1])) { + CAM_ERR(CAM_CRM, "lnk:%s sync_info->lnk_hdl[1]:%x lnk2_hdl:%x", + CAM_IS_NULL_TO_STR(link2), sync_info->link_hdls[1], + (!link2) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : link2->link_hdl); rc = -EINVAL; goto done; } @@ -3894,8 +3927,11 @@ int cam_req_mgr_flush_requests( /* session hdl's priv data is cam session struct */ session = (struct cam_req_mgr_core_session *) cam_get_device_priv(flush_info->session_hdl); - if (!session) { - CAM_ERR(CAM_CRM, "Invalid session %x", flush_info->session_hdl); + if (!session || (session->session_hdl != flush_info->session_hdl)) { + CAM_ERR(CAM_CRM, "ses: %s flush->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(session), flush_info->session_hdl, + (!session) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : session->session_hdl); rc = -EINVAL; goto end; } @@ -3907,8 +3943,10 @@ int cam_req_mgr_flush_requests( link = (struct cam_req_mgr_core_link *) cam_get_device_priv(flush_info->link_hdl); - if (!link) { - CAM_DBG(CAM_CRM, "link ptr NULL %x", flush_info->link_hdl); + if (!link || (link->link_hdl != flush_info->link_hdl)) { + CAM_ERR(CAM_CRM, "link:%s flush->link_hdl:%x link->link_hdl:%x", + CAM_IS_NULL_TO_STR(link), flush_info->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto end; } @@ -3966,9 +4004,12 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) for (i = 0; i < control->num_links; i++) { link = (struct cam_req_mgr_core_link *) cam_get_device_priv(control->link_hdls[i]); - if (!link) { - CAM_ERR(CAM_CRM, "Link(%d) is NULL on session 0x%x", - i, control->session_hdl); + if (!link || (link->link_hdl != control->link_hdls[i])) { + CAM_ERR(CAM_CRM, + "link:%s control->lnk_hdl:%x link->lnk_hdl:%x", + CAM_IS_NULL_TO_STR(link), control->link_hdls[i], + (!link) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; break; } @@ -4047,9 +4088,11 @@ int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) /* session hdl's priv data is cam session struct */ session = (struct cam_req_mgr_core_session *) cam_get_device_priv(dump_req->session_handle); - if (!session) { - CAM_ERR(CAM_CRM, "Invalid session %x", - dump_req->session_handle); + if (!session || (session->session_hdl != dump_req->session_handle)) { + CAM_ERR(CAM_CRM, "ses:%s dump_req->ses_hdl:%x ses->ses_hdl:%x", + CAM_IS_NULL_TO_STR(session), dump_req->session_handle, + (!session) ? + CAM_REQ_MGR_DEFAULT_HDL_VAL : session->session_hdl); rc = -EINVAL; goto end; } @@ -4061,8 +4104,10 @@ int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req) link = (struct cam_req_mgr_core_link *) cam_get_device_priv(dump_req->link_hdl); - if (!link || link->link_hdl != dump_req->link_hdl) { - CAM_DBG(CAM_CRM, "link ptr NULL %x", dump_req->link_hdl); + if (!link || (link->link_hdl != dump_req->link_hdl)) { + CAM_ERR(CAM_CRM, "link:%s dump->link_hdl:%x link->link_hdl:%x", + CAM_IS_NULL_TO_STR(link), dump_req->link_hdl, + (!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl); rc = -EINVAL; goto end; } diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.h b/drivers/cam_req_mgr/cam_req_mgr_core.h index 106af51f9c1e..1be2f4cd1a38 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_REQ_MGR_CORE_H_ #define _CAM_REQ_MGR_CORE_H_ @@ -17,6 +18,7 @@ #define CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX 50000 #define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 #define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 +#define CAM_REQ_MGR_DEFAULT_HDL_VAL 0 #define FORCE_DISABLE_RECOVERY 2 #define FORCE_ENABLE_RECOVERY 1 diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 181a1558a904..b21312f61bea 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -1,11 +1,15 @@ /* 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. */ #ifndef _CAM_DEBUG_UTIL_H_ #define _CAM_DEBUG_UTIL_H_ +#define CAM_IS_NULL_TO_STR(ptr) ((ptr) ? "Non-NULL" : "NULL") + +/* Module IDs used for debug logging */ #define CAM_CDM (1 << 0) #define CAM_CORE (1 << 1) #define CAM_CPAS (1 << 2) -- GitLab From fbd6c0e5184bc065b88d363680a0e4762575fffb Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 29 Mar 2022 15:13:17 +0530 Subject: [PATCH 369/410] msm: camera: memmgr: Update copyright fix CRs-Fixed: 3161837 Change-Id: Ibf7a6fc9f3ed7b75cad90d88444078621944fbad Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_mem_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 359004f68900..b62679206242 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, 2022 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include -- GitLab From 456c872716498f26f8429c8bc21a3e1585c0adea Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Tue, 29 Mar 2022 15:13:17 +0530 Subject: [PATCH 370/410] msm: camera: memmgr: Update copyright fix CRs-Fixed: 3161837 Change-Id: Ibf7a6fc9f3ed7b75cad90d88444078621944fbad Signed-off-by: Tejas Prajapati --- drivers/cam_req_mgr/cam_mem_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 359004f68900..b62679206242 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, 2022 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include -- GitLab From 030ab03dd0c6062ff7b69504377b233c34dfa333 Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Tue, 29 Mar 2022 10:54:51 +0530 Subject: [PATCH 371/410] msm: camera: eeprom: Add OOB read check for eeprom memory map Add check to prevent OOB read of eeprom memory map. Change-Id: Ifeeeffdc2a50536edbde5b5d755a052ace86d596 CRs-Fixed: 3003049 Signed-off-by: Shravan Nevatia --- drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 2d4f986dbf47..41f3a9538c08 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -991,7 +992,16 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, rc = -EINVAL; goto end; } + + if ((num_map + 1) >= + (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { + CAM_ERR(CAM_EEPROM, "OOB error"); + rc = -EINVAL; + goto end; + } /* Configure the following map slave address */ + map[num_map + 1].saddr = i2c_info->slave_addr; rc = cam_eeprom_update_slaveInfo(e_ctrl, cmd_buf); -- GitLab From 68f25e9e4883b14458245a70172dacda88b3980d Mon Sep 17 00:00:00 2001 From: "yixiang.wu" Date: Tue, 5 Jan 2021 18:05:58 +0800 Subject: [PATCH 372/410] [1 of 1][10277816]add scanner driver releated code ###%%%comment:[1 of 1]add scanner driver releated code ###%%%bug number:10277816 ###%%%product name:n10 ###%%%root cause:Specification ###%%%Bug category:T2M ###%%%regression response:--- ###%%%regression comments: ###%%%Module_Impact:scanner ###%%%Test_Suggestion:you can check scanner function ###%%%Solution:add scanner driver releated code ###%%%Test_Report:you can check scanner function ###%%%VAL Can Test:Yes Change-Id: Idff9ce67f86e14b287375af9aa437aaede40eb52 --- .../cam_sensor/cam_sensor_core.c | 578 +++++++++++++++++- .../cam_sensor_utils/cam_sensor_cmn_header.h | 1 + .../cam_sensor_utils/cam_sensor_util.c | 26 + 3 files changed, 596 insertions(+), 9 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index a6cbd20d62af..6ee5ce29b0f7 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -4,6 +4,10 @@ */ #include +/* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ +#include +#include +/* MODIFIED-END by yixiang.wu,BUG-10277816*/ #include #include "cam_sensor_core.h" #include "cam_sensor_util.h" @@ -740,6 +744,475 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->sensor_state = CAM_SENSOR_INIT; } +/* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ +//s_ctrl->io_master_info.client yanhao + + +static int32_t se4750_mipi_i2c_rxdata(struct i2c_client *client, + unsigned char *rxdata, int data_length) +{ + int32_t rc = 0; + uint16_t saddr = client->addr; + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = I2C_M_RD, + .len = data_length, + .buf = rxdata, + }, + }; + rc = i2c_transfer(client->adapter, msgs, 1); + if (rc < 0) + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata failed 0x%x", saddr); + return rc; +} + +static int32_t se4750_mipi_i2c_txdata(struct i2c_client *client, + unsigned char *txdata, int length) +{ + int32_t rc = 0; + uint16_t saddr = client->addr; + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + rc = i2c_transfer(client->adapter, msg, 1); + if (rc < 0) + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata faild 0x%x rc=%d", saddr,rc); + return rc; +} + + + + +int streamOn_cmds(struct i2c_client *client){ + int rc = 0; + int i = 0; + int retry = 30; + unsigned char streamOn_enableHW[3]={0x84,0x01,0x7b}; + unsigned char streamOn_enableMIPI[3]={0x86,0x03,0x77}; + unsigned char streamOn_enableAimOn[3]={0x55,0x01,0xaa}; + unsigned char streamOn_enableIllumOn[3]={0x59,0x01,0xa6}; + unsigned char streamOn_enableAcqOn[3]={0x58,0x01,0xa7}; + unsigned char respbuf[2] = {0}; + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOn_enableHW,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableHW failed rc=%d retry=%d", rc, i); + } + } + + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableHW failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableHW[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableHW success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOn_enableMIPI,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableMIPI failed rc=%d retry=%d", rc, i); + } + } + + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableMIPI failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableMIPI[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableMIPI success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOn_enableAimOn,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAimOn failed rc=%d retry=%d", rc, i); + } + } + + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAimOn failed rc=%d",rc); + goto ERR_EXIT; + } + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableAimOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAimOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOn_enableIllumOn,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableIllumOn failed rc=%d retry=%d", rc, i); + } + } + + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableIllumOn failed rc=%d",rc); + goto ERR_EXIT; + } + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableIllumOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableIllumOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOn_enableAcqOn,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAcqOn failed rc=%d retry=%d", rc, i); + } + } + + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAcqOn failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableAcqOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAcqOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +ERR_EXIT: + return rc; +} + + +int streamOff_cmds(struct i2c_client *client){ + int rc = 0; + int i = 0; + int retry = 30; +// unsigned char streamOff_AimOff[3]={0x55,0x00,0xab}; +// unsigned char streamOff_IllumOff[3]={0x59,0x00,0xa7}; + unsigned char streamOff_AcqOff[3]={0x58,0x00,0xa8}; + unsigned char respbuf[2] = {0}; +#if 0 + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOff_AimOff,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AimOff failed rc=%d retry=%d", rc, i); + } + } + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AimOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_AimOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AimOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + for(i=0; i < retry ; i++){ + rc = rc = se4750_mipi_i2c_txdata(client,streamOff_IllumOff,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_IllumOff failed rc=%d retry=%d", rc, i); + } + } + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_IllumOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_IllumOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_IllumOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +#endif + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOff_AcqOff,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d retry=%d", rc, i); + } + } + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_AcqOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AcqOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +ERR_EXIT: + return rc; +} + + +#define SE4750_MIPI_MISC_NAME "sdl_control" +#define SE4750_I2C_ADDR 0x5C +bool is_zebra_misc_device_exist = false; +static int is_opened_by_SDL = 0; // A flag to indicate if scan engine is opened by SDL. +static struct cam_sensor_ctrl_t *g_s_ctrl; +struct file_operations se4750_mipi_misc_fops; +//#define MIMIC_ENGINE_RESPONSE 1 +#ifdef MIMIC_ENGINE_RESPONSE +static int mimic_cmd_response = 0; +static int last_cmd_op_code = 0; +#endif + +static struct miscdevice se4750_mipi_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name =SE4750_MIPI_MISC_NAME, + .fops = &se4750_mipi_misc_fops, +}; + +/* -------------------------------------------------------------------------- + * 'misc' device file operations + */ + +static int se4750_mipi_misc_open(struct inode* pINode, struct file* pFile) +{ + int rc = 0; + if (g_s_ctrl) + { + rc = cam_sensor_power_up(g_s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + //goto free_power_settings; + } + } + is_opened_by_SDL = 1; + pr_err("SDL open %s:%d is_opened_by_SDL=%d\n",__func__,__LINE__, is_opened_by_SDL); + return 0; +} + + +static long se4750_mipi_misc_ioctl(struct file* pFile, unsigned int uiCmd, unsigned long ulArg) +{ + struct i2c_client* pClient; + struct i2c_rdwr_ioctl_data I2CData; + struct i2c_msg I2CMsg; + u8 __user* pData; + long lRetVal; + + //pr_err("yanhao open %s:%d \n",__func__,__LINE__); + + if ((uiCmd != I2C_RDWR) || !ulArg ) + { + return(-EINVAL); + } + pClient =dev_get_drvdata(se4750_mipi_misc_device.this_device); + //pr_err("yanhao open %s:%d client.addr = 0x%x \n",__func__,__LINE__,pClient->addr); + + // Copy data structure argument from user-space + if ( copy_from_user(&I2CData, (struct i2c_rdwr_ioctl_data __user*) ulArg, sizeof(I2CData)) ) + { + return(-EFAULT); + } + + // Only allow one message at a time + if ( I2CData.nmsgs != 1 ) + { + return(-EINVAL); + } + + // Copy the message structure from user-space + if ( copy_from_user(&I2CMsg, I2CData.msgs, sizeof(struct i2c_msg)) ) + { + return(-EFAULT); + } + + lRetVal = 0; + // Only allow transfers to the SE4750, limit the size of the message and don't allow received length changes + if ( (I2CMsg.addr != SE4750_I2C_ADDR) || (I2CMsg.len > 256) || (I2CMsg.flags & I2C_M_RECV_LEN) ) + { + return(-EINVAL); + } + + // Map the data buffer from user-space + pData = (u8 __user*) I2CMsg.buf; + I2CMsg.buf = memdup_user(pData, I2CMsg.len); + if ( IS_ERR(I2CMsg.buf) ) + { + return(PTR_ERR(I2CMsg.buf)); + } + if (!(I2CMsg.flags & I2C_M_RD)) + { + print_hex_dump(KERN_ERR, "sdl_control_ioctl: w:", DUMP_PREFIX_NONE, 16, 1, I2CMsg.buf, I2CMsg.len, true); +#ifdef MIMIC_ENGINE_RESPONSE + if (I2CMsg.buf[0] == 0x77 || I2CMsg.buf[0] == 0x58) + { + mimic_cmd_response = 1; + last_cmd_op_code = I2CMsg.buf[0]; + kfree(I2CMsg.buf); + return I2CMsg.len; + } +#endif + } + else + { +#ifdef MIMIC_ENGINE_RESPONSE + if (mimic_cmd_response) + { + mimic_cmd_response = 0; + I2CMsg.buf[0] = last_cmd_op_code; + I2CMsg.buf[1] = 0x80; + I2CMsg.len = 2; + if ( copy_to_user(pData, I2CMsg.buf, I2CMsg.len) ) + { + lRetVal = -EFAULT; + } + kfree(I2CMsg.buf); + return I2CMsg.len; + } +#endif + } + // Perform the I2C transfer + lRetVal = i2c_transfer(pClient->adapter, &I2CMsg, 1); + if ( (lRetVal >= 0) && (I2CMsg.flags & I2C_M_RD) ) + { + print_hex_dump(KERN_ERR, "sdl_control_ioctl: r:", DUMP_PREFIX_NONE, 16, 1, I2CMsg.buf, I2CMsg.len, true); + // Successful read, copy data to user-space + if ( copy_to_user(pData, I2CMsg.buf, I2CMsg.len) ) + { + lRetVal = -EFAULT; + } + } + kfree(I2CMsg.buf); + return lRetVal; +} + +static int se4750_mipi_misc_release(struct inode* pINode, struct file* pFile){ +#if 0 + int rc = 0; + + if (g_s_ctrl) + { + rc = cam_sensor_power_down(g_s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + //goto free_power_settings; + } + } +#endif + //is_opened_by_SDL = 0; + pr_err("SDL open %s:%d is_opened_by_SDL=%d\n",__func__,__LINE__, is_opened_by_SDL); + + return 0; +} + + +struct file_operations se4750_mipi_misc_fops ={ + .owner = THIS_MODULE, + .unlocked_ioctl = se4750_mipi_misc_ioctl, + .open = se4750_mipi_misc_open, + .release = se4750_mipi_misc_release, +}; + + +unsigned char cmdbuf[4] = {0x70,0x00,0x00,0x90}; +char respbuf[24] = {0}; +/* MODIFIED-END by yixiang.wu,BUG-10277816*/ + int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) { int rc = 0; @@ -754,6 +1227,35 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) return -EINVAL; } + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + if(slave_info->sensor_id == 0x80){ + //match id + memset(respbuf,0,24*sizeof(char)); + rc = se4750_mipi_i2c_txdata(s_ctrl->io_master_info.client,cmdbuf,4); + msleep(10); + rc = se4750_mipi_i2c_rxdata(s_ctrl->io_master_info.client,respbuf,24); + if((respbuf[0] == 0x70 && respbuf[1] == 0x80 ) && (respbuf[8] == 0x32 && respbuf[9] == 0x30)){ + CAM_ERR(CAM_SENSOR,"in %s : se4750 match id success !",__func__); + chipid = 0x4720; + if(!is_zebra_misc_device_exist){ + misc_register(&se4750_mipi_misc_device); + g_s_ctrl = s_ctrl; + dev_set_drvdata(se4750_mipi_misc_device.this_device, s_ctrl->io_master_info.client); + is_zebra_misc_device_exist =true; + } + return rc; + }else{ + CAM_ERR(CAM_SENSOR,"in %s : se4720 match id failed,respbuf[0] = 0x%x,[1] = 0x%x,[8] = 0x%x,[9] = 0x%x !",__func__, + respbuf[0],respbuf[1],respbuf[8],respbuf[9]); + chipid = 0x0; + return -ENODEV; + } + CAM_ERR(CAM_SENSOR, "yanhao read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + return rc; + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ + rc = camera_io_dev_read( &(s_ctrl->io_master_info), slave_info->sensor_id_reg_addr, @@ -761,7 +1263,7 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->sensor_probe_addr_type, s_ctrl->sensor_probe_data_type); - CAM_DBG(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", + CAM_WARN(CAM_SENSOR, "yanhao read id: 0x%x expected id 0x%x:", // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 chipid, slave_info->sensor_id); if (cam_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) { @@ -792,6 +1294,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } } + CAM_ERR(CAM_SENSOR, "wuyq:cmd->op_code 0x%x",cmd->op_code); // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 mutex_lock(&(s_ctrl->cam_sensor_mutex)); switch (cmd->op_code) { case CAM_SENSOR_PROBE_CMD: { @@ -942,11 +1445,15 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = -EFAULT; goto release_mutex; } - - rc = cam_sensor_power_up(s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); - goto release_mutex; + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + if (!is_opened_by_SDL) + { + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); + goto release_mutex; + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ } s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; @@ -976,6 +1483,13 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + if (is_opened_by_SDL) + { + is_opened_by_SDL = 0; // se4750_mipi_misc_release is called before CAM_STOP_DEV is called, so clear is_opened_by_SDL flag here. + CAM_INFO(CAM_SENSOR,"Set is_opened_by_SDL = %d", is_opened_by_SDL); + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); @@ -1032,7 +1546,10 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } - if (s_ctrl->i2c_data.streamon_settings.is_settings_valid && + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + if(s_ctrl->sensordata->slave_info.sensor_id != 0x80){ + if (s_ctrl->i2c_data.streamon_settings.is_settings_valid && + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ (s_ctrl->i2c_data.streamon_settings.request_id == 0)) { rc = cam_sensor_apply_settings(s_ctrl, 0, CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON); @@ -1041,7 +1558,22 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, "cannot apply streamon settings"); goto release_mutex; } - } + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + } + }else{ + //yanhao stream on + #ifndef MIMIC_ENGINE_RESPONSE + if (is_opened_by_SDL) //paul don't send commands if it's opened by SDL + { + //msleep(100); + CAM_INFO(CAM_SENSOR, "CAM_START_DEV with is_opened_by_SDL = %d", is_opened_by_SDL); + } + else + #endif + rc = streamOn_cmds(s_ctrl->io_master_info.client); + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ + s_ctrl->sensor_state = CAM_SENSOR_START; CAM_INFO(CAM_SENSOR, "CAM_START_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", @@ -1057,7 +1589,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->sensor_state); goto release_mutex; } - + if(s_ctrl->sensordata->slave_info.sensor_id != 0x80){ // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid && (s_ctrl->i2c_data.streamoff_settings.request_id == 0)) { rc = cam_sensor_apply_settings(s_ctrl, 0, @@ -1067,6 +1599,21 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, "cannot apply streamoff settings"); } } + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + }else{ + #if 0 //// To sync with ISP/VFE timing, we need to send ACQ_off command here. Cannot send it in SDL via /dev/sdl_control. + //#ifndef MIMIC_ENGINE_RESPONSE + if (is_opened_by_SDL) //paul don't send commands if it's opened by SDL + { + //msleep(100); + CAM_INFO(CAM_SENSOR, "CAM_START_DEV with is_opened_by_SDL = %d", is_opened_by_SDL); + } + else + #endif + //yanhao stream off + rc = streamOff_cmds(s_ctrl->io_master_info.client); + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ cam_sensor_release_per_frame_resource(s_ctrl); s_ctrl->last_flush_req = 0; @@ -1083,6 +1630,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); goto release_mutex; } + + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + if(s_ctrl->sensordata->slave_info.sensor_id == 0x80){ + rc = 0; + break; + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ + if (s_ctrl->i2c_data.init_settings.is_settings_valid && (s_ctrl->i2c_data.init_settings.request_id == 0)) { @@ -1483,6 +2038,11 @@ int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) } CAM_DBG(CAM_REQ, " Sensor update req id: %lld", apply->request_id); trace_cam_apply_req("Sensor", apply->request_id); + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + if (s_ctrl->sensordata->slave_info.sensor_id == 0x80){ + return 0; + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ mutex_lock(&(s_ctrl->cam_sensor_mutex)); rc = cam_sensor_apply_settings(s_ctrl, apply->request_id, CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE); diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 9c4025a789af..64067e8110b2 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -142,6 +142,7 @@ enum msm_camera_power_seq_type { SENSOR_STANDBY, SENSOR_CUSTOM_GPIO1, SENSOR_CUSTOM_GPIO2, + SENSOR_CUSTOM_GPIO3, // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 SENSOR_SEQ_TYPE_MAX, }; diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index b0c0b4384366..2e1b94a20917 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1681,6 +1681,29 @@ int cam_sensor_util_init_gpio_pin_tbl( rc = 0; } + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ + rc = of_property_read_u32(of_node, "gpio-custom3", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-custom3 failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-custom3 invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO3] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_CUSTOM_GPIO3] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-custom3 %d", + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO3]); + } else { + rc = 0; + } + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ + return rc; free_gpio_info: @@ -1953,6 +1976,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, case SENSOR_STANDBY: case SENSOR_CUSTOM_GPIO1: case SENSOR_CUSTOM_GPIO2: + case SENSOR_CUSTOM_GPIO3: // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 if (no_gpio) { CAM_ERR(CAM_SENSOR, "request gpio failed"); goto power_up_failed; @@ -2082,6 +2106,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, case SENSOR_STANDBY: case SENSOR_CUSTOM_GPIO1: case SENSOR_CUSTOM_GPIO2: + case SENSOR_CUSTOM_GPIO3: // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 if (!gpio_num_info) continue; if (!gpio_num_info->valid @@ -2249,6 +2274,7 @@ int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl, case SENSOR_STANDBY: case SENSOR_CUSTOM_GPIO1: case SENSOR_CUSTOM_GPIO2: + case SENSOR_CUSTOM_GPIO3: // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 if (!gpio_num_info->valid[pd->seq_type]) continue; -- GitLab From 5e0af179335b9f71e9beb9486a37b2716096602e Mon Sep 17 00:00:00 2001 From: "yixiang.wu" Date: Fri, 22 Jan 2021 16:38:31 +0800 Subject: [PATCH 373/410] [1 of 1][10277816]add the scanner driver code ###%%%comment:[1 of 1]add the scanner driver code ###%%%bug number:10277816 ###%%%product name:n10 ###%%%root cause:Specification ###%%%Bug category:T2M ###%%%regression response:--- ###%%%regression comments: ###%%%Module_Impact:scanner ###%%%Test_Suggestion:you can test scanner function ###%%%Solution:add the scanner driver code ###%%%Test_Report:you can test scanner function ###%%%VAL Can Test:Yes Change-Id: Ib37fe3c0dcda9a510c3b9e313074e971bb0eff15 --- drivers/cam_sensor_module/cam_sensor/Makefile | 2 +- .../cam_sensor_module/cam_sensor/cam_se47xx.c | 1850 +++++++++++++++++ .../cam_sensor/cam_sensor_core.c | 578 +---- 3 files changed, 1861 insertions(+), 569 deletions(-) create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_se47xx.c diff --git a/drivers/cam_sensor_module/cam_sensor/Makefile b/drivers/cam_sensor_module/cam_sensor/Makefile index d3a6fbb6c3e4..02169c17eb63 100644 --- a/drivers/cam_sensor_module/cam_sensor/Makefile +++ b/drivers/cam_sensor_module/cam_sensor/Makefile @@ -10,4 +10,4 @@ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_u ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils -obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_dev.o cam_sensor_core.o cam_sensor_soc.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_dev.o cam_sensor_core.o cam_sensor_soc.o cam_se47xx.o diff --git a/drivers/cam_sensor_module/cam_sensor/cam_se47xx.c b/drivers/cam_sensor_module/cam_sensor/cam_se47xx.c new file mode 100644 index 000000000000..384b7921f8d8 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_se47xx.c @@ -0,0 +1,1850 @@ +/* Copyright (C) 2021 Tcl Corporation Limited */ +/* +################################################################################ +# se47xx family of image sensors +# Copyright Zebra Technologies 2020 +# +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License version 2 and +# * only version 2 as published by the Free Software Foundation. +# * +# * This program is distributed in the hope that 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 +#include +#include +#include +#include +#include +#include +#include "cam_sensor_core.h" +#include "cam_sensor_util.h" +#include "cam_soc_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" +#include "cam_sensor_soc.h" + + +#define SCANNER_SENSOR_NAME "se47xx" + +//#define SCANNER_KLOGD + +#define TAG SCANNER_SENSOR_NAME +#define I2C_INTERVAL (10) + +#define SE47XX_SIZE_WVGA 0 +#define SE47XX_I2C_DEVICE_ADDR 0x5c +#define SE47XX_IMG_RES 0x5c +#define SE47XX_IMG_RES_RB2 0x01 +#define SE47XX_IMG_RES_RB4 0x02 +#define SE47XX_IMG_RES_CB2 0x03 +#define SE47XX_IMG_RES_CB4 0x04 +#define SE47XX_ACQ 0x58 +#define SE47XX_ACQ_ON 0x01 +#define SE47XX_ACQ_OFF 0x00 +#define SE47XX_AIM 0x55 +#define SE47XX_AIM_ON 0x01 +#define SE47XX_AIM_OFF 0x00 +#define SE47XX_AIM_DURING_EXPOSURE 0x56 +#define SE47XX_ILLUM 0x59 +#define SE47XX_ILLUM_ON 0x01 +#define SE47XX_ILLUM_OFF 0x00 +#define SE47XX_AUTO_POWER 0x74 +#define SE47XX_AUTO_POWER_EN 0x01 +#define SE47XX_TIME_TO_LOW_POWER 0x75 +#define SE47XX_PICKLIST_MODE 0x7b //Scanning Specific Barcode. +#define SE47XX_LCD_MODE 0x82 //Scanning Bar code On LCD. +#define SE47XX_FRAME_RATE 0x5E // FPS +#define SE47XX_PING 0x7A +#define SE47XX_IMG_CAP_MODE 0x73 +#define SE47XX_IMG_CAP_MODE_ON 0x01 +#define SE47XX_IMG_CAP_MODE_OFF 0x00 + +#define SE47XX_GET_PARAM 0x70 + +//BlockBuster return status values +#define SE47XX_RETURN_ACK 0x80 //Bit 7 Command Processed +#define SE47XX_RETURN_SP1 0x01 +#define SE47XX_RETURN_NAK 0x82 +#define SE47XX_RETURN_CKSM_ERROR 0x84 +#define SE47XX_RETURN_AIM_POWER_FAILURE 0x88 +#define SE47XX_RETURN_THERMAL_FAILURE 0x90 +#define SE47XX_RETURN_INTERNAL_I2C_FAILURE 0x20 +#define SE47XX_RETURN_SP6 0x40 +#define SE47XX_RETURN_UNUSUAL_ACK 0xA2 //unusual ack + +//#define USE_I2C_DELAY + +static int is_opened_by_SDL = 0; // A flag to indicate if scan engine is opened by SDL. +struct file_operations sdl_control_fops; + +static struct cam_sensor_ctrl_t* se47xx_misc_wa = NULL; +extern int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl); +extern void cam_sensor_query_cap(struct cam_sensor_ctrl_t *s_ctrl, + struct cam_sensor_query_cap *query_cap); + +#define BUF_SIZE 20 +static char g_camstatus[BUF_SIZE] = "none"; +static struct mutex g_camstatus_mutex; + +static int scan_exist_status = 0; +static int g_is_scan_mode = 0; +void set_scan_mode (int value) +{ + g_is_scan_mode = (value) ? 1 : 0; +} +EXPORT_SYMBOL(set_scan_mode); + +static int is_scan_mode (void) +{ + return g_is_scan_mode; +} +EXPORT_SYMBOL(is_scan_mode); + +#ifdef USE_I2C_DELAY +static unsigned get_tick_count (void) +{ + struct timeval gettick; + do_gettimeofday(&gettick); + return gettick.tv_sec * 1000 + gettick.tv_usec / 1000; +} +#endif + +int32_t cam_se47xx_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, + void *arg); + +static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_se47xx_driver_cmd(s_ctrl, arg); + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_sensor_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "s_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + + return 0; +} + +static struct v4l2_subdev_core_ops cam_sensor_subdev_core_ops = { + .ioctl = cam_sensor_subdev_ioctl, + .s_power = cam_sensor_power, +}; + +static struct v4l2_subdev_ops cam_sensor_subdev_ops = { + .core = &cam_sensor_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_sensor_internal_ops = { + .close = cam_sensor_subdev_close, +}; + +static int cam_sensor_init_subdev_params(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + + s_ctrl->v4l2_dev_str.internal_ops = + &cam_sensor_internal_ops; + s_ctrl->v4l2_dev_str.ops = + &cam_sensor_subdev_ops; + strlcpy(s_ctrl->device_name, SCANNER_SENSOR_NAME, + sizeof(s_ctrl->device_name)); + s_ctrl->v4l2_dev_str.name = + s_ctrl->device_name; + s_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + s_ctrl->v4l2_dev_str.ent_function = + CAM_SENSOR_DEVICE_TYPE; + s_ctrl->v4l2_dev_str.token = s_ctrl; + + rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str)); + if (rc) { + CAM_ERR(CAM_SENSOR, + "%s :cam_register_subdev failed, rc(%d)", s_ctrl->device_name, rc); + } + + return rc; +} + +static struct miscdevice sdl_control_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "sdl_control", + .fops = &sdl_control_fops, +}; + +static uint8_t se47xx_calc_checksum (uint8_t *data, uint16_t count) +{ + uint16_t sum = 0; + uint16_t i; + + for (i = 0; i < count; i++) + sum += data[i]; + + sum = ~sum + 1; + + return (sum & 0xff); +} + +static int se47xx_send_command (struct i2c_client *client, uint8_t *data, uint8_t len) +{ + struct i2c_msg msg; + + if (!client) { + pr_err("Invalid argument! (client=%p)", client); + return -1; + } + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + + return i2c_transfer(client->adapter, &msg, 1); +} + +static int se47xx_get_response (struct i2c_client *client, uint8_t *data, uint8_t len) +{ + struct i2c_msg msg; + + if (!client) { + pr_err("Invalid argument! (client=%p)", client); + return -1; + } + + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = len; + msg.buf = data; + + return i2c_transfer(client->adapter, &msg, 1); +} + +static int se47xx_send_command0 (struct i2c_client *client, uint8_t command, uint8_t *response) +{ + int rc; + uint8_t data[2]; + + data[0] = command; + data[1] = se47xx_calc_checksum(data, 1); + + rc = se47xx_send_command(client, data, 2); + if (rc < 0) { + mdelay(100); + rc = se47xx_send_command(client, data, 2); + if (rc < 0) { + pr_err("se47xx_send_command() failed!"); + return rc; + } + } + rc = se47xx_get_response(client, data, 2); + if (rc < 0) { + mdelay(100); + rc = se47xx_get_response(client, data, 2); + if (rc < 0) { + pr_err("se47xx_get_response() failed!"); + return rc; + } + } + if (command != data[0]) { + pr_err("command and response mismatch!"); + return -1; + } + if (response != NULL) { + *response = data[1]; + } + + return 0; +} +//it is not used during decoding +#if 0 +static int se47xx_send_command1 (struct i2c_client *client, uint8_t command, uint8_t value, uint8_t *response) +{ + int rc; + uint8_t data[3]; + + data[0] = command; + data[1] = value; + data[2] = se47xx_calc_checksum(data, 2); + rc = se47xx_send_command(client, data, 3); + if (rc < 0) { + mdelay(100); + rc = se47xx_send_command(client, data, 3); + if (rc < 0) { + pr_err("se47xx_send_command() failed!"); + return rc; + } + } + rc = se47xx_get_response(client, data, 2); + if (rc < 0) { + mdelay(100); + rc = se47xx_get_response(client, data, 2); + if (rc < 0) { + pr_err("se47xx_get_response() failed!"); + return rc; + } + } + + if (command != data[0]) { + pr_err("command and response mismatch!"); + return -1; + } + if (response != NULL) { + *response = data[1]; + } + + return 0; +} +#endif + +static int cam_se47xx_match_id(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint8_t response = 0; + struct cam_camera_slave_info *slave_info; + + slave_info = &(s_ctrl->sensordata->slave_info); + + if (!slave_info) { + CAM_ERR(CAM_SENSOR, " failed: %pK", + slave_info); + return -EINVAL; + } + + rc = se47xx_send_command0(s_ctrl->io_master_info.client, SE47XX_PING, &response); + if (rc < 0) { + pr_err("se47xx_send_command0(SE47XX_PING) failed!"); + return rc; + } + if (SE47XX_RETURN_ACK == response) { + scan_exist_status = 1; + se47xx_misc_wa = s_ctrl; + dev_set_drvdata(sdl_control_device.this_device, s_ctrl->io_master_info.client); + pr_err("se47xx match probe success\n"); + return 0; + } else { + scan_exist_status = 0; + pr_err("se47xx match id failed!"); + return -ENODEV; + } +} + +static int32_t se4750_mipi_i2c_rxdata(struct i2c_client *client, + unsigned char *rxdata, int data_length) +{ + int32_t rc = 0; + uint16_t saddr = client->addr; + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = I2C_M_RD, + .len = data_length, + .buf = rxdata, + }, + }; + rc = i2c_transfer(client->adapter, msgs, 1); + if (rc < 0) + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata failed 0x%x", saddr); + return rc; +} + +static int32_t se4750_mipi_i2c_txdata(struct i2c_client *client, + unsigned char *txdata, int length) +{ + int32_t rc = 0; + uint16_t saddr = client->addr; + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + rc = i2c_transfer(client->adapter, msg, 1); + if (rc < 0) + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata faild 0x%x rc=%d", saddr,rc); + return rc; +} + +static int se47xx_streamOn(struct i2c_client *client){ + int rc = 0; + int i = 0; + unsigned char streamOn_enableHW[3]={0x84,0x01,0x7b}; + unsigned char streamOn_enableMIPI[3]={0x86,0x03,0x77}; + unsigned char streamOn_enableAimOn[3]={0x55,0x01,0xaa}; + unsigned char streamOn_enableIllumOn[3]={0x59,0x01,0xa6}; + unsigned char streamOn_enableAcqOn[3]={0x58,0x01,0xa7}; + unsigned char respbuf[2] = {0}; + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableHW,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableHW failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableHW[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableHW success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableMIPI,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableMIPI failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableMIPI[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableMIPI success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableAimOn,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAimOn failed rc=%d",rc); + goto ERR_EXIT; + } + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableAimOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAimOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableIllumOn,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableIllumOn failed rc=%d",rc); + goto ERR_EXIT; + } + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableIllumOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableIllumOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableAcqOn,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAcqOn failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableAcqOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAcqOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +ERR_EXIT: + return rc; +} + +static int se47xx_streamOff(struct i2c_client *client){ + int rc = 0; + int i = 0; + int retry = 10; +// unsigned char streamOff_AimOff[3]={0x55,0x00,0xab}; +// unsigned char streamOff_IllumOff[3]={0x59,0x00,0xa7}; + unsigned char streamOff_AcqOff[3]={0x58,0x00,0xa8}; + unsigned char respbuf[2] = {0}; +#if 0 + rc = se4750_mipi_i2c_txdata(client,streamOff_AimOff,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AimOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_AimOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AimOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + rc = se4750_mipi_i2c_txdata(client,streamOff_IllumOff,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_IllumOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_IllumOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_IllumOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +#endif + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOff_AcqOff,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d retry=%d", rc, i); + } + } + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_AcqOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AcqOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +ERR_EXIT: + return rc; +} + +static int streamOn_cmds(struct i2c_client *client){ + int rc = 0; + int i = 0; + unsigned char streamOn_enableHW[3]={0x84,0x01,0x7b}; + unsigned char streamOn_enableMIPI[3]={0x86,0x03,0x77}; + unsigned char streamOn_enableAimOn[3]={0x55,0x01,0xaa}; + unsigned char streamOn_enableIllumOn[3]={0x59,0x01,0xa6}; + unsigned char streamOn_enableAcqOn[3]={0x58,0x01,0xa7}; + unsigned char respbuf[2] = {0}; + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableHW,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableHW failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableHW[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableHW success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableMIPI,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableMIPI failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableMIPI[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableMIPI success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableAimOn,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAimOn failed rc=%d",rc); + goto ERR_EXIT; + } + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableAimOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAimOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableIllumOn,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableIllumOn failed rc=%d",rc); + goto ERR_EXIT; + } + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableIllumOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableIllumOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + + rc = se4750_mipi_i2c_txdata(client,streamOn_enableAcqOn,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAcqOn failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOn_enableAcqOn[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAcqOn success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + +ERR_EXIT: + return rc; +} + + +static int streamOff_cmds(struct i2c_client *client){ + int rc = 0; + int i = 0; + int retry = 10; +// unsigned char streamOff_AimOff[3]={0x55,0x00,0xab}; +// unsigned char streamOff_IllumOff[3]={0x59,0x00,0xa7}; + unsigned char streamOff_AcqOff[3]={0x58,0x00,0xa8}; + unsigned char respbuf[2] = {0}; +#if 0 + rc = se4750_mipi_i2c_txdata(client,streamOff_AimOff,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AimOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_AimOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AimOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + + rc = se4750_mipi_i2c_txdata(client,streamOff_IllumOff,3); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_IllumOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0;i<10;i++){ + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_IllumOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_IllumOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +#endif + for(i=0; i < retry ; i++){ + rc = se4750_mipi_i2c_txdata(client,streamOff_AcqOff,3); + if(rc > 0) + { + break; + } + else + { + msleep(1); + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d retry=%d", rc, i); + } + } + if (i >= retry) + { + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d",rc); + goto ERR_EXIT; + } + + for(i=0; i < retry ; i++){ + + rc = se4750_mipi_i2c_rxdata(client,respbuf,2); + if(rc > 0 && respbuf[0] == streamOff_AcqOff[0] && respbuf[1] == 0x80){ + CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AcqOff success! i =%d",i); + break; + }else{ + msleep(1); + } + } + +ERR_EXIT: + return rc; +} + + +static void cam_sensor_update_req_mgr( + struct cam_sensor_ctrl_t *s_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_req_mgr_add_request add_req; + + add_req.link_hdl = s_ctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + CAM_ERR(CAM_SENSOR, " Rxed Req Id: %lld", + csl_packet->header.request_id); + add_req.dev_hdl = s_ctrl->bridge_intf.device_hdl; + add_req.skip_before_applying = 0; + if (s_ctrl->bridge_intf.crm_cb && + s_ctrl->bridge_intf.crm_cb->add_req) + s_ctrl->bridge_intf.crm_cb->add_req(&add_req); + + CAM_ERR(CAM_SENSOR, " add req to req mgr: %lld", + add_req.req_id); +} + +static void cam_sensor_release_stream_rsc( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int rc; + + i2c_set = &(s_ctrl->i2c_data.streamoff_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting Streamoff settings"); + } + + i2c_set = &(s_ctrl->i2c_data.streamon_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting Streamon settings"); + } +} + +static void cam_sensor_release_per_frame_resource( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int i, rc; + + if (s_ctrl->i2c_data.per_frame != NULL) { + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(s_ctrl->i2c_data.per_frame[i]); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + } + } + } +} + +static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, + void *arg) +{ + int32_t rc = 0; + uintptr_t generic_ptr; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_buf_io_cfg *io_cfg = NULL; + struct i2c_settings_array *i2c_reg_settings = NULL; + size_t len_of_buff = 0; + size_t remain_len = 0; + uint32_t *offset = NULL; + struct cam_config_dev_cmd config; + struct i2c_data_settings *i2c_data = NULL; + + ioctl_ctrl = (struct cam_control *)arg; + + if (ioctl_ctrl->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_SENSOR, "Invalid Handle Type"); + return -EINVAL; + } + + if (copy_from_user(&config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) + return -EFAULT; + + rc = cam_mem_get_cpu_buf( + config.packet_handle, + &generic_ptr, + &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed in getting the packet: %d", rc); + return rc; + } + + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_SENSOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto end; + } + + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *)(generic_ptr + + (uint32_t)config.offset); + + if ((csl_packet == NULL) || cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_SENSOR, "Invalid packet params"); + rc = -EINVAL; + goto end; + + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG && + csl_packet->header.request_id <= s_ctrl->last_flush_req + && s_ctrl->last_flush_req != 0) { + CAM_ERR(CAM_SENSOR, + "reject request %lld, last request to flush %u", + csl_packet->header.request_id, s_ctrl->last_flush_req); + rc = -EINVAL; + goto end; + } + + if (csl_packet->header.request_id > s_ctrl->last_flush_req) + s_ctrl->last_flush_req = 0; + + i2c_data = &(s_ctrl->i2c_data); + CAM_DBG(CAM_SENSOR, "Header OpCode: %d", csl_packet->header.op_code); + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG: { + i2c_reg_settings = &i2c_data->init_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG: { + i2c_reg_settings = &i2c_data->config_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { + if (s_ctrl->streamon_count > 0) + goto end; + + s_ctrl->streamon_count = s_ctrl->streamon_count + 1; + i2c_reg_settings = &i2c_data->streamon_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { + if (s_ctrl->streamoff_count > 0) + goto end; + + s_ctrl->streamoff_count = s_ctrl->streamoff_count + 1; + i2c_reg_settings = &i2c_data->streamoff_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_READ: { + i2c_reg_settings = &(i2c_data->read_settings); + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + + CAM_DBG(CAM_SENSOR, "number of IO configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs == 0) { + CAM_ERR(CAM_SENSOR, "No I/O configs to process"); + goto end; + } + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_SENSOR, "I/O config is invalid(NULL)"); + goto end; + } + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { + CAM_WARN(CAM_SENSOR, + "Rxed Update packets without linking"); + goto end; + } + + i2c_reg_settings = + &i2c_data->per_frame[csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY]; + CAM_DBG(CAM_SENSOR, "Received Packet: %lld req: %lld", + csl_packet->header.request_id % MAX_PER_FRAME_ARRAY, + csl_packet->header.request_id); + if (i2c_reg_settings->is_settings_valid == 1) { + CAM_ERR(CAM_SENSOR, + "Already some pkt in offset req : %lld", + csl_packet->header.request_id); + /* + * Update req mgr even in case of failure. + * This will help not to wait indefinitely + * and freeze. If this log is triggered then + * fix it. + */ + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + goto end; + } + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { + CAM_WARN(CAM_SENSOR, + "Rxed NOP packets without linking"); + goto end; + } + + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + goto end; + } + default: + CAM_ERR(CAM_SENSOR, "Invalid Packet Header"); + rc = -EINVAL; + goto end; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += csl_packet->cmd_buf_offset / 4; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + rc = cam_sensor_i2c_command_parser(&s_ctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); + goto end; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) == + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE) { + i2c_reg_settings->request_id = + csl_packet->header.request_id; + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + } + +end: + return rc; +} + +int32_t cam_se47xx_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, + void *arg) +{ + int rc = 0, pkt_opcode = 0; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_sensor_power_ctrl_t *power_info = + &s_ctrl->sensordata->power_info; + if (!s_ctrl || !arg) { + CAM_ERR(CAM_SENSOR, "s_ctrl is NULL"); + return -EINVAL; + } + + CAM_ERR(CAM_SENSOR, "wuyq enter %s type:0x%x", __func__, cmd->op_code); + if (cmd->op_code != CAM_SENSOR_PROBE_CMD) { + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_SENSOR, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + switch (cmd->op_code) { + case CAM_SENSOR_PROBE_CMD: { + if (s_ctrl->is_probe_succeed == 1) { + CAM_ERR(CAM_SENSOR, + "Already Sensor Probed in the slot"); + break; + } + + if (cmd->handle_type == + CAM_HANDLE_MEM_HANDLE) { + rc = cam_handle_mem_ptr(cmd->handle, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Get Buffer Handle Failed"); + goto release_mutex; + } + } else { + CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d", + cmd->handle_type); + rc = -EINVAL; + goto release_mutex; + } + + /* Parse and fill vreg params for powerup settings */ + rc = msm_camera_fill_vreg_params( + &s_ctrl->soc_info, + s_ctrl->sensordata->power_info.power_setting, + s_ctrl->sensordata->power_info.power_setting_size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in filling vreg params for PUP rc %d", + rc); + goto free_power_settings; + } + + /* Parse and fill vreg params for powerdown settings*/ + rc = msm_camera_fill_vreg_params( + &s_ctrl->soc_info, + s_ctrl->sensordata->power_info.power_down_setting, + s_ctrl->sensordata->power_info.power_down_setting_size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in filling vreg params for PDOWN rc %d", + rc); + goto free_power_settings; + } + + /* Power up and probe sensor */ + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + goto free_power_settings; + } + + /* Match sensor ID */ + rc = cam_se47xx_match_id(s_ctrl); + if (rc < 0) { + cam_sensor_power_down(s_ctrl); + msleep(20); + goto free_power_settings; + } + + CAM_INFO(CAM_SENSOR, + "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x", + s_ctrl->soc_info.index, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + s_ctrl->sensordata->slave_info.sensor_id); + + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); + goto free_power_settings; + } + /* + * Set probe succeeded flag to 1 so that no other camera shall + * probed on this slot + */ + s_ctrl->is_probe_succeed = 1; + s_ctrl->sensor_state = CAM_SENSOR_INIT; + } + break; + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev sensor_acq_dev; + struct cam_create_dev_hdl bridge_params; + + if ((s_ctrl->is_probe_succeed == 0) || + (s_ctrl->sensor_state != CAM_SENSOR_INIT)) { + CAM_WARN(CAM_SENSOR, + "Not in right state to aquire %d, probe %d", + s_ctrl->sensor_state, s_ctrl->is_probe_succeed); + rc = -EINVAL; + goto release_mutex; + } + + if (s_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_SENSOR, "Device is already acquired"); + rc = -EINVAL; + goto release_mutex; + } + rc = copy_from_user(&sensor_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(sensor_acq_dev)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed Copying from user"); + goto release_mutex; + } + + bridge_params.session_hdl = sensor_acq_dev.session_handle; + bridge_params.ops = &s_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = s_ctrl; + + sensor_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; + s_ctrl->bridge_intf.session_hdl = sensor_acq_dev.session_handle; + + CAM_DBG(CAM_SENSOR, "Device Handle: %d", + sensor_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &sensor_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_SENSOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + + /* for preview debug */ + if (!is_opened_by_SDL) { + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); + goto release_mutex; + } + } + + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + s_ctrl->last_flush_req = 0; + CAM_INFO(CAM_SENSOR, + "CAM_ACQUIRE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_RELEASE_DEV: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_START)) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to release : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + if (s_ctrl->bridge_intf.link_hdl != -1) { + CAM_ERR(CAM_SENSOR, + "Device [%d] still active on link 0x%x", + s_ctrl->sensor_state, + s_ctrl->bridge_intf.link_hdl); + rc = -EAGAIN; + goto release_mutex; + } + + /* for preview debug */ + if (is_opened_by_SDL) { + is_opened_by_SDL = 0; + } + + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); + goto release_mutex; + } + + cam_sensor_release_per_frame_resource(s_ctrl); + cam_sensor_release_stream_rsc(s_ctrl); + if (s_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_SENSOR, + "Invalid Handles: link hdl: %d device hdl: %d", + s_ctrl->bridge_intf.device_hdl, + s_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed in destroying the device hdl"); + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.session_hdl = -1; + + s_ctrl->sensor_state = CAM_SENSOR_INIT; + CAM_INFO(CAM_SENSOR, + "CAM_RELEASE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + s_ctrl->streamon_count = 0; + s_ctrl->streamoff_count = 0; + s_ctrl->last_flush_req = 0; + } + break; + case CAM_QUERY_CAP: { + struct cam_sensor_query_cap sensor_cap; + + cam_sensor_query_cap(s_ctrl, &sensor_cap); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &sensor_cap, sizeof(struct cam_sensor_query_cap))) { + CAM_ERR(CAM_SENSOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + } + CAM_ERR(CAM_SENSOR, "wuyq %s type:CAM_QUERY_CAP", __func__); + break; + + case CAM_START_DEV: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_START)) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to start : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + //paul don't send commands if it's opened by SDL + if (is_opened_by_SDL) { + //msleep(100); + CAM_INFO(CAM_SENSOR, "CAM_START_DEV with is_opened_by_SDL = %d", is_opened_by_SDL); + } else { + if ( 1 == 1 ) + rc = se47xx_streamOn(s_ctrl->io_master_info.client); + else + rc = streamOn_cmds(s_ctrl->io_master_info.client); + + } + + s_ctrl->sensor_state = CAM_SENSOR_START; + CAM_INFO(CAM_SENSOR, + "CAM_START_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_STOP_DEV: { + if (s_ctrl->sensor_state != CAM_SENSOR_START) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to stop : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + //paul don't send commands if it's opened by SDL + if (is_opened_by_SDL) { + //msleep(100); + CAM_INFO(CAM_SENSOR, "CAM_START_DEV with is_opened_by_SDL = %d", is_opened_by_SDL); + } else { + if (1 == 1) + rc = se47xx_streamOff(s_ctrl->io_master_info.client); + else + rc = streamOff_cmds(s_ctrl->io_master_info.client); + + } + + cam_sensor_release_per_frame_resource(s_ctrl); + s_ctrl->last_flush_req = 0; + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + CAM_INFO(CAM_SENSOR, + "CAM_STOP_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_CONFIG_DEV: { + rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); + goto release_mutex; + } + if (s_ctrl->sensordata->slave_info.sensor_id == 0x80) { + rc = 0; + break; + } + if (s_ctrl->i2c_data.init_settings.is_settings_valid && + (s_ctrl->i2c_data.init_settings.request_id == 0)) { + + pkt_opcode = + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG; + rc = cam_sensor_apply_settings(s_ctrl, 0, + pkt_opcode); + + if ((rc == -EAGAIN) && + (s_ctrl->io_master_info.master_type == CCI_MASTER)) { + /* If CCI hardware is resetting we need to wait + * for sometime before reapply + */ + CAM_WARN(CAM_SENSOR, + "Reapplying the Init settings due to cci hw reset"); + usleep_range(1000, 1010); + rc = cam_sensor_apply_settings(s_ctrl, 0, + pkt_opcode); + } + s_ctrl->i2c_data.init_settings.request_id = -1; + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply init settings rc= %d", + rc); + delete_request(&s_ctrl->i2c_data.init_settings); + goto release_mutex; + } + rc = delete_request(&s_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the Init settings"); + goto release_mutex; + } + } + + if (s_ctrl->i2c_data.config_settings.is_settings_valid && + (s_ctrl->i2c_data.config_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG); + + s_ctrl->i2c_data.config_settings.request_id = -1; + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply config settings"); + delete_request( + &s_ctrl->i2c_data.config_settings); + goto release_mutex; + } + rc = delete_request(&s_ctrl->i2c_data.config_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the config settings"); + goto release_mutex; + } + s_ctrl->sensor_state = CAM_SENSOR_CONFIG; + } + + if (s_ctrl->i2c_data.read_settings.is_settings_valid) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_READ); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply read settings"); + delete_request( + &s_ctrl->i2c_data.read_settings); + goto release_mutex; + } + rc = delete_request( + &s_ctrl->i2c_data.read_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the read settings"); + goto release_mutex; + } + } + + CAM_DBG(CAM_SENSOR, + "CAM_CONFIG_DEV done sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + goto release_mutex; + } + +release_mutex: + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; + +free_power_settings: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; +} + +static ssize_t device_sysfs_se47xx_camstatus_show (struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char *s = buf; + mutex_lock(&g_camstatus_mutex); + s += sprintf(buf, g_camstatus); + mutex_unlock(&g_camstatus_mutex); + return s - buf + 1; +} + +static ssize_t device_sysfs_se47xx_camstatus_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + char lbuf[BUF_SIZE]; + mutex_lock(&g_camstatus_mutex); + if (count <= 0 || count >= sizeof(g_camstatus)) { + goto exit_camstatus_store; + } + memcpy(lbuf, buf, count); + lbuf[count] = 0; + if (lbuf[0] == '#' && strcmp(g_camstatus, lbuf + 1) == 0) { + strcpy(g_camstatus, "none"); + } else if (lbuf[0] != '#' && strcmp(g_camstatus, "none") == 0) { + strcpy(g_camstatus, lbuf); + } + +exit_camstatus_store: + mutex_unlock(&g_camstatus_mutex); + return count; +} + +static DEVICE_ATTR(camstatus, 0664, device_sysfs_se47xx_camstatus_show, device_sysfs_se47xx_camstatus_store); + +static ssize_t device_sysfs_se47xx_is_scan_mode_show (struct device* dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", g_is_scan_mode); +} + +static DEVICE_ATTR(is_scan_mode, S_IRUGO, + device_sysfs_se47xx_is_scan_mode_show, + NULL); + +static ssize_t device_sysfs_se47xx_scan_exist_status_show (struct device* dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", scan_exist_status); +} + +static DEVICE_ATTR(scan_exist_status, S_IRUGO, + device_sysfs_se47xx_scan_exist_status_show, + NULL); + +struct kobject *device_se47xx_kobj = NULL; +static int device_sysfs_init (void) +{ + int rc = 0; + + device_se47xx_kobj = kobject_create_and_add("se47xx", NULL); + if (device_se47xx_kobj == NULL) { + pr_err("kobject_creat_and_add(/sys/se47xx/) failed!"); + return -ENOMEM; + } + + rc = sysfs_create_file(device_se47xx_kobj,&dev_attr_is_scan_mode.attr); + if (rc) { + pr_err("sysfs_creat_file(/sys/se47xx/is_scan_mode) failed!"); + goto destroy_kobj; + } + + rc = sysfs_create_file(device_se47xx_kobj, &dev_attr_camstatus.attr); + if (rc) { + pr_err("sysfs_create_file('/sys/se47xx/camstatus') failed"); + goto destroy_is_scanstatus_mode; + } + + rc = sysfs_create_file(device_se47xx_kobj, &dev_attr_scan_exist_status.attr); + if (rc) { + pr_err("sysfs_create_file('/sys/se47xx/scan_exist_status') failed"); + goto destroy_scan_exist_status_mode; + } + + mutex_init(&g_camstatus_mutex); + + return rc; + +destroy_scan_exist_status_mode: + sysfs_remove_file(device_se47xx_kobj, &dev_attr_camstatus.attr); +destroy_is_scanstatus_mode: + sysfs_remove_file(device_se47xx_kobj, &dev_attr_is_scan_mode.attr); +destroy_kobj: + kobject_put(device_se47xx_kobj); + return rc; +} + +static void device_sysfs_deinit (void) +{ + mutex_destroy(&g_camstatus_mutex); + sysfs_remove_file(device_se47xx_kobj, &dev_attr_scan_exist_status.attr); + sysfs_remove_file(device_se47xx_kobj, &dev_attr_camstatus.attr); + sysfs_remove_file(device_se47xx_kobj, &dev_attr_is_scan_mode.attr); + kobject_put(device_se47xx_kobj); +} + +static int sdl_control_open (struct inode* node, struct file* file) +{ + int rc = 0; + if (se47xx_misc_wa) + { + CAM_ERR(CAM_SENSOR, "se47xx_misc_wa is not null"); + rc = cam_sensor_power_up(se47xx_misc_wa); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + //goto free_power_settings; + } + } + is_opened_by_SDL = 1; + CAM_INFO(CAM_SENSOR, "SDL open %s:%d is_opened_by_SDL=%d\n",__func__,__LINE__, is_opened_by_SDL); + return 0; +} + +//#define MIMIC_ENGINE_RESPONSE 1 +#ifdef MIMIC_ENGINE_RESPONSE +static int mimic_cmd_response = 0; +static int last_cmd_op_code = 0; +#endif + +static long sdl_control_ioctl (struct file* file, unsigned int cmd, unsigned long arg) +{ + struct i2c_client* pClient; + struct i2c_rdwr_ioctl_data I2CData; + struct i2c_msg I2CMsg; + u8 __user* pData; + long lRetVal; + + //pr_err("yanhao open %s:%d \n",__func__,__LINE__); + + if ((cmd != I2C_RDWR) || !arg ) + { + return(-EINVAL); + } + + + pClient =dev_get_drvdata(sdl_control_device.this_device); + //pClient = file->private_data->sensor_i2c_client->client; + //CAM_ERR(CAM_SENSOR, "yanhao open %s:%d client.addr = 0x%x \n",__func__,__LINE__,pClient->addr); + + // Copy data structure argument from user-space + if ( copy_from_user(&I2CData, (struct i2c_rdwr_ioctl_data __user*) arg, sizeof(I2CData)) ) + { + return(-EFAULT); + } + + // Only allow one message at a time + if ( I2CData.nmsgs != 1 ) + { + return(-EINVAL); + } + + // Copy the message structure from user-space + if ( copy_from_user(&I2CMsg, I2CData.msgs, sizeof(struct i2c_msg)) ) + { + return(-EFAULT); + } + + lRetVal = 0; + // Only allow transfers to the SE4750, limit the size of the message and don't allow received length changes + if ( (I2CMsg.addr != SE47XX_I2C_DEVICE_ADDR) || (I2CMsg.len > 256) || (I2CMsg.flags & I2C_M_RECV_LEN) ) + { + return(-EINVAL); + } + + // Map the data buffer from user-space + pData = (u8 __user*) I2CMsg.buf; + I2CMsg.buf = memdup_user(pData, I2CMsg.len); + if ( IS_ERR(I2CMsg.buf) ) + { + return(PTR_ERR(I2CMsg.buf)); + } + if (!(I2CMsg.flags & I2C_M_RD)) + { + print_hex_dump(KERN_ERR, "sdl_control_ioctl: w:", DUMP_PREFIX_NONE, 16, 1, I2CMsg.buf, I2CMsg.len, true); +#ifdef MIMIC_ENGINE_RESPONSE + if (I2CMsg.buf[0] == 0x77 || I2CMsg.buf[0] == 0x58) + { + mimic_cmd_response = 1; + last_cmd_op_code = I2CMsg.buf[0]; + kfree(I2CMsg.buf); + return I2CMsg.len; + } +#endif + } + else + { +#ifdef MIMIC_ENGINE_RESPONSE + if (mimic_cmd_response) + { + mimic_cmd_response = 0; + I2CMsg.buf[0] = last_cmd_op_code; + I2CMsg.buf[1] = 0x80; + I2CMsg.len = 2; + if ( copy_to_user(pData, I2CMsg.buf, I2CMsg.len) ) + { + lRetVal = -EFAULT; + } + kfree(I2CMsg.buf); + return I2CMsg.len; + } +#endif + } + // Perform the I2C transfer + lRetVal = i2c_transfer(pClient->adapter, &I2CMsg, 1); + if ( (lRetVal >= 0) && (I2CMsg.flags & I2C_M_RD) ) + { + print_hex_dump(KERN_ERR, "sdl_control_ioctl: r:", DUMP_PREFIX_NONE, 16, 1, I2CMsg.buf, I2CMsg.len, true); + // Successful read, copy data to user-space + if ( copy_to_user(pData, I2CMsg.buf, I2CMsg.len) ) + { + lRetVal = -EFAULT; + } + } + kfree(I2CMsg.buf); + return lRetVal; +} + +static int sdl_control_release (struct inode* node, struct file* file) +{ + CAM_ERR(CAM_SENSOR,"enter"); + return 0; +} + +struct file_operations sdl_control_fops = +{ + .owner = THIS_MODULE, + .unlocked_ioctl = sdl_control_ioctl, + .open = sdl_control_open, + .release = sdl_control_release, +}; + +static int cam_se47xx_driver_i2c_remove(struct i2c_client *client) +{ + int i; + struct cam_sensor_ctrl_t *s_ctrl = i2c_get_clientdata(client); + struct cam_hw_soc_info *soc_info; + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "sensor device is NULL"); + return 0; + } + + CAM_INFO(CAM_SENSOR, "i2c remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); + soc_info = &s_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + kfree(s_ctrl->i2c_data.per_frame); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); + kfree(s_ctrl); + + return 0; +} + +int32_t cam_sensor_apply_request_nop(struct cam_req_mgr_apply_request *apply) +{ + CAM_INFO(CAM_SENSOR,"%s Enter", __func__); + return 0; +} + +int32_t cam_sensor_flush_request_nop(struct cam_req_mgr_flush_request *flush_req) +{ + CAM_INFO(CAM_SENSOR,"%s Enter", __func__); + return 0; +} + +static int32_t se47xx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0; + int i = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + struct cam_hw_soc_info *soc_info = NULL; + + CAM_ERR(CAM_SENSOR,"%s Enter", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_SENSOR, + "%s :i2c_check_functionality failed", client->name); + return -EFAULT; + } + + /* Create barcode control structure */ + s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, + "%s :kzalloc for s_ctrl acquire mem failed, rc(%d)", client->name, rc); + return -ENOMEM; + } + + /* Set the barcode private data */ + i2c_set_clientdata(client, s_ctrl); + + s_ctrl->io_master_info.client = client; + soc_info = &s_ctrl->soc_info; + soc_info->dev = &client->dev; + soc_info->dev_name = client->name; + + /* Initialize sensor device type */ + s_ctrl->of_node = client->dev.of_node; + s_ctrl->io_master_info.master_type = I2C_MASTER; + s_ctrl->is_probe_succeed = 0; + s_ctrl->last_flush_req = 0; + + /* Parse dt data for init*/ + rc = cam_sensor_parse_dt(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "%s :cam_sensor_parse_dt failed, rc(%d)", client->name, rc); + goto free_s_ctrl; + } + + /* Set ioctl interface for up layer */ + rc = cam_sensor_init_subdev_params(s_ctrl); + if (rc) { + CAM_ERR(CAM_SENSOR, + "%s :cam_sensor_init_subdev_params failed, rc(%d)", client->name, rc); + goto free_s_ctrl; + } + + s_ctrl->i2c_data.per_frame = + (struct i2c_settings_array *) + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (s_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_SENSOR, + "%s :kzalloc for per_frame acquire mem failed, rc(%d)", client->name, rc); + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(s_ctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); + + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info; + s_ctrl->bridge_intf.ops.link_setup = cam_sensor_establish_link; + s_ctrl->bridge_intf.ops.apply_req = cam_sensor_apply_request_nop; + s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request_nop; + + s_ctrl->sensordata->power_info.dev = soc_info->dev; + + /* Registering sdl_control */ + CAM_INFO(CAM_SENSOR, "Registering sdl_control"); + //se47xx_misc_wa = s_ctrl; + rc = misc_register(&sdl_control_device); + if (rc) { + CAM_ERR(CAM_SENSOR, + "%s :misc_register failed, rc(%d)", client->name, rc); + } else { + device_sysfs_init(); + } + + return rc; +unreg_subdev: + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); +free_s_ctrl: + kfree(s_ctrl); + return rc; +} + +static int se47xx_i2c_remove (struct i2c_client *client) +{ + CAM_ERR(CAM_SENSOR,"enter"); + cam_se47xx_driver_i2c_remove(client); + device_sysfs_deinit(); + CAM_ERR(CAM_SENSOR,"exit"); + return 0; +} + +static const struct i2c_device_id se47xx_i2c_id[] = { + { SCANNER_SENSOR_NAME, (kernel_ulong_t)NULL }, + { } +}; + +static const struct of_device_id se47xx_dt_match[] = { + { .compatible = "zebra,se47xx" }, + { } +}; +MODULE_DEVICE_TABLE(of, se47xx_dt_match); + +static struct i2c_driver cam_se47xx_driver_i2c = { + .id_table = se47xx_i2c_id, + .probe = se47xx_i2c_probe, + .remove = se47xx_i2c_remove, + .driver = { + .name = SCANNER_SENSOR_NAME, + .of_match_table = se47xx_dt_match, + }, +}; + + +static int __init se47xx_init_module (void) +{ + CAM_ERR(CAM_SENSOR,"++"); + return i2c_add_driver(&cam_se47xx_driver_i2c); +} + +static void __exit se47xx_exit_module (void) +{ + CAM_ERR(CAM_SENSOR,"++"); + return i2c_del_driver(&cam_se47xx_driver_i2c); +} + +module_init(se47xx_init_module); +module_exit(se47xx_exit_module); +MODULE_DESCRIPTION("Zebra SE47XX 2D scanner driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 6ee5ce29b0f7..9e2381b436dd 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -4,10 +4,6 @@ */ #include -/* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ -#include -#include -/* MODIFIED-END by yixiang.wu,BUG-10277816*/ #include #include "cam_sensor_core.h" #include "cam_sensor_util.h" @@ -744,475 +740,6 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->sensor_state = CAM_SENSOR_INIT; } -/* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ -//s_ctrl->io_master_info.client yanhao - - -static int32_t se4750_mipi_i2c_rxdata(struct i2c_client *client, - unsigned char *rxdata, int data_length) -{ - int32_t rc = 0; - uint16_t saddr = client->addr; - struct i2c_msg msgs[] = { - { - .addr = saddr, - .flags = I2C_M_RD, - .len = data_length, - .buf = rxdata, - }, - }; - rc = i2c_transfer(client->adapter, msgs, 1); - if (rc < 0) - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata failed 0x%x", saddr); - return rc; -} - -static int32_t se4750_mipi_i2c_txdata(struct i2c_client *client, - unsigned char *txdata, int length) -{ - int32_t rc = 0; - uint16_t saddr = client->addr; - struct i2c_msg msg[] = { - { - .addr = saddr, - .flags = 0, - .len = length, - .buf = txdata, - }, - }; - rc = i2c_transfer(client->adapter, msg, 1); - if (rc < 0) - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata faild 0x%x rc=%d", saddr,rc); - return rc; -} - - - - -int streamOn_cmds(struct i2c_client *client){ - int rc = 0; - int i = 0; - int retry = 30; - unsigned char streamOn_enableHW[3]={0x84,0x01,0x7b}; - unsigned char streamOn_enableMIPI[3]={0x86,0x03,0x77}; - unsigned char streamOn_enableAimOn[3]={0x55,0x01,0xaa}; - unsigned char streamOn_enableIllumOn[3]={0x59,0x01,0xa6}; - unsigned char streamOn_enableAcqOn[3]={0x58,0x01,0xa7}; - unsigned char respbuf[2] = {0}; - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_txdata(client,streamOn_enableHW,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableHW failed rc=%d retry=%d", rc, i); - } - } - - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableHW failed rc=%d",rc); - goto ERR_EXIT; - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOn_enableHW[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableHW success! i =%d",i); - break; - }else{ - msleep(1); - } - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_txdata(client,streamOn_enableMIPI,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableMIPI failed rc=%d retry=%d", rc, i); - } - } - - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableMIPI failed rc=%d",rc); - goto ERR_EXIT; - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOn_enableMIPI[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableMIPI success! i =%d",i); - break; - }else{ - msleep(1); - } - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_txdata(client,streamOn_enableAimOn,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAimOn failed rc=%d retry=%d", rc, i); - } - } - - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAimOn failed rc=%d",rc); - goto ERR_EXIT; - } - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOn_enableAimOn[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAimOn success! i =%d",i); - break; - }else{ - msleep(1); - } - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_txdata(client,streamOn_enableIllumOn,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableIllumOn failed rc=%d retry=%d", rc, i); - } - } - - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableIllumOn failed rc=%d",rc); - goto ERR_EXIT; - } - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOn_enableIllumOn[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableIllumOn success! i =%d",i); - break; - }else{ - msleep(1); - } - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_txdata(client,streamOn_enableAcqOn,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAcqOn failed rc=%d retry=%d", rc, i); - } - } - - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOn_enableAcqOn failed rc=%d",rc); - goto ERR_EXIT; - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOn_enableAcqOn[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOn_enableAcqOn success! i =%d",i); - break; - }else{ - msleep(1); - } - } - -ERR_EXIT: - return rc; -} - - -int streamOff_cmds(struct i2c_client *client){ - int rc = 0; - int i = 0; - int retry = 30; -// unsigned char streamOff_AimOff[3]={0x55,0x00,0xab}; -// unsigned char streamOff_IllumOff[3]={0x59,0x00,0xa7}; - unsigned char streamOff_AcqOff[3]={0x58,0x00,0xa8}; - unsigned char respbuf[2] = {0}; -#if 0 - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_txdata(client,streamOff_AimOff,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AimOff failed rc=%d retry=%d", rc, i); - } - } - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AimOff failed rc=%d",rc); - goto ERR_EXIT; - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOff_AimOff[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AimOff success! i =%d",i); - break; - }else{ - msleep(1); - } - } - - for(i=0; i < retry ; i++){ - rc = rc = se4750_mipi_i2c_txdata(client,streamOff_IllumOff,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_IllumOff failed rc=%d retry=%d", rc, i); - } - } - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_IllumOff failed rc=%d",rc); - goto ERR_EXIT; - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOff_IllumOff[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_IllumOff success! i =%d",i); - break; - }else{ - msleep(1); - } - } - -#endif - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_txdata(client,streamOff_AcqOff,3); - if(rc > 0) - { - break; - } - else - { - msleep(1); - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d retry=%d", rc, i); - } - } - if (i >= retry) - { - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_txdata streamOff_AcqOff failed rc=%d",rc); - goto ERR_EXIT; - } - - for(i=0; i < retry ; i++){ - rc = se4750_mipi_i2c_rxdata(client,respbuf,2); - if(rc > 0 && respbuf[0] == streamOff_AcqOff[0] && respbuf[1] == 0x80){ - CAM_ERR(CAM_SENSOR,"se4750_mipi_i2c_rxdata streamOff_AcqOff success! i =%d",i); - break; - }else{ - msleep(1); - } - } - -ERR_EXIT: - return rc; -} - - -#define SE4750_MIPI_MISC_NAME "sdl_control" -#define SE4750_I2C_ADDR 0x5C -bool is_zebra_misc_device_exist = false; -static int is_opened_by_SDL = 0; // A flag to indicate if scan engine is opened by SDL. -static struct cam_sensor_ctrl_t *g_s_ctrl; -struct file_operations se4750_mipi_misc_fops; -//#define MIMIC_ENGINE_RESPONSE 1 -#ifdef MIMIC_ENGINE_RESPONSE -static int mimic_cmd_response = 0; -static int last_cmd_op_code = 0; -#endif - -static struct miscdevice se4750_mipi_misc_device = { - .minor = MISC_DYNAMIC_MINOR, - .name =SE4750_MIPI_MISC_NAME, - .fops = &se4750_mipi_misc_fops, -}; - -/* -------------------------------------------------------------------------- - * 'misc' device file operations - */ - -static int se4750_mipi_misc_open(struct inode* pINode, struct file* pFile) -{ - int rc = 0; - if (g_s_ctrl) - { - rc = cam_sensor_power_up(g_s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "power up failed"); - //goto free_power_settings; - } - } - is_opened_by_SDL = 1; - pr_err("SDL open %s:%d is_opened_by_SDL=%d\n",__func__,__LINE__, is_opened_by_SDL); - return 0; -} - - -static long se4750_mipi_misc_ioctl(struct file* pFile, unsigned int uiCmd, unsigned long ulArg) -{ - struct i2c_client* pClient; - struct i2c_rdwr_ioctl_data I2CData; - struct i2c_msg I2CMsg; - u8 __user* pData; - long lRetVal; - - //pr_err("yanhao open %s:%d \n",__func__,__LINE__); - - if ((uiCmd != I2C_RDWR) || !ulArg ) - { - return(-EINVAL); - } - pClient =dev_get_drvdata(se4750_mipi_misc_device.this_device); - //pr_err("yanhao open %s:%d client.addr = 0x%x \n",__func__,__LINE__,pClient->addr); - - // Copy data structure argument from user-space - if ( copy_from_user(&I2CData, (struct i2c_rdwr_ioctl_data __user*) ulArg, sizeof(I2CData)) ) - { - return(-EFAULT); - } - - // Only allow one message at a time - if ( I2CData.nmsgs != 1 ) - { - return(-EINVAL); - } - - // Copy the message structure from user-space - if ( copy_from_user(&I2CMsg, I2CData.msgs, sizeof(struct i2c_msg)) ) - { - return(-EFAULT); - } - - lRetVal = 0; - // Only allow transfers to the SE4750, limit the size of the message and don't allow received length changes - if ( (I2CMsg.addr != SE4750_I2C_ADDR) || (I2CMsg.len > 256) || (I2CMsg.flags & I2C_M_RECV_LEN) ) - { - return(-EINVAL); - } - - // Map the data buffer from user-space - pData = (u8 __user*) I2CMsg.buf; - I2CMsg.buf = memdup_user(pData, I2CMsg.len); - if ( IS_ERR(I2CMsg.buf) ) - { - return(PTR_ERR(I2CMsg.buf)); - } - if (!(I2CMsg.flags & I2C_M_RD)) - { - print_hex_dump(KERN_ERR, "sdl_control_ioctl: w:", DUMP_PREFIX_NONE, 16, 1, I2CMsg.buf, I2CMsg.len, true); -#ifdef MIMIC_ENGINE_RESPONSE - if (I2CMsg.buf[0] == 0x77 || I2CMsg.buf[0] == 0x58) - { - mimic_cmd_response = 1; - last_cmd_op_code = I2CMsg.buf[0]; - kfree(I2CMsg.buf); - return I2CMsg.len; - } -#endif - } - else - { -#ifdef MIMIC_ENGINE_RESPONSE - if (mimic_cmd_response) - { - mimic_cmd_response = 0; - I2CMsg.buf[0] = last_cmd_op_code; - I2CMsg.buf[1] = 0x80; - I2CMsg.len = 2; - if ( copy_to_user(pData, I2CMsg.buf, I2CMsg.len) ) - { - lRetVal = -EFAULT; - } - kfree(I2CMsg.buf); - return I2CMsg.len; - } -#endif - } - // Perform the I2C transfer - lRetVal = i2c_transfer(pClient->adapter, &I2CMsg, 1); - if ( (lRetVal >= 0) && (I2CMsg.flags & I2C_M_RD) ) - { - print_hex_dump(KERN_ERR, "sdl_control_ioctl: r:", DUMP_PREFIX_NONE, 16, 1, I2CMsg.buf, I2CMsg.len, true); - // Successful read, copy data to user-space - if ( copy_to_user(pData, I2CMsg.buf, I2CMsg.len) ) - { - lRetVal = -EFAULT; - } - } - kfree(I2CMsg.buf); - return lRetVal; -} - -static int se4750_mipi_misc_release(struct inode* pINode, struct file* pFile){ -#if 0 - int rc = 0; - - if (g_s_ctrl) - { - rc = cam_sensor_power_down(g_s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "power up failed"); - //goto free_power_settings; - } - } -#endif - //is_opened_by_SDL = 0; - pr_err("SDL open %s:%d is_opened_by_SDL=%d\n",__func__,__LINE__, is_opened_by_SDL); - - return 0; -} - - -struct file_operations se4750_mipi_misc_fops ={ - .owner = THIS_MODULE, - .unlocked_ioctl = se4750_mipi_misc_ioctl, - .open = se4750_mipi_misc_open, - .release = se4750_mipi_misc_release, -}; - - -unsigned char cmdbuf[4] = {0x70,0x00,0x00,0x90}; -char respbuf[24] = {0}; -/* MODIFIED-END by yixiang.wu,BUG-10277816*/ - int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) { int rc = 0; @@ -1227,35 +754,6 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) return -EINVAL; } - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - if(slave_info->sensor_id == 0x80){ - //match id - memset(respbuf,0,24*sizeof(char)); - rc = se4750_mipi_i2c_txdata(s_ctrl->io_master_info.client,cmdbuf,4); - msleep(10); - rc = se4750_mipi_i2c_rxdata(s_ctrl->io_master_info.client,respbuf,24); - if((respbuf[0] == 0x70 && respbuf[1] == 0x80 ) && (respbuf[8] == 0x32 && respbuf[9] == 0x30)){ - CAM_ERR(CAM_SENSOR,"in %s : se4750 match id success !",__func__); - chipid = 0x4720; - if(!is_zebra_misc_device_exist){ - misc_register(&se4750_mipi_misc_device); - g_s_ctrl = s_ctrl; - dev_set_drvdata(se4750_mipi_misc_device.this_device, s_ctrl->io_master_info.client); - is_zebra_misc_device_exist =true; - } - return rc; - }else{ - CAM_ERR(CAM_SENSOR,"in %s : se4720 match id failed,respbuf[0] = 0x%x,[1] = 0x%x,[8] = 0x%x,[9] = 0x%x !",__func__, - respbuf[0],respbuf[1],respbuf[8],respbuf[9]); - chipid = 0x0; - return -ENODEV; - } - CAM_ERR(CAM_SENSOR, "yanhao read id: 0x%x expected id 0x%x:", - chipid, slave_info->sensor_id); - return rc; - } - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ - rc = camera_io_dev_read( &(s_ctrl->io_master_info), slave_info->sensor_id_reg_addr, @@ -1263,7 +761,7 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->sensor_probe_addr_type, s_ctrl->sensor_probe_data_type); - CAM_WARN(CAM_SENSOR, "yanhao read id: 0x%x expected id 0x%x:", // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 + CAM_DBG(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", // MODIFIED by yixiang.wu, 2021-01-22,BUG-10277816 chipid, slave_info->sensor_id); if (cam_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) { @@ -1294,7 +792,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } } - CAM_ERR(CAM_SENSOR, "wuyq:cmd->op_code 0x%x",cmd->op_code); // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 mutex_lock(&(s_ctrl->cam_sensor_mutex)); switch (cmd->op_code) { case CAM_SENSOR_PROBE_CMD: { @@ -1445,14 +942,12 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = -EFAULT; goto release_mutex; } - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - if (!is_opened_by_SDL) - { - rc = cam_sensor_power_up(s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); - goto release_mutex; - } + + /* MODIFIED-BEGIN by yixiang.wu, 2021-01-22,BUG-10277816*/ + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); + goto release_mutex; /* MODIFIED-END by yixiang.wu,BUG-10277816*/ } @@ -1483,13 +978,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - if (is_opened_by_SDL) - { - is_opened_by_SDL = 0; // se4750_mipi_misc_release is called before CAM_STOP_DEV is called, so clear is_opened_by_SDL flag here. - CAM_INFO(CAM_SENSOR,"Set is_opened_by_SDL = %d", is_opened_by_SDL); - } - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); @@ -1546,10 +1034,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - if(s_ctrl->sensordata->slave_info.sensor_id != 0x80){ - if (s_ctrl->i2c_data.streamon_settings.is_settings_valid && - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ + if (s_ctrl->i2c_data.streamon_settings.is_settings_valid && // MODIFIED by yixiang.wu, 2021-01-22,BUG-10277816 (s_ctrl->i2c_data.streamon_settings.request_id == 0)) { rc = cam_sensor_apply_settings(s_ctrl, 0, CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON); @@ -1558,22 +1043,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, "cannot apply streamon settings"); goto release_mutex; } - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - } - }else{ - //yanhao stream on - #ifndef MIMIC_ENGINE_RESPONSE - if (is_opened_by_SDL) //paul don't send commands if it's opened by SDL - { - //msleep(100); - CAM_INFO(CAM_SENSOR, "CAM_START_DEV with is_opened_by_SDL = %d", is_opened_by_SDL); - } - else - #endif - rc = streamOn_cmds(s_ctrl->io_master_info.client); - } - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ - + } // MODIFIED by yixiang.wu, 2021-01-22,BUG-10277816 s_ctrl->sensor_state = CAM_SENSOR_START; CAM_INFO(CAM_SENSOR, "CAM_START_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", @@ -1589,7 +1059,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->sensor_state); goto release_mutex; } - if(s_ctrl->sensordata->slave_info.sensor_id != 0x80){ // MODIFIED by yixiang.wu, 2021-01-05,BUG-10277816 + if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid && (s_ctrl->i2c_data.streamoff_settings.request_id == 0)) { rc = cam_sensor_apply_settings(s_ctrl, 0, @@ -1599,21 +1069,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, "cannot apply streamoff settings"); } } - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - }else{ - #if 0 //// To sync with ISP/VFE timing, we need to send ACQ_off command here. Cannot send it in SDL via /dev/sdl_control. - //#ifndef MIMIC_ENGINE_RESPONSE - if (is_opened_by_SDL) //paul don't send commands if it's opened by SDL - { - //msleep(100); - CAM_INFO(CAM_SENSOR, "CAM_START_DEV with is_opened_by_SDL = %d", is_opened_by_SDL); - } - else - #endif - //yanhao stream off - rc = streamOff_cmds(s_ctrl->io_master_info.client); - } - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ cam_sensor_release_per_frame_resource(s_ctrl); s_ctrl->last_flush_req = 0; @@ -1630,14 +1085,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); goto release_mutex; } - - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - if(s_ctrl->sensordata->slave_info.sensor_id == 0x80){ - rc = 0; - break; - } - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ - if (s_ctrl->i2c_data.init_settings.is_settings_valid && (s_ctrl->i2c_data.init_settings.request_id == 0)) { @@ -2038,11 +1485,6 @@ int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) } CAM_DBG(CAM_REQ, " Sensor update req id: %lld", apply->request_id); trace_cam_apply_req("Sensor", apply->request_id); - /* MODIFIED-BEGIN by yixiang.wu, 2021-01-05,BUG-10277816*/ - if (s_ctrl->sensordata->slave_info.sensor_id == 0x80){ - return 0; - } - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ mutex_lock(&(s_ctrl->cam_sensor_mutex)); rc = cam_sensor_apply_settings(s_ctrl, apply->request_id, CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE); -- GitLab From baf3d4ab70b68dadca16bcf94409b6a638d19bb8 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 22 Mar 2021 16:31:17 +0800 Subject: [PATCH 374/410] [ALM:10872982] [FP4]:imx576 ,imx582 uw power on &&&%%%comment:[FP4]:imx576 ,imx582 uw power on &&&%%%bug number:10872982 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:camera function &&&%%%Solution:camera power on &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:yes Change-Id: Iddca184662b4cc5569aa1f63ebd32b82383fd6b6 --- drivers/cam_utils/cam_soc_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index 69f748b80661..3272390c118d 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -30,7 +30,7 @@ #define CAM_SOC_MAX_BASE CAM_SOC_MAX_BLOCK /* maximum number of device regulator */ -#define CAM_SOC_MAX_REGULATOR 5 +#define CAM_SOC_MAX_REGULATOR 10 /* maximum number of device clock */ #define CAM_SOC_MAX_CLK 32 -- GitLab From abb14e89e379e2f7b79485a8575aef1426d92a92 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Fri, 21 May 2021 16:12:04 +0800 Subject: [PATCH 375/410] [ALM:10872982] [FP4]:ois gyro offset calibration` &&&%%%comment:[FP4]:ois gyro offset calibration &&&%%%bug number:10872982 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 355 ++++++++++++++++++ .../cam_sensor_module/cam_ois/cam_ois_core.h | 4 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 10 + 3 files changed, 369 insertions(+) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 4520139fa001..a3229396eb03 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -15,6 +15,20 @@ #include "cam_common_util.h" #include "cam_packet_util.h" +typedef struct REGSETTING{ + uint16_t reg ; + uint16_t val ; +}REGSETTING ; + +static int32_t gyro_offset_X = 0; +static int32_t gyro_offset_Y = 0; + +static int32_t gyro_offset_X_check = -1; +static int32_t gyro_offset_Y_check = -1; + +static int calibration_status = 0; + + int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) { @@ -291,6 +305,277 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, return rc; } +static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + uint32_t fw_size; + uint32_t cmd_adress=0,cmd_data=0; + + const REGSETTING cml_ois_gyro_calibration[]= { + //gyro cali mode + {0x9b2c ,0x0002} ,//0[write]enter calibration mode + {0x9b28 ,0x2000} ,//1[read]check mode + {0x9b2a ,0x0001} ,//2[write] + {0x9b28 ,0x2001} ,//3[read]calibration done + {0x9fb0 ,0x8001} ,//4[read]gyro offset calibratin result + {0x9fb6 ,0x0000} ,//5[read]gyro offset X + {0x9fb8 ,0x0000} ,//6[read]gyro offset Y + //save mode + {0x9b2c ,0x0006} ,//7[write]store mode + {0x9b28 ,0x6000} ,//8[read] + {0x0220 ,0xc0d4} ,//9[write]code pt off + {0x9b2a ,0x0001} ,//10[write] + {0x9b28 ,0x6001} ,//11[read]store done + {0x0220 ,0x0000} ,//12[write]code pt on + }; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + total_bytes = sizeof(cml_ois_gyro_calibration[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return -ENOMEM; + } + //[Begin]enter gyro cali mode + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[0].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[0].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0002"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write {0x9b2c ,0x0002} failed %d", rc); + + } + else + { + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[5].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9fb6 -> 0x%x",cmd_data); + + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[6].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9fb8 -> 0x%x",cmd_data); + + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[1].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read {0x9b28 ,0x2000} failed: %d",rc); + } + else + { + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + if (cmd_data == cml_ois_gyro_calibration[1].val) + { + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[2].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[2].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); + mdelay(50); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0001} failed %d", rc); + } + else + { + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[3].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read {0x9b28 ,0x2001} failed: %d",rc); + } + else + { + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + if (cmd_data == cml_ois_gyro_calibration[3].val) + { + CAM_ERR(CAM_OIS, "read {0x9b28 ,0x2001} success"); + cmd_adress = cml_ois_gyro_calibration[4].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read {0x9fb0 ,0x8001} failed: %d",rc); + } + else + { + CAM_ERR(CAM_OIS,"read 0x9fb0 -> 0x%x",cmd_data); + if (cmd_data == cml_ois_gyro_calibration[4].val) + CAM_ERR(CAM_OIS,"read 0x9fb0 -> 0x%x",cmd_data); + } + } + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[5].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read 0x9fb6 failed: %d",rc); + } + else + { + CAM_ERR(CAM_OIS,"read 0x9fb6 -> 0x%x",cmd_data); + gyro_offset_X = cmd_data; + } + + + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[6].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read 0x9fb8 failed: %d",rc); + } + else + { + CAM_ERR(CAM_OIS,"read 0x9fb8 -> 0x%x",cmd_data); + gyro_offset_Y = cmd_data; + } + + + } + } + } + else + { + CAM_ERR(CAM_OIS,"ois read value nok"); + } + } + + } + CAM_ERR(CAM_OIS,"ois calibration op end"); + //[End]enter gyro cali mode + + //[Begin]enter save mode + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[7].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[7].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0006"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0001} failed %d", rc); + } + + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[8].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[9].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[9].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0220 -> 0xc0d4"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write 0x0220 -> 0xc0d4 failed %d", rc); + } + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[10].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[10].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001 failed %d", rc); + } + + mdelay(100); + cmd_adress = cml_ois_gyro_calibration[11].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[12].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[12].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0220 -> 0x0000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write 0x0220 -> 0x0000 failed %d", rc); + } + CAM_ERR(CAM_OIS,"ois save gyro offset end"); + //[End]enter save mode + + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); + page = NULL; + + return rc; +} + + +static int cam_ois_gyro_offset_check(struct cam_ois_ctrl_t *o_ctrl) +{ + int32_t rc = 0; + uint32_t cmd_adress=0,cmd_data=0; + + const REGSETTING cml_ois_gyro_offset_check[]= { + {0x9fb6 ,0x0000} ,//0[read]gyro offset X + {0x9fb8 ,0x0000} ,//1[read]gyro offset Y + }; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + + mdelay(50); + cmd_adress = cml_ois_gyro_offset_check[0].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read 0x9fb6 failed: %d",rc); + } + else + { + CAM_ERR(CAM_OIS,"read 0x9fb6 -> 0x%x",cmd_data); + gyro_offset_X_check = cmd_data; + } + + + mdelay(50); + cmd_adress = cml_ois_gyro_offset_check[1].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read 0x9fb8 failed: %d",rc); + } + else + { + CAM_ERR(CAM_OIS,"read 0x9fb8 -> 0x%x",cmd_data); + gyro_offset_Y_check = cmd_data; + } + + return rc; +} + + static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) { uint16_t total_bytes = 0; @@ -418,6 +703,76 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) * * Returns success or failure */ + +ssize_t ois_gyro_cali_data_show(struct device *dev, struct device_attribute *attr, char *buf){ + + return sprintf(buf, "%u\n", calibration_status); + +} + +ssize_t ois_gyro_cali_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ + + struct cam_ois_ctrl_t *o_ctrl = NULL; + char cmd_buf[32]; + uint32_t cmd_adress=0,cmd_data=0; + char flag; + int gyro_cali_flag=0,check_gyro_offset=0; + int rc = 0; + + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + memset(cmd_buf,0,32); + o_ctrl = platform_get_drvdata(pdev); + + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return count; + } + //cpy user cmd to kernel 0x:0x:r 0x:0x:w + strcpy(cmd_buf,buf); + sscanf(cmd_buf,"%x:%x:%c",&cmd_adress,&cmd_data,&flag); + + if(flag=='w'){ + CAM_ERR(CAM_OIS, "ois write:adress=0x%x,data=0x%x",cmd_adress,cmd_data); + if ((cmd_adress == 0x9b2c) && (cmd_data == 0x0002))//gyro offset calibration mode + { + gyro_cali_flag = 1; + } + else + { + gyro_cali_flag = 0; + } + if (gyro_cali_flag) + { + rc = cam_ois_gyro_calibration(o_ctrl); + } + CAM_ERR(CAM_OIS, "cam_ois_gyro_calibration end"); + } + + if (flag=='r') + { + CAM_ERR(CAM_OIS, "ois read:adress1=0x%x,adress2=0x%x",cmd_adress,cmd_data); + if ((cmd_adress == 0x9fb6) && (cmd_data == 0x9fb8))//check gyro_offset + { + check_gyro_offset = 1; + } + else + { + check_gyro_offset = 0; + } + if (check_gyro_offset) + { + rc = cam_ois_gyro_offset_check(o_ctrl); + } + CAM_ERR(CAM_OIS, "cam_ois_gyro_calibration end"); + } + if ((gyro_offset_X == gyro_offset_X_check) && (gyro_offset_Y == gyro_offset_Y_check)) + calibration_status = 1; + + return count; +} + + static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) { int32_t rc = 0; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index 33abe8b75c72..31d514a61558 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -30,5 +30,9 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *e_ctrl, void *arg); */ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl); +ssize_t ois_gyro_cali_data_show(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t ois_gyro_cali_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); + + #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 6de45da89c44..7f4be120cb5c 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -173,6 +173,9 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) return rc; } +DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); + + static int cam_ois_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -319,6 +322,9 @@ static int32_t cam_ois_platform_driver_probe( if (rc) goto free_soc; + rc = device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data); + CAM_ERR(CAM_OIS, "creat ois calibration data sys node rc=%d", rc); + rc = cam_ois_update_i2c_info(o_ctrl, &soc_private->i2c_info); if (rc) { CAM_ERR(CAM_OIS, "failed: to update i2c info rc %d", rc); @@ -356,6 +362,10 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) return -EINVAL; } + device_remove_file(&pdev->dev, &dev_attr_ois_gyro_cali_data); + CAM_ERR(CAM_OIS, "remove calibration node"); + + CAM_INFO(CAM_OIS, "platform driver remove invoked"); soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) -- GitLab From c3b5455884e4be91265d1e9193e857e192475d74 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Tue, 1 Jun 2021 20:22:11 +0800 Subject: [PATCH 376/410] [ALM:10872982] [FP4]:ois position data &&&%%%comment:[FP4]:ois position data &&&%%%bug number:10872982 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 59 +++++++++++++++++++ .../cam_sensor_module/cam_ois/cam_ois_core.h | 3 +- .../cam_sensor_module/cam_ois/cam_ois_dev.c | 13 ++-- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index a3229396eb03..1e1ae32e7054 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -703,6 +703,65 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) * * Returns success or failure */ +static char ois_read_cmd_buf[32]; + +ssize_t ois_position_data_show(struct device *dev, struct device_attribute *attr, char *buf){ + + strcpy(buf,ois_read_cmd_buf); + return sizeof(ois_read_cmd_buf); +} + +ssize_t ois_position_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ + + struct cam_ois_ctrl_t *o_ctrl = NULL; + int32_t rc = 0; + char cmd_buf[5]; + int32_t flag; + uint32_t cmd_adress=0,cmd_data=0; + uint32_t position_data[5]; + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + memset(cmd_buf,0,5); + memset(ois_read_cmd_buf,0,sizeof(ois_read_cmd_buf)); + o_ctrl = platform_get_drvdata(pdev); + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return count; + } + strcpy(cmd_buf,buf); + sscanf(cmd_buf,"%d",&flag); + + if (flag == 1) { + cmd_adress = 0x9CB8;//POSITION_ESTIMATE_X + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois Failed: random read I2C settings: %d",rc); + return count; + } + else{ + CAM_DBG(CAM_OIS,"ois read::address: 0x%x reg_data: 0x%x",cmd_adress,cmd_data); + position_data[0] = cmd_data; + } + + cmd_adress = 0x9CBA;//POSITION_ESTIMATE_Y + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois Failed: random read I2C settings: %d",rc); + return count; + } + else{ + CAM_DBG(CAM_OIS,"ois read::address: 0x%x reg_data: 0x%x",cmd_adress,cmd_data); + position_data[1] = cmd_data; + } + sprintf(ois_read_cmd_buf,"%.4x%.4x\n",position_data[0],position_data[1]); + + CAM_DBG(CAM_OIS,"ois kernel read::position_X 0x%x,position_Y 0x%x",position_data[0],position_data[1]); + } + + + return count; +} + ssize_t ois_gyro_cali_data_show(struct device *dev, struct device_attribute *attr, char *buf){ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index 31d514a61558..458edb7304cd 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -32,7 +32,8 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl); ssize_t ois_gyro_cali_data_show(struct device *dev, struct device_attribute *attr, char *buf); ssize_t ois_gyro_cali_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); - +ssize_t ois_position_data_show(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t ois_position_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 7f4be120cb5c..059002052fbb 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -174,7 +174,7 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) } DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); - +DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_store); static int cam_ois_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -322,8 +322,11 @@ static int32_t cam_ois_platform_driver_probe( if (rc) goto free_soc; - rc = device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data); - CAM_ERR(CAM_OIS, "creat ois calibration data sys node rc=%d", rc); + if ((device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data)) || + (device_create_file(&pdev->dev, &dev_attr_ois_position_data))) + { + CAM_ERR(CAM_OIS, "creat ois device_create_file failed rc=%d", rc); + } rc = cam_ois_update_i2c_info(o_ctrl, &soc_private->i2c_info); if (rc) { @@ -364,7 +367,9 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_ois_gyro_cali_data); CAM_ERR(CAM_OIS, "remove calibration node"); - + + device_remove_file(&pdev->dev, &dev_attr_ois_position_data); + CAM_ERR(CAM_OIS, "remove position node"); CAM_INFO(CAM_OIS, "platform driver remove invoked"); soc_info = &o_ctrl->soc_info; -- GitLab From 4700d67a4823fa9abddf1d577caa0e27d50daeb3 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Sat, 5 Jun 2021 17:41:43 +0800 Subject: [PATCH 377/410] [ALM:10872982] [FP4]:ois status node &&&%%%comment:[FP4]:ois status node &&&%%%bug number:10872982 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 217 +++++++++++++++++- .../cam_sensor_module/cam_ois/cam_ois_core.h | 3 +- .../cam_sensor_module/cam_ois/cam_ois_dev.c | 12 +- 3 files changed, 217 insertions(+), 15 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 1e1ae32e7054..acadc1120e16 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -27,7 +27,7 @@ static int32_t gyro_offset_X_check = -1; static int32_t gyro_offset_Y_check = -1; static int calibration_status = 0; - +static int ois_status = 0; int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -696,13 +696,147 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) return rc; } -/** - * cam_ois_pkt_parse - Parse csl packet - * @o_ctrl: ctrl structure - * @arg: Camera control command argument - * - * Returns success or failure - */ +const REGSETTING cml_ois_control[]= { + {0x9b2c ,0x0001} , + {0x9b2a ,0x0001} , + {0x9b28 ,0x1001} , + {0x9b2a ,0x0003} ,//enter idle low power mode + {0x9b28 ,0x1003} , +}; + +static int cam_cml_ois_enable(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + uint32_t fw_size; + uint32_t cmd_adress=0,cmd_data=0; + + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + total_bytes = sizeof(cml_ois_control[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return -ENOMEM; + } + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[0].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[0].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write {0x9b2c ,0x0001} failed %d", rc); + + } + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[1].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[1].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0001} failed %d", rc); + } + + mdelay(50); + cmd_adress = cml_ois_control[2].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + + if (cmd_data == cml_ois_control[2].val) + rc = 1; + else + rc = 0; + + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); + page = NULL; + + return rc; +} + +static int cam_cml_ois_disable(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + uint32_t fw_size; + uint32_t cmd_adress=0,cmd_data=0; + + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + total_bytes = sizeof(cml_ois_control[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return -ENOMEM; + } + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[0].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[0].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write {0x9b2c ,0x0001} failed %d", rc); + + } + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[3].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[3].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0000} failed %d", rc); + } + + mdelay(50); + cmd_adress = cml_ois_control[4].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + + if (cmd_data == cml_ois_control[4].val) + rc = 1; + else + rc = 0; + + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); + page = NULL; + + return rc; +} + + static char ois_read_cmd_buf[32]; ssize_t ois_position_data_show(struct device *dev, struct device_attribute *attr, char *buf){ @@ -762,6 +896,65 @@ ssize_t ois_position_data_store(struct device *dev, struct device_attribute *at return count; } +ssize_t ois_status_show(struct device *dev, struct device_attribute *attr, char *buf){ + + return sprintf(buf, "%u\n", ois_status); + +} + +ssize_t ois_status_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ + + struct cam_ois_ctrl_t *o_ctrl = NULL; + char cmd_buf[32]; + uint32_t cmd_adress=0,cmd_data=0; + char flag; + int rc = 0; + + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + memset(cmd_buf,0,32); + o_ctrl = platform_get_drvdata(pdev); + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return count; + } + //cpy user cmd to kernel 0x:0x:r 0x:0x:w + strcpy(cmd_buf,buf); + sscanf(cmd_buf,"%x:%x:%c",&cmd_adress,&cmd_data,&flag); + +/************* OIS enable BEGIN ******************/ + if ((flag == 'w') && (cmd_adress == 0x9b2a) && (cmd_data == 0x0001)) + { + rc = cam_cml_ois_enable(o_ctrl); + if (rc == 1){ + ois_status = 1; + CAM_ERR(CAM_OIS, "ois enable success"); + } + else { + ois_status = 0; + CAM_ERR(CAM_OIS, "ois enable failed"); + } + } +/************* OIS enable END ******************/ + +/************* OIS disable BEGIN ******************/ + if ((flag == 'w') && (cmd_adress == 0x9b2a) && (cmd_data == 0x0003)) + { + rc = cam_cml_ois_disable(o_ctrl); + if (rc == 1) { + ois_status = 2; + CAM_ERR(CAM_OIS, "ois disable success"); + } + else { + ois_status = 0; + CAM_ERR(CAM_OIS, "ois disable failed"); + } + } +/************* OIS disable BEGIN ******************/ + + return count; +} + ssize_t ois_gyro_cali_data_show(struct device *dev, struct device_attribute *attr, char *buf){ @@ -831,7 +1024,13 @@ ssize_t ois_gyro_cali_data_store(struct device *dev, struct device_attribute *a return count; } - +/** + * cam_ois_pkt_parse - Parse csl packet + * @o_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) { int32_t rc = 0; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index 458edb7304cd..02bb381d2062 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -34,6 +34,7 @@ ssize_t ois_gyro_cali_data_show(struct device *dev, struct device_attribute *att ssize_t ois_gyro_cali_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_position_data_show(struct device *dev, struct device_attribute *attr, char *buf); ssize_t ois_position_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); - +ssize_t ois_status_show(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t ois_status_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 059002052fbb..04475ce68672 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -175,6 +175,8 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_store); +DEVICE_ATTR(ois_status, 0664, ois_status_show, ois_status_store); + static int cam_ois_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -323,7 +325,8 @@ static int32_t cam_ois_platform_driver_probe( goto free_soc; if ((device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data)) || - (device_create_file(&pdev->dev, &dev_attr_ois_position_data))) + (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || + (device_create_file(&pdev->dev, &dev_attr_ois_status))) { CAM_ERR(CAM_OIS, "creat ois device_create_file failed rc=%d", rc); } @@ -366,11 +369,10 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) } device_remove_file(&pdev->dev, &dev_attr_ois_gyro_cali_data); - CAM_ERR(CAM_OIS, "remove calibration node"); - + device_remove_file(&pdev->dev, &dev_attr_ois_status); device_remove_file(&pdev->dev, &dev_attr_ois_position_data); - CAM_ERR(CAM_OIS, "remove position node"); - + CAM_ERR(CAM_OIS, " device_remove_file node"); + CAM_INFO(CAM_OIS, "platform driver remove invoked"); soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) -- GitLab From 67cae93f950d05c875ffc2f8a6083c776d27ba5e Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 7 Jun 2021 17:01:07 +0800 Subject: [PATCH 378/410] [ALM:10872982] [FP4]:ois init status &&&%%%comment:[FP4]:ois status node &&&%%%bug number:10872982 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index acadc1120e16..fc0349c46647 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -320,7 +320,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) {0x9b28 ,0x2000} ,//1[read]check mode {0x9b2a ,0x0001} ,//2[write] {0x9b28 ,0x2001} ,//3[read]calibration done - {0x9fb0 ,0x8001} ,//4[read]gyro offset calibratin result + {0x9fb0 ,0x8001} ,//4[read]gyro offset calibration result {0x9fb6 ,0x0000} ,//5[read]gyro offset X {0x9fb8 ,0x0000} ,//6[read]gyro offset Y //save mode @@ -711,7 +711,6 @@ static int cam_cml_ois_enable(struct cam_ois_ctrl_t *o_ctrl) struct cam_sensor_i2c_reg_setting i2c_reg_setting; struct page *page = NULL; uint32_t fw_size; - uint32_t cmd_adress=0,cmd_data=0; if (!o_ctrl) { @@ -753,16 +752,7 @@ static int cam_cml_ois_enable(struct cam_ois_ctrl_t *o_ctrl) if (rc < 0) { CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0001} failed %d", rc); } - mdelay(50); - cmd_adress = cml_ois_control[2].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); - - if (cmd_data == cml_ois_control[2].val) - rc = 1; - else - rc = 0; cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); page = NULL; @@ -777,7 +767,6 @@ static int cam_cml_ois_disable(struct cam_ois_ctrl_t *o_ctrl) struct cam_sensor_i2c_reg_setting i2c_reg_setting; struct page *page = NULL; uint32_t fw_size; - uint32_t cmd_adress=0,cmd_data=0; if (!o_ctrl) { @@ -819,16 +808,7 @@ static int cam_cml_ois_disable(struct cam_ois_ctrl_t *o_ctrl) if (rc < 0) { CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0000} failed %d", rc); } - mdelay(50); - cmd_adress = cml_ois_control[4].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); - - if (cmd_data == cml_ois_control[4].val) - rc = 1; - else - rc = 0; cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); page = NULL; @@ -897,6 +877,29 @@ ssize_t ois_position_data_store(struct device *dev, struct device_attribute *at } ssize_t ois_status_show(struct device *dev, struct device_attribute *attr, char *buf){ + + struct cam_ois_ctrl_t *o_ctrl = NULL; + uint32_t cmd_adress=0,cmd_data=0; + int rc = 0; + + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + o_ctrl = platform_get_drvdata(pdev); + + cmd_adress = cml_ois_control[2].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + + if (cmd_data == cml_ois_control[2].val) { + ois_status = 1; + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + } + else if (cmd_data == cml_ois_control[4].val) { + ois_status = 2; + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + } + else { + ois_status = 0; + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + } return sprintf(buf, "%u\n", ois_status); @@ -908,7 +911,6 @@ ssize_t ois_status_store(struct device *dev, struct device_attribute *attr, con char cmd_buf[32]; uint32_t cmd_adress=0,cmd_data=0; char flag; - int rc = 0; struct platform_device *pdev = container_of(dev, struct platform_device, dev); memset(cmd_buf,0,32); @@ -925,30 +927,15 @@ ssize_t ois_status_store(struct device *dev, struct device_attribute *attr, con /************* OIS enable BEGIN ******************/ if ((flag == 'w') && (cmd_adress == 0x9b2a) && (cmd_data == 0x0001)) { - rc = cam_cml_ois_enable(o_ctrl); - if (rc == 1){ - ois_status = 1; - CAM_ERR(CAM_OIS, "ois enable success"); - } - else { - ois_status = 0; - CAM_ERR(CAM_OIS, "ois enable failed"); - } + cam_cml_ois_enable(o_ctrl); + } /************* OIS enable END ******************/ /************* OIS disable BEGIN ******************/ if ((flag == 'w') && (cmd_adress == 0x9b2a) && (cmd_data == 0x0003)) { - rc = cam_cml_ois_disable(o_ctrl); - if (rc == 1) { - ois_status = 2; - CAM_ERR(CAM_OIS, "ois disable success"); - } - else { - ois_status = 0; - CAM_ERR(CAM_OIS, "ois disable failed"); - } + cam_cml_ois_disable(o_ctrl); } /************* OIS disable BEGIN ******************/ -- GitLab From b822d424984009841d0558c45aebec964983a253 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Sat, 12 Jun 2021 10:18:05 +0800 Subject: [PATCH 379/410] [ALM:10872982] [FP4]:camera module info &&&%%%comment:[FP4]:camera module info &&&%%%bug number:10872982 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor/cam_sensor_core.c | 23 ++++++ .../cam_sensor/cam_sensor_dev.c | 78 +++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 9e2381b436dd..b8f2d87955d4 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -772,6 +772,10 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) return rc; } +extern char main_camera_status[32]; +extern char aux_camera_status[32]; +extern char front_camera_status[32]; + int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, void *arg) { @@ -878,6 +882,25 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->sensordata->slave_info.sensor_id); cam_sensor_free_power_reg_rsc(s_ctrl); + + if (s_ctrl->soc_info.index == 0 && s_ctrl->sensordata->slave_info.sensor_id == 0x582) + { + CAM_INFO(CAM_SENSOR, "match SONY_imx582_sma"); + snprintf(main_camera_status, sizeof(main_camera_status), "SONY_IMX582_SMA"); + } + + if (s_ctrl->soc_info.index == 2 && s_ctrl->sensordata->slave_info.sensor_id == 0x576) + { + CAM_INFO(CAM_SENSOR, "match SONY_imx576"); + snprintf(front_camera_status, sizeof(front_camera_status), "SONY_IMX576"); + } + + if (s_ctrl->soc_info.index == 1 && s_ctrl->sensordata->slave_info.sensor_id == 0x582) + { + CAM_INFO(CAM_SENSOR, "match SONY_imx582_UW"); + snprintf(aux_camera_status, sizeof(aux_camera_status), "SONY_IMX582_UW"); + } + rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index ed6b17b7bea3..f6281d0028ab 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -402,6 +402,82 @@ static struct i2c_driver cam_sensor_driver_i2c = { }, }; +char main_camera_status[32] = {0}; +char aux_camera_status[32] = {0}; +char front_camera_status[32] = {0}; + +static ssize_t main_camera_show (struct device* dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", main_camera_status); +} + +static DEVICE_ATTR(camera_main, S_IRUGO, + main_camera_show, + NULL); + +static ssize_t aux_camera_show (struct device* dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", aux_camera_status); +} + +static DEVICE_ATTR(camera_aux, S_IRUGO, + aux_camera_show, + NULL); + +static ssize_t front_camera_show (struct device* dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", front_camera_status); +} + +static DEVICE_ATTR(camera_front, S_IRUGO, + front_camera_show, + NULL); + +struct kobject *device_sensor_module_kobj = NULL; + + +static int sensor_module_sysfs_init(void) +{ + int rc = 0; + + device_sensor_module_kobj = kobject_create_and_add("sensor_module", NULL); + if (device_sensor_module_kobj == NULL) { + pr_err("kobject_creat_and_add(/sys/sensor_module/) failed!"); + return -ENOMEM; + } + + rc = sysfs_create_file(device_sensor_module_kobj,&dev_attr_camera_main.attr); + if (rc) { + pr_err("sysfs_creat_file(/sys/sensor_module/camera_main) failed!"); + goto destroy_kobj; + } + + rc = sysfs_create_file(device_sensor_module_kobj, &dev_attr_camera_aux.attr); + if (rc) { + pr_err("sysfs_create_file('/sys/sensor_module/camera_aux') failed"); + goto destroy_kobj; + } + + rc = sysfs_create_file(device_sensor_module_kobj, &dev_attr_camera_front.attr); + if (rc) { + pr_err("sysfs_create_file('/sys/sensor_module/camera_front') failed"); + goto destroy_kobj; + } + + return rc; + + destroy_kobj: + kobject_put(device_sensor_module_kobj); + return rc; + +} + static int __init cam_sensor_driver_init(void) { int32_t rc = 0; @@ -413,6 +489,8 @@ static int __init cam_sensor_driver_init(void) return rc; } + rc = sensor_module_sysfs_init(); + rc = i2c_add_driver(&cam_sensor_driver_i2c); if (rc) CAM_ERR(CAM_SENSOR, "i2c_add_driver failed rc = %d", rc); -- GitLab From df408b0efe70d23c230890fac65ec705f8662a05 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Tue, 29 Jun 2021 15:21:33 +0800 Subject: [PATCH 380/410] [ALM:10872982] [FP4]:Init setting must be done before ois offset calibration &&&%%%comment:[FP4]:Init setting must be done before ois offset calibration &&&%%%bug number:10872982 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:camera &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index fc0349c46647..585f5eebc410 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -330,6 +330,10 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) {0x9b2a ,0x0001} ,//10[write] {0x9b28 ,0x6001} ,//11[read]store done {0x0220 ,0x0000} ,//12[write]code pt on + + {0x0018 ,0x0001} ,//13[write] + {0x9E18 ,0x0002} ,//14[write] + {0x0024 ,0x0001} ,//15[write] }; if (!o_ctrl) { @@ -337,7 +341,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) return -EINVAL; } total_bytes = sizeof(cml_ois_gyro_calibration[0]); - + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; i2c_reg_setting.size = total_bytes; @@ -351,6 +355,29 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) } //[Begin]enter gyro cali mode i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[13].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[13].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[14].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[14].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9E18 -> 0x0002"); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[15].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[15].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); + + mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[0].reg; i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[0].val; i2c_reg_setting.reg_setting[0].delay = 1; -- GitLab From 4aec7802a1b0b11e2a4b2bd3c6e7ce7349cdd1fd Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 19 Jul 2021 19:56:20 +0800 Subject: [PATCH 381/410] [ALM:11087279] [FP4]:ois sr &&&%%%comment:[FP4]:ois sr &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 392 +++++++++++++----- .../cam_sensor_module/cam_ois/cam_ois_core.h | 4 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 12 +- 3 files changed, 302 insertions(+), 106 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 585f5eebc410..cb5573edd693 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -26,8 +26,12 @@ static int32_t gyro_offset_Y = 0; static int32_t gyro_offset_X_check = -1; static int32_t gyro_offset_Y_check = -1; +static int32_t ois_reg_value = -1; + + static int calibration_status = 0; static int ois_status = 0; +static int ois_init_status = 0; int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -361,6 +365,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[13].val; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); mdelay(50); @@ -368,6 +373,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[14].val; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); CAM_ERR(CAM_OIS, "write 0x9E18 -> 0x0002"); mdelay(50); @@ -375,6 +381,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[15].val; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); mdelay(50); @@ -384,110 +391,60 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0002"); rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); - if (rc < 0) { - CAM_ERR(CAM_OIS, "write {0x9b2c ,0x0002} failed %d", rc); - } - else - { - mdelay(50); - cmd_adress = cml_ois_gyro_calibration[5].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - CAM_ERR(CAM_OIS,"read 0x9fb6 -> 0x%x",cmd_data); + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[5].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9fb6 -> 0x%x",cmd_data); - mdelay(50); - cmd_adress = cml_ois_gyro_calibration[6].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - CAM_ERR(CAM_OIS,"read 0x9fb8 -> 0x%x",cmd_data); + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[6].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9fb8 -> 0x%x",cmd_data); - mdelay(50); - cmd_adress = cml_ois_gyro_calibration[1].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - if (rc < 0) - { - CAM_ERR(CAM_OIS, "read {0x9b28 ,0x2000} failed: %d",rc); - } - else - { - CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); - if (cmd_data == cml_ois_gyro_calibration[1].val) - { - i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[2].reg; - i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[2].val; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); - mdelay(50); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); - if (rc < 0) { - CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0001} failed %d", rc); - } - else - { - mdelay(50); - cmd_adress = cml_ois_gyro_calibration[3].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - if (rc < 0) - { - CAM_ERR(CAM_OIS, "read {0x9b28 ,0x2001} failed: %d",rc); - } - else - { - CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); - if (cmd_data == cml_ois_gyro_calibration[3].val) - { - CAM_ERR(CAM_OIS, "read {0x9b28 ,0x2001} success"); - cmd_adress = cml_ois_gyro_calibration[4].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - if (rc < 0) - { - CAM_ERR(CAM_OIS, "read {0x9fb0 ,0x8001} failed: %d",rc); - } - else - { - CAM_ERR(CAM_OIS,"read 0x9fb0 -> 0x%x",cmd_data); - if (cmd_data == cml_ois_gyro_calibration[4].val) - CAM_ERR(CAM_OIS,"read 0x9fb0 -> 0x%x",cmd_data); - } - } - mdelay(50); - cmd_adress = cml_ois_gyro_calibration[5].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - if (rc < 0) - { - CAM_ERR(CAM_OIS, "read 0x9fb6 failed: %d",rc); - } - else - { - CAM_ERR(CAM_OIS,"read 0x9fb6 -> 0x%x",cmd_data); - gyro_offset_X = cmd_data; - } + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[1].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[2].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[2].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + + mdelay(3000); + cmd_adress = cml_ois_gyro_calibration[3].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); + + if (cmd_data == cml_ois_gyro_calibration[3].val) + { + CAM_ERR(CAM_OIS, "read {0x9b28 ,0x2001} success"); + } + + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[4].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9fb0 -> 0x%x",cmd_data); + + mdelay(3000); + cmd_adress = cml_ois_gyro_calibration[5].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9fb6 -> 0x%x",cmd_data); + gyro_offset_X = cmd_data; - mdelay(50); - cmd_adress = cml_ois_gyro_calibration[6].reg; - rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - if (rc < 0) - { - CAM_ERR(CAM_OIS, "read 0x9fb8 failed: %d",rc); - } - else - { - CAM_ERR(CAM_OIS,"read 0x9fb8 -> 0x%x",cmd_data); - gyro_offset_Y = cmd_data; - } - + mdelay(50); + cmd_adress = cml_ois_gyro_calibration[6].reg; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS,"read 0x9fb8 -> 0x%x",cmd_data); + gyro_offset_Y = cmd_data; - } - } - } - else - { - CAM_ERR(CAM_OIS,"ois read value nok"); - } - } - } CAM_ERR(CAM_OIS,"ois calibration op end"); //[End]enter gyro cali mode @@ -531,7 +488,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001 failed %d", rc); } - mdelay(100); + mdelay(50); cmd_adress = cml_ois_gyro_calibration[11].reg; rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); CAM_ERR(CAM_OIS,"read 0x9b28 -> 0x%x",cmd_data); @@ -724,13 +681,136 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) } const REGSETTING cml_ois_control[]= { - {0x9b2c ,0x0001} , - {0x9b2a ,0x0001} , - {0x9b28 ,0x1001} , - {0x9b2a ,0x0003} ,//enter idle low power mode - {0x9b28 ,0x1003} , + {0x9b2c ,0x0001} ,//[0] + {0x9b2a ,0x0001} ,//[1] + {0x9b28 ,0x1001} ,//[2] + {0x9b2a ,0x0003} ,//[3]enter idle low power mode + {0x9b28 ,0x1003} ,//[4] + +//ois init before sr test + {0x0018 ,0x0001} ,//[5] + {0x9e18 ,0x0002} ,//[6] + {0x0024 ,0x0001} ,//[7] + {0x8820 ,0x0028} ,//[8] + {0x9b2a ,0x0002} ,//[9] }; +static int cam_ois_init(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + uint32_t fw_size; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + total_bytes = sizeof(cml_ois_control[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return -ENOMEM; + } + + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + +/************* OIS init BEGIN ******************/ + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[5].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[5].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[6].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[6].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9e18 -> 0x0002"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[7].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[7].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[8].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[8].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x8820 -> 0x0028"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[9].reg; + i2c_reg_setting.reg_setting[0].reg_data = cml_ois_control[9].val; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0002"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(50); + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); + page = NULL; + + return rc; +} + + +ssize_t ois_init_before_sr_test_show(struct device *dev, struct device_attribute *attr, char *buf){ + + return sprintf(buf, "%u\n", ois_init_status); + +} + +ssize_t ois_init_before_sr_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ + struct cam_ois_ctrl_t *o_ctrl = NULL; + char cmd_buf[32]; + uint32_t cmd_adress=0,cmd_data=0; + char flag; + int rc = 0; + + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + memset(cmd_buf,0,32); + o_ctrl = platform_get_drvdata(pdev); + + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return count; + } + //cpy user cmd to kernel 0x:0x:r 0x:0x:w + strcpy(cmd_buf,buf); + sscanf(cmd_buf,"%x:%x:%c",&cmd_adress,&cmd_data,&flag); + + if ((flag == 'w') && (cmd_adress == 0x0018) && (cmd_data == 0x0001)) + { + CAM_ERR(CAM_OIS, "prepare ois write:adress=0x%x,data=0x%x",cmd_adress,cmd_data); + rc = cam_ois_init(o_ctrl); + if (rc == 0) + ois_init_status = 1; + else + ois_init_status = 0; + } + + return count; +} + static int cam_cml_ois_enable(struct cam_ois_ctrl_t *o_ctrl) { uint16_t total_bytes = 0; @@ -843,6 +923,112 @@ static int cam_cml_ois_disable(struct cam_ois_ctrl_t *o_ctrl) return rc; } +ssize_t ois_reg_show(struct device *dev, struct device_attribute *attr, char *buf){ + + return sprintf(buf, "0x%x\n", ois_reg_value); + +} + +ssize_t ois_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ + + struct cam_ois_ctrl_t *o_ctrl = NULL; + char cmd_buf[32]; + uint32_t cmd_adress=0,cmd_data=0,read_data=0; + char flag; + int rc = 0; + int i = 0; + + uint16_t total_bytes = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + uint32_t fw_size; + + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + memset(cmd_buf,0,32); + o_ctrl = platform_get_drvdata(pdev); + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return count; + } + + total_bytes = sizeof(cml_ois_control[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return -ENOMEM; + } + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + + //cpy user cmd to kernel 0x:0x:r/w + strcpy(cmd_buf,buf); + sscanf(cmd_buf,"%x:%x:%c",&cmd_adress,&cmd_data,&flag); + + if (flag == 'r') + { + mdelay(50); + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&read_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) + { + CAM_ERR(CAM_OIS, "read %x failed: %d",cmd_adress,rc); + } + else + { + CAM_ERR(CAM_OIS,"read %x -> 0x%x",cmd_adress,read_data); + ois_reg_value = read_data; + } + mdelay(50); + } + else if (flag == 'w') + { + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cmd_adress; + i2c_reg_setting.reg_setting[0].reg_data = cmd_data; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x%x -> 0x%x",cmd_adress,cmd_data); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "write 0x%x -> 0x%x failed %d",cmd_adress,cmd_data,rc); + + } + mdelay(50); + } + else + { + if (flag == 'k') + { + while(i < 3000) + { + mdelay(10); + cmd_adress = 0x9bc0; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&read_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + pr_err("yjw cam_camera_cci_i2c_read_seq line%d: addr = 0x%x ,Data: 0x%x \n",__LINE__,cmd_adress,read_data); + cmd_adress = 0x9c00; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&read_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + pr_err("yjw cam_camera_cci_i2c_read_seq line%d: addr = 0x%x ,Data: 0x%x \n",__LINE__,cmd_adress,read_data); + cmd_adress = 0x9bc2; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&read_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + pr_err("yjw cam_camera_cci_i2c_read_seq line%d: addr = 0x%x ,Data: 0x%x \n",__LINE__,cmd_adress,read_data); + cmd_adress = 0x9c02; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&read_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + pr_err("yjw cam_camera_cci_i2c_read_seq line%d: addr = 0x%x ,Data: 0x%x \n",__LINE__,cmd_adress,read_data); + i++; + } + } + } + + + + return count; +} static char ois_read_cmd_buf[32]; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index 02bb381d2062..97fe77c2839c 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -36,5 +36,9 @@ ssize_t ois_position_data_show(struct device *dev, struct device_attribute *attr ssize_t ois_position_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_status_show(struct device *dev, struct device_attribute *attr, char *buf); ssize_t ois_status_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +ssize_t ois_reg_show(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t ois_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +ssize_t ois_init_before_sr_test_show(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t ois_init_before_sr_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 04475ce68672..b85a8143a3cd 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -176,6 +176,8 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_store); DEVICE_ATTR(ois_status, 0664, ois_status_show, ois_status_store); +DEVICE_ATTR(ois_reg, 0664, ois_reg_show, ois_reg_store); +DEVICE_ATTR(ois_init_before_sr_test, 0664, ois_init_before_sr_test_show, ois_init_before_sr_test_store); static int cam_ois_i2c_driver_probe(struct i2c_client *client, @@ -324,9 +326,11 @@ static int32_t cam_ois_platform_driver_probe( if (rc) goto free_soc; - if ((device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data)) || - (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || - (device_create_file(&pdev->dev, &dev_attr_ois_status))) + if ((device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data)) || + (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || + (device_create_file(&pdev->dev, &dev_attr_ois_status)) || + (device_create_file(&pdev->dev, &dev_attr_ois_reg)) || + (device_create_file(&pdev->dev, &dev_attr_ois_init_before_sr_test))) { CAM_ERR(CAM_OIS, "creat ois device_create_file failed rc=%d", rc); } @@ -371,6 +375,8 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_ois_gyro_cali_data); device_remove_file(&pdev->dev, &dev_attr_ois_status); device_remove_file(&pdev->dev, &dev_attr_ois_position_data); + device_remove_file(&pdev->dev, &dev_attr_ois_reg); + device_remove_file(&pdev->dev, &dev_attr_ois_init_before_sr_test); CAM_ERR(CAM_OIS, " device_remove_file node"); CAM_INFO(CAM_OIS, "platform driver remove invoked"); -- GitLab From bed79efc2a6f4d89de5105ca5dd21ad71d6f364f Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Fri, 13 Aug 2021 15:56:58 +0800 Subject: [PATCH 382/410] [ALM:11087279] [FP4]:ois gain offset &&&%%%comment:[FP4]:ois gain offset &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 17 ++++++++++++++++ .../cam_sensor_io/cam_sensor_cci_i2c.c | 20 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index cb5573edd693..8d064407a802 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -32,6 +32,8 @@ static int32_t ois_reg_value = -1; static int calibration_status = 0; static int ois_status = 0; static int ois_init_status = 0; +extern float gyro_gain_X; + int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -317,6 +319,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) struct page *page = NULL; uint32_t fw_size; uint32_t cmd_adress=0,cmd_data=0; + uint32_t c=0; const REGSETTING cml_ois_gyro_calibration[]= { //gyro cali mode @@ -338,6 +341,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) {0x0018 ,0x0001} ,//13[write] {0x9E18 ,0x0002} ,//14[write] {0x0024 ,0x0001} ,//15[write] + {0x9fb2 ,0x0000} ,//16[read] }; if (!o_ctrl) { @@ -384,6 +388,19 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); + mdelay(50); + gyro_gain_X = gyro_gain_X -0.075; + c = (int) (gyro_gain_X*8192); + if (c > 0) + { + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[16].reg; + i2c_reg_setting.reg_setting[0].reg_data = c; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9fb2 -> 0x%x",c); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + } + mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[0].reg; i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[0].val; diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c index a5e780a2e119..797fd1c30c4f 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -50,6 +50,16 @@ int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, return rc; } +union sf +{ + float f; + unsigned char s[4]; +}cam_gyro_gain; + +float gyro_gain_X = 0.0; + + + int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, uint32_t addr, uint8_t *data, enum camera_sensor_i2c_type addr_type, @@ -60,6 +70,7 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, unsigned char *buf = NULL; int i = 0; struct cam_cci_ctrl cci_ctrl; + uint8_t d[4]; if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) || (data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) @@ -89,6 +100,15 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, data[i] = buf[i]; CAM_DBG(CAM_SENSOR, "Byte %d: Data: 0x%x\n", i, data[i]); } + + if (num_byte == 7494){ + for (i = 0; i < 4; i++) + d[i] = data[6980+i]; + sprintf(cam_gyro_gain.s,"%c%c%c%c", d[0],d[1],d[2],d[3]); + gyro_gain_X = cam_gyro_gain.f; + } + + kfree(buf); return rc; } -- GitLab From 8d869cbe21d4ead4e56cc76c9c63ca76ce3adc23 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Sat, 14 Aug 2021 18:53:57 +0800 Subject: [PATCH 383/410] [ALM:11087279] [FP4]:ois gain offset &&&%%%comment:[FP4]:ois gain offset &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- drivers/cam_sensor_module/cam_ois/cam_ois_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 8d064407a802..5ce8eced96b4 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -320,6 +320,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) uint32_t fw_size; uint32_t cmd_adress=0,cmd_data=0; uint32_t c=0; + float gain = 0.0; const REGSETTING cml_ois_gyro_calibration[]= { //gyro cali mode @@ -389,8 +390,8 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); mdelay(50); - gyro_gain_X = gyro_gain_X -0.075; - c = (int) (gyro_gain_X*8192); + gain = gyro_gain_X -0.075; + c = (int) (gain*8192); if (c > 0) { i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[16].reg; -- GitLab From 99095134f1d33c61267cac0535c623eeeb09a80b Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Wed, 18 Aug 2021 14:39:17 +0800 Subject: [PATCH 384/410] [ALM:11087279] [FP4]:ois gain_Y offset &&&%%%comment:[FP4]:ois gain_Y offset &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 114 +++++++++++++++--- .../cam_sensor_module/cam_ois/cam_ois_core.h | 2 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 4 +- .../cam_sensor_io/cam_sensor_cci_i2c.c | 10 +- 4 files changed, 110 insertions(+), 20 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 5ce8eced96b4..0bab5cdaf889 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ - #include #include #include @@ -15,6 +14,9 @@ #include "cam_common_util.h" #include "cam_packet_util.h" +#define default_gain_X 0.075 +#define default_gain_Y 0.05 + typedef struct REGSETTING{ uint16_t reg ; uint16_t val ; @@ -22,18 +24,19 @@ typedef struct REGSETTING{ static int32_t gyro_offset_X = 0; static int32_t gyro_offset_Y = 0; - static int32_t gyro_offset_X_check = -1; static int32_t gyro_offset_Y_check = -1; - static int32_t ois_reg_value = -1; static int calibration_status = 0; static int ois_status = 0; static int ois_init_status = 0; -extern float gyro_gain_X; +extern float gyro_gain_X; +extern float gyro_gain_Y; +static int32_t decrease_gain_X = 0; +static int32_t decrease_gain_Y = 0; int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -319,9 +322,10 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) struct page *page = NULL; uint32_t fw_size; uint32_t cmd_adress=0,cmd_data=0; - uint32_t c=0; - float gain = 0.0; - + uint32_t c=0,d=0; + float target_gain_X = 0.0; + float target_gain_Y = 0.0; + const REGSETTING cml_ois_gyro_calibration[]= { //gyro cali mode {0x9b2c ,0x0002} ,//0[write]enter calibration mode @@ -343,6 +347,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) {0x9E18 ,0x0002} ,//14[write] {0x0024 ,0x0001} ,//15[write] {0x9fb2 ,0x0000} ,//16[read] + {0x9fb4 ,0x0000} ,//17[read] }; if (!o_ctrl) { @@ -390,16 +395,59 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); mdelay(50); - gain = gyro_gain_X -0.075; - c = (int) (gain*8192); - if (c > 0) + if (decrease_gain_X == 0 && decrease_gain_Y == 0) { - i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[16].reg; - i2c_reg_setting.reg_setting[0].reg_data = c; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9fb2 -> 0x%x",c); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + target_gain_X = gyro_gain_X - default_gain_X; + target_gain_Y = gyro_gain_Y - default_gain_Y; + c = (int) (target_gain_X*8192); + d = (int) (target_gain_Y*8192); + + if (c<=11264 && c>=5939 && d<=11060 && d>=6144)//0.725-1.375,0.75-1.35 + { + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[16].reg; + i2c_reg_setting.reg_setting[0].reg_data = c; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9fb2 -> 0x%x(default offset)",c); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[17].reg; + i2c_reg_setting.reg_setting[0].reg_data = d; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9fb4 -> 0x%x(default offset)",d); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + } + else + CAM_ERR(CAM_OIS, "invalid x(0x%x) or y(0x%x) gain",c,d); + } + else + { + target_gain_X = gyro_gain_X - (float) decrease_gain_X/1000; + target_gain_Y = gyro_gain_Y - (float) decrease_gain_Y/1000; + c = (int) (target_gain_X*8192); + d = (int) (target_gain_Y*8192); + + if (c<=11264 && c>=5939 && d<=11060 && d>=6144)//0.725-1.375,0.75-1.35 + { + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[16].reg; + i2c_reg_setting.reg_setting[0].reg_data = c; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9fb2 -> 0x%x(manual)",c); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(50); + i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[17].reg; + i2c_reg_setting.reg_setting[0].reg_data = d; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9fb4 -> 0x%x(manual)",c); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + } + else + CAM_ERR(CAM_OIS, "invalid x(0x%x) or y(0x%x) gain",c,d); } mdelay(50); @@ -1107,6 +1155,40 @@ ssize_t ois_position_data_store(struct device *dev, struct device_attribute *at return count; } +ssize_t ois_gain_set_show(struct device *dev, struct device_attribute *attr, char *buf){ + + return sprintf(buf, "%d,%d\n", decrease_gain_X,decrease_gain_Y); +} + +ssize_t ois_gain_set_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ + + struct cam_ois_ctrl_t *o_ctrl = NULL; + char cmd_buf[32]; + char flag; + int32_t x_gain=0,y_gain=0; + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + memset(cmd_buf,0,32); + o_ctrl = platform_get_drvdata(pdev); + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return count; + } + //cpy user cmd to kernel x_gain:y_gain:w + strcpy(cmd_buf,buf); + sscanf(cmd_buf,"%d:%d:%c",&x_gain,&y_gain,&flag); + + if (flag == 'w') + { + CAM_ERR(CAM_OIS, "x_gain %d,y_gain %d",x_gain,y_gain); + decrease_gain_X = x_gain; + decrease_gain_Y = y_gain; + } + + return count; +} + + ssize_t ois_status_show(struct device *dev, struct device_attribute *attr, char *buf){ struct cam_ois_ctrl_t *o_ctrl = NULL; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index 97fe77c2839c..7b49ecf0f8bf 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -40,5 +40,7 @@ ssize_t ois_reg_show(struct device *dev, struct device_attribute *attr, char *bu ssize_t ois_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_init_before_sr_test_show(struct device *dev, struct device_attribute *attr, char *buf); ssize_t ois_init_before_sr_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +ssize_t ois_gain_set_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +ssize_t ois_gain_set_show(struct device *dev, struct device_attribute *attr, char *buf); #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index b85a8143a3cd..cb1046c87aea 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -178,7 +178,7 @@ DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_s DEVICE_ATTR(ois_status, 0664, ois_status_show, ois_status_store); DEVICE_ATTR(ois_reg, 0664, ois_reg_show, ois_reg_store); DEVICE_ATTR(ois_init_before_sr_test, 0664, ois_init_before_sr_test_show, ois_init_before_sr_test_store); - +DEVICE_ATTR(ois_gain_set, 0664, ois_gain_set_show, ois_gain_set_store); static int cam_ois_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -330,6 +330,7 @@ static int32_t cam_ois_platform_driver_probe( (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_status)) || (device_create_file(&pdev->dev, &dev_attr_ois_reg)) || + (device_create_file(&pdev->dev, &dev_attr_ois_gain_set)) || (device_create_file(&pdev->dev, &dev_attr_ois_init_before_sr_test))) { CAM_ERR(CAM_OIS, "creat ois device_create_file failed rc=%d", rc); @@ -376,6 +377,7 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_ois_status); device_remove_file(&pdev->dev, &dev_attr_ois_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_reg); + device_remove_file(&pdev->dev, &dev_attr_ois_gain_set); device_remove_file(&pdev->dev, &dev_attr_ois_init_before_sr_test); CAM_ERR(CAM_OIS, " device_remove_file node"); diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c index 797fd1c30c4f..b523a53656e6 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -57,8 +57,7 @@ union sf }cam_gyro_gain; float gyro_gain_X = 0.0; - - +float gyro_gain_Y = 0.0; int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, uint32_t addr, uint8_t *data, @@ -105,7 +104,12 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, for (i = 0; i < 4; i++) d[i] = data[6980+i]; sprintf(cam_gyro_gain.s,"%c%c%c%c", d[0],d[1],d[2],d[3]); - gyro_gain_X = cam_gyro_gain.f; + gyro_gain_X = cam_gyro_gain.f;//X gain + + for (i = 0; i < 4; i++) + d[i] = data[6984+i]; + sprintf(cam_gyro_gain.s,"%c%c%c%c", d[0],d[1],d[2],d[3]); + gyro_gain_Y = cam_gyro_gain.f;//Y gain } -- GitLab From 1946d5415b333b1553a8478db83df6db00e0d172 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Wed, 18 Aug 2021 16:07:35 +0800 Subject: [PATCH 385/410] [ALM:11087279] [FP4]:add debug log &&&%%%comment:[FP4]:add debug log &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- drivers/cam_sensor_module/cam_ois/cam_ois_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 0bab5cdaf889..dfed5fddc158 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -443,7 +443,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].reg_data = d; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9fb4 -> 0x%x(manual)",c); + CAM_ERR(CAM_OIS, "write 0x9fb4 -> 0x%x(manual)",d); rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); } else -- GitLab From c2ebbe7495e35801791d4de906a743a0c4878a19 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 23 Aug 2021 19:25:42 +0800 Subject: [PATCH 386/410] [ALM:11087279] [FP4]:aicview optimization &&&%%%comment:[FP4]:aicview optimization &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor/cam_sensor_core.c | 236 +++++- .../cam_sensor/cam_sensor_dev.c | 3 +- .../cam_sensor/cam_sensor_dev.h | 11 + .../cam_sensor/cam_sensor_initsetting.h.txt | 751 ++++++++++++++++++ include/uapi/media/cam_defs.h | 3 + 5 files changed, 960 insertions(+), 44 deletions(-) create mode 100644 drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index b8f2d87955d4..9cbd794d399d 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -12,6 +12,25 @@ #include "cam_common_util.h" #include "cam_packet_util.h" +int sensor_start_thread(void *ctrl); +struct cam_sensor_i2c_reg_setting_oem{ + struct cam_sensor_i2c_reg_array reg_setting[4600]; + uint32_t size; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + unsigned short delay; +}; + +struct cam_all_sensor_initsetting { + struct cam_sensor_i2c_reg_setting_oem sensor576; + struct cam_sensor_i2c_reg_setting_oem sensor582; + struct cam_sensor_i2c_reg_setting_oem sensor582_sma; +}; + +struct cam_all_sensor_initsetting g_oem_sensor_setting = +{ +#include "cam_sensor_initsetting.h.txt" +}; static void cam_sensor_update_req_mgr( struct cam_sensor_ctrl_t *s_ctrl, @@ -715,8 +734,17 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) cam_sensor_release_per_frame_resource(s_ctrl); if (s_ctrl->sensor_state != CAM_SENSOR_INIT) - cam_sensor_power_down(s_ctrl); - + { + if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) + { + cam_sensor_power_down(s_ctrl); + s_ctrl->power_stat = CAM_SENSOR_POWER_OFF; + s_ctrl->setting_stat = CAM_SENSOR_SETTING_INVALID; + } + else{ + CAM_ERR(CAM_SENSOR,"SENSOR already power off!!"); + } + } if (s_ctrl->bridge_intf.device_hdl != -1) { rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); if (rc < 0) @@ -844,10 +872,17 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } /* Power up and probe sensor */ - rc = cam_sensor_power_up(s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "power up failed"); - goto free_power_settings; + if(s_ctrl->power_stat == CAM_SENSOR_POWER_OFF) + { + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + goto free_power_settings; + } + s_ctrl->power_stat = CAM_SENSOR_POWER_ON; + } + else{ + CAM_ERR(CAM_SENSOR,"SENSOR already power on !!"); } if (s_ctrl->i2c_data.poweron_reg_settings.is_settings_valid) { rc = cam_sensor_apply_settings(s_ctrl, 0, @@ -861,7 +896,16 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, /* Match sensor ID */ rc = cam_sensor_match_id(s_ctrl); if (rc < 0) { - cam_sensor_power_down(s_ctrl); + if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) + { + cam_sensor_power_down(s_ctrl); + s_ctrl->power_stat = CAM_SENSOR_POWER_OFF; + s_ctrl->setting_stat = CAM_SENSOR_SETTING_INVALID; + } + else + { + CAM_ERR(CAM_SENSOR,"SENSOR already power off!!"); + } msleep(20); goto free_power_settings; } @@ -900,11 +944,19 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_INFO(CAM_SENSOR, "match SONY_imx582_UW"); snprintf(aux_camera_status, sizeof(aux_camera_status), "SONY_IMX582_UW"); } - - rc = cam_sensor_power_down(s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); - goto free_power_settings; + if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) + { + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); + goto free_power_settings; + } + s_ctrl->power_stat = CAM_SENSOR_POWER_OFF; + s_ctrl->setting_stat = CAM_SENSOR_SETTING_INVALID; + } + else + { + CAM_ERR(CAM_SENSOR,"SENSOR already power off!!"); } /* * Set probe succeeded flag to 1 so that no other camera shall @@ -967,11 +1019,18 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } /* MODIFIED-BEGIN by yixiang.wu, 2021-01-22,BUG-10277816*/ - rc = cam_sensor_power_up(s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); - goto release_mutex; - /* MODIFIED-END by yixiang.wu,BUG-10277816*/ + if(s_ctrl->power_stat == CAM_SENSOR_POWER_OFF) + { + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); + goto release_mutex; + /* MODIFIED-END by yixiang.wu,BUG-10277816*/ + } + s_ctrl->power_stat = CAM_SENSOR_POWER_ON; + } + else{ + CAM_ERR(CAM_SENSOR,"SENSOR already power on!!"); } s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; @@ -1000,11 +1059,20 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = -EAGAIN; goto release_mutex; } - - rc = cam_sensor_power_down(s_ctrl); - if (rc < 0) { - CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); - goto release_mutex; + + if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) + { + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); + goto release_mutex; + } + s_ctrl->power_stat = CAM_SENSOR_POWER_OFF; + s_ctrl->setting_stat = CAM_SENSOR_SETTING_INVALID; + } + else + { + CAM_ERR(CAM_SENSOR,"SENSOR already power off!!"); } cam_sensor_release_per_frame_resource(s_ctrl); @@ -1113,28 +1181,35 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, pkt_opcode = CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG; - rc = cam_sensor_apply_settings(s_ctrl, 0, - pkt_opcode); - - if ((rc == -EAGAIN) && - (s_ctrl->io_master_info.master_type == CCI_MASTER)) { - /* If CCI hardware is resetting we need to wait - * for sometime before reapply - */ - CAM_WARN(CAM_SENSOR, - "Reapplying the Init settings due to cci hw reset"); - usleep_range(1000, 1010); + if(s_ctrl->setting_stat != CAM_SENSOR_SETTING_SUCCESS) + { rc = cam_sensor_apply_settings(s_ctrl, 0, - pkt_opcode); + pkt_opcode); + + if ((rc == -EAGAIN) && + (s_ctrl->io_master_info.master_type == CCI_MASTER)) { + /* If CCI hardware is resetting we need to wait + * for sometime before reapply + */ + CAM_WARN(CAM_SENSOR, + "Reapplying the Init settings due to cci hw reset"); + usleep_range(1000, 1010); + rc = cam_sensor_apply_settings(s_ctrl, 0, + pkt_opcode); + } + s_ctrl->i2c_data.init_settings.request_id = -1; + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply init settings rc= %d", + rc); + delete_request(&s_ctrl->i2c_data.init_settings); + goto release_mutex; + } + s_ctrl->setting_stat = CAM_SENSOR_SETTING_SUCCESS; } - s_ctrl->i2c_data.init_settings.request_id = -1; - - if (rc < 0) { - CAM_ERR(CAM_SENSOR, - "cannot apply init settings rc= %d", - rc); - delete_request(&s_ctrl->i2c_data.init_settings); - goto release_mutex; + else + { + CAM_ERR(CAM_SENSOR,"sensor already init setting !!!!"); } rc = delete_request(&s_ctrl->i2c_data.init_settings); if (rc < 0) { @@ -1192,6 +1267,26 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->sensordata->slave_info.sensor_slave_addr); } break; + case CAM_GET_ID:{ + rc = copy_to_user((void __user *)cmd->handle,&s_ctrl->soc_info.index,sizeof(uint32_t)); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"get_id err"); + goto release_mutex; + } + } + break; + case CAM_SENSOR_POWERON:{ + struct task_struct *thread_hand = NULL; + thread_hand = kthread_run(sensor_start_thread,s_ctrl,s_ctrl->device_name); + if(thread_hand == NULL) + { + CAM_ERR(CAM_SENSOR,"sensor power on thread run err!!"); + rc = -EINVAL; + goto release_mutex; + } + } + break; + default: CAM_ERR(CAM_SENSOR, "Invalid Opcode: %d", cmd->op_code); rc = -EINVAL; @@ -1274,7 +1369,15 @@ int cam_sensor_power(struct v4l2_subdev *sd, int on) mutex_lock(&(s_ctrl->cam_sensor_mutex)); if (!on && s_ctrl->sensor_state == CAM_SENSOR_START) { - cam_sensor_power_down(s_ctrl); + if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) + { + cam_sensor_power_down(s_ctrl); + s_ctrl->power_stat = CAM_SENSOR_POWER_OFF; + s_ctrl->setting_stat = CAM_SENSOR_SETTING_INVALID; + } + else{ + CAM_ERR(CAM_SENSOR,"SENSOR already power off!!"); + } s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; } mutex_unlock(&(s_ctrl->cam_sensor_mutex)); @@ -1581,3 +1684,50 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return rc; } +int sensor_start_thread(void *ctrl) +{ + struct cam_sensor_ctrl_t *s_ctrl = ctrl; + int rc; + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if(s_ctrl->power_stat == CAM_SENSOR_POWER_OFF) + { + rc = cam_sensor_power_up(s_ctrl); + if(rc < 0) + { + CAM_ERR(CAM_SENSOR,"sensor power up error"); + } + else{ + s_ctrl->power_stat = CAM_SENSOR_POWER_ON; + if(s_ctrl->setting_stat != CAM_SENSOR_SETTING_SUCCESS) + { + if(s_ctrl->soc_info.index == 0 && s_ctrl->sensordata->slave_info.sensor_id == 0x582)//main + { + struct cam_sensor_i2c_reg_setting sensor_setting; + sensor_setting.reg_setting = g_oem_sensor_setting.sensor582_sma.reg_setting; + sensor_setting.size = g_oem_sensor_setting.sensor582_sma.size; + sensor_setting.addr_type = g_oem_sensor_setting.sensor582_sma.addr_type; + sensor_setting.data_type = g_oem_sensor_setting.sensor582_sma.data_type; + sensor_setting.delay = g_oem_sensor_setting.sensor582_sma.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info),&sensor_setting); + if(rc < 0) + { + CAM_ERR(CAM_SENSOR,"sensor init setting error!!!!"); + } + else + { + CAM_ERR(CAM_SENSOR,"sensor init setting success"); + s_ctrl->setting_stat = CAM_SENSOR_SETTING_SUCCESS; + } + } + } + else{ + CAM_ERR(CAM_SENSOR,"sensor already init setting !!!!"); + } + } + } + else{ + CAM_ERR(CAM_SENSOR,"sensor already power on!!"); + } + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return 0; +} diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index f6281d0028ab..9de0af6f56a3 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -225,7 +225,8 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request; s_ctrl->sensordata->power_info.dev = soc_info->dev; - + s_ctrl->power_stat = CAM_SENSOR_POWER_OFF; + s_ctrl->setting_stat = CAM_SENSOR_SETTING_INVALID; return rc; unreg_subdev: cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h index d9e8eaaeb129..99ab099a01ee 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -45,6 +45,15 @@ enum cam_sensor_state_t { CAM_SENSOR_START, }; +enum cam_sensor_power_state_t{ + CAM_SENSOR_POWER_OFF, + CAM_SENSOR_POWER_ON +}; +enum cam_sensor_setting_state_t{ + CAM_SENSOR_SETTING_INVALID, + CAM_SENSOR_SETTING_SUCCESS, +}; + /** * struct intf_params * @device_hdl: Device Handle @@ -112,6 +121,8 @@ struct cam_sensor_ctrl_t { uint32_t last_flush_req; uint16_t pipeline_delay; int32_t open_cnt; + enum cam_sensor_power_state_t power_stat; + enum cam_sensor_setting_state_t setting_stat; }; #endif /* _CAM_SENSOR_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt new file mode 100644 index 000000000000..9d37aaa52985 --- /dev/null +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt @@ -0,0 +1,751 @@ +.sensor576={ + .reg_setting={ + {.reg_addr = 0x0136,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x0137,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C7E,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C7F,.reg_data = 0x07,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x380D,.reg_data = 0x80,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C00,.reg_data = 0x1A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C01,.reg_data = 0x1A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C02,.reg_data = 0x1A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C03,.reg_data = 0x1A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C04,.reg_data = 0x1A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C05,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C08,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C09,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0A,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0D,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0E,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0F,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3F89,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4B8E,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4B8F,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4BA8,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4BAA,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4BAB,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4BC9,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5511,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x560B,.reg_data = 0x5B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x56A7,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5B3B,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5BA7,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6002,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6014,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6118,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6122,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6128,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6132,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6138,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6142,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6148,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6152,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x617B,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x617E,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6187,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x618A,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6193,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6196,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x619F,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A2,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61AB,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61AE,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B7,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61BA,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61C3,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61C6,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61CF,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61D2,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61DB,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61DE,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61E7,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61EA,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61F3,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61F6,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61FF,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6202,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x620B,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x620E,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6217,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x621A,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6223,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6226,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B0B,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B0C,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B0D,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B0F,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B10,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B11,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B12,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B13,.reg_data = 0x07,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B14,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B15,.reg_data = 0x09,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B16,.reg_data = 0x0C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B17,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B18,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B19,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B1A,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B1B,.reg_data = 0x0B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B1C,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B1D,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B1F,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B20,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B21,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B22,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B23,.reg_data = 0x07,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B24,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B25,.reg_data = 0x09,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B26,.reg_data = 0x0C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B27,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B28,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B29,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B2A,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6B2B,.reg_data = 0x0B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x7948,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x7949,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x794B,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x794C,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x794D,.reg_data = 0x3A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x7951,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x7952,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x7955,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9004,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9200,.reg_data = 0xA0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9201,.reg_data = 0xA7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9202,.reg_data = 0xA0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9203,.reg_data = 0xAA,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9204,.reg_data = 0xA0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9205,.reg_data = 0xAD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9206,.reg_data = 0xA0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9207,.reg_data = 0xB0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9208,.reg_data = 0xA0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9209,.reg_data = 0xB3,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920A,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920B,.reg_data = 0x34,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920C,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920D,.reg_data = 0x36,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920E,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920F,.reg_data = 0x37,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9210,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9211,.reg_data = 0x38,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9212,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9213,.reg_data = 0x39,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9214,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9215,.reg_data = 0x3A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9216,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9217,.reg_data = 0x3C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9218,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9219,.reg_data = 0x3D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921A,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921B,.reg_data = 0x3E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921C,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921D,.reg_data = 0x3F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921E,.reg_data = 0x7F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921F,.reg_data = 0x77,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99AF,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99B0,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99B1,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99B2,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99B3,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E1,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E2,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E3,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E4,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E5,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E6,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E7,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E8,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99E9,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x99EA,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE286,.reg_data = 0x31,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE2A6,.reg_data = 0x32,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE2C6,.reg_data = 0x33,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4038,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9856,.reg_data = 0xA0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9857,.reg_data = 0x78,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9858,.reg_data = 0x64,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x986E,.reg_data = 0x64,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9870,.reg_data = 0x3C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x993A,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x993B,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9953,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9954,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x996B,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x996D,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x996F,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x998E,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA101,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA103,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA105,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA107,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA109,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA10B,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA10D,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA10F,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA111,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA113,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA115,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA117,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA119,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA11B,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA11D,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAA58,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAA59,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAB03,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAB04,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAB05,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAD6A,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAD6B,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAD77,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAD82,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAD83,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE06,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE07,.reg_data = 0x16,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE08,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE09,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE0A,.reg_data = 0x16,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE0B,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAF01,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAF03,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAF05,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xB048,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, + }, + .size = 208, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +.sensor582={ + .reg_setting={ + {.reg_addr = 0x0136,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x0137,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C7E,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C7F,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C00,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C01,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C02,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C03,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C04,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C05,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C06,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C07,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C08,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C09,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0A,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0B,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0C,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0D,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0E,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0F,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3F89,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5265,.reg_data = 0x13,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5268,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x526A,.reg_data = 0x27,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x526B,.reg_data = 0x23,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5727,.reg_data = 0x77,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5729,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x572B,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5737,.reg_data = 0x88,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5739,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x573B,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x574B,.reg_data = 0x4D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x574F,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5757,.reg_data = 0xA8,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5759,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x575B,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5765,.reg_data = 0x8C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5768,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5769,.reg_data = 0xE7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x577D,.reg_data = 0x5A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x577F,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5781,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5783,.reg_data = 0x95,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5787,.reg_data = 0xC2,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5789,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x578B,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x579B,.reg_data = 0x8A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x579D,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x579F,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57A5,.reg_data = 0x95,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57A9,.reg_data = 0x99,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57AB,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57AF,.reg_data = 0xC9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57B3,.reg_data = 0x95,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57BF,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57C1,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57C9,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x57CB,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5801,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5803,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5811,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5813,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5B79,.reg_data = 0xB5,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5B7B,.reg_data = 0x51,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C57,.reg_data = 0x54,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C59,.reg_data = 0xD9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C5B,.reg_data = 0x90,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C5D,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C5F,.reg_data = 0x2A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C61,.reg_data = 0xAF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C62,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C63,.reg_data = 0xBA,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C65,.reg_data = 0x42,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C67,.reg_data = 0xC8,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C69,.reg_data = 0x4D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C6B,.reg_data = 0xBC,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C6D,.reg_data = 0x44,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C6E,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C6F,.reg_data = 0xE5,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C73,.reg_data = 0x34,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C74,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C75,.reg_data = 0xBC,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C7F,.reg_data = 0x40,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C81,.reg_data = 0xA7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C82,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C83,.reg_data = 0xD8,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C85,.reg_data = 0xA6,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C8B,.reg_data = 0x6F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C8C,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5C8D,.reg_data = 0xF7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5E2C,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x5E2D,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6024,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6027,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6030,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6033,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x603C,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x603F,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6048,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x604B,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x606A,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x606F,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6071,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6079,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x607A,.reg_data = 0x07,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x607B,.reg_data = 0x07,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x607C,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x607D,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x607E,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x607F,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6080,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6081,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6082,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6083,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6084,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6085,.reg_data = 0x0B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6086,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6087,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6088,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6089,.reg_data = 0x0B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x608B,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x608C,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6091,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6095,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6098,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6099,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x609A,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x609B,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x609C,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x609D,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x609E,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x609F,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60A0,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60B7,.reg_data = 0x32,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60C1,.reg_data = 0x32,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60C5,.reg_data = 0x32,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60D5,.reg_data = 0x99,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60DF,.reg_data = 0x99,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60E3,.reg_data = 0x99,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60F3,.reg_data = 0x99,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60F7,.reg_data = 0xAD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60FB,.reg_data = 0xCE,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60FD,.reg_data = 0x99,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x60FF,.reg_data = 0xCE,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6103,.reg_data = 0xCE,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6106,.reg_data = 0x16,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6107,.reg_data = 0x15,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6108,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x610A,.reg_data = 0x17,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x610B,.reg_data = 0x16,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x610C,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x610E,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x610F,.reg_data = 0x16,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6110,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6112,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6113,.reg_data = 0x17,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6114,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6116,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6117,.reg_data = 0x18,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6118,.reg_data = 0x11,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6147,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6148,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6149,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x614A,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x614B,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x614C,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x614D,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x614E,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x614F,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6150,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6151,.reg_data = 0x0D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6152,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6153,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6154,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6155,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6157,.reg_data = 0x21,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6159,.reg_data = 0x0C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x615B,.reg_data = 0x0C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x615D,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6161,.reg_data = 0x22,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6163,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6165,.reg_data = 0x1F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6167,.reg_data = 0x1A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x616B,.reg_data = 0x22,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x616D,.reg_data = 0x21,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x616F,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6171,.reg_data = 0x1B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6175,.reg_data = 0x23,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6177,.reg_data = 0x22,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6179,.reg_data = 0x21,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x617B,.reg_data = 0x1E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x617F,.reg_data = 0x23,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6181,.reg_data = 0x23,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6183,.reg_data = 0x23,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6185,.reg_data = 0x1E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6188,.reg_data = 0xB4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6189,.reg_data = 0x7E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x618A,.reg_data = 0x96,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x618B,.reg_data = 0x50,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x618D,.reg_data = 0xD2,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x618E,.reg_data = 0xC8,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x618F,.reg_data = 0xB4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6190,.reg_data = 0x78,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6192,.reg_data = 0xE6,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6193,.reg_data = 0xCC,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6194,.reg_data = 0xB4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6195,.reg_data = 0x82,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6197,.reg_data = 0xE6,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6198,.reg_data = 0xD2,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6199,.reg_data = 0xD2,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x619A,.reg_data = 0xAA,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x619C,.reg_data = 0xE6,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x619D,.reg_data = 0xE8,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x619E,.reg_data = 0xDC,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x619F,.reg_data = 0xCD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A1,.reg_data = 0x09,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A2,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A3,.reg_data = 0x0B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A4,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A6,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A7,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A8,.reg_data = 0x0B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61A9,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61AB,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61AC,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61AD,.reg_data = 0x0B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61AE,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B0,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B1,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B2,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B3,.reg_data = 0x09,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B5,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B6,.reg_data = 0x08,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B7,.reg_data = 0x09,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61B8,.reg_data = 0x09,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61C4,.reg_data = 0x0F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61C5,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61C9,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61CA,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61CC,.reg_data = 0x0A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61CE,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61CF,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x61D1,.reg_data = 0x23,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x621E,.reg_data = 0x50,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x621F,.reg_data = 0x3C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6220,.reg_data = 0x30,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6221,.reg_data = 0x30,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6223,.reg_data = 0x6E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6224,.reg_data = 0x5E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6225,.reg_data = 0x5C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6226,.reg_data = 0x5C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6229,.reg_data = 0x64,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x622A,.reg_data = 0x66,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x622B,.reg_data = 0x66,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E1D,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E25,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E38,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E3B,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9004,.reg_data = 0x2C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9200,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9201,.reg_data = 0xA7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9202,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9203,.reg_data = 0xAA,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9204,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9205,.reg_data = 0xAD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9206,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9207,.reg_data = 0xB0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9208,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9209,.reg_data = 0xB3,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920A,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920B,.reg_data = 0x34,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920C,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920D,.reg_data = 0x36,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920E,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920F,.reg_data = 0x37,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9210,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9211,.reg_data = 0x38,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9212,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9213,.reg_data = 0x39,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9214,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9215,.reg_data = 0x3A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9216,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9217,.reg_data = 0x3C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9218,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9219,.reg_data = 0x3D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921A,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921B,.reg_data = 0x3E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921C,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921D,.reg_data = 0x3F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921E,.reg_data = 0x85,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921F,.reg_data = 0x77,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9226,.reg_data = 0x42,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9227,.reg_data = 0x52,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9228,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9229,.reg_data = 0xB9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922A,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922B,.reg_data = 0xBF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922C,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922D,.reg_data = 0xC5,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922E,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922F,.reg_data = 0xCB,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9230,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9231,.reg_data = 0xD1,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9232,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9233,.reg_data = 0xD7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9234,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9235,.reg_data = 0xDD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9236,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9237,.reg_data = 0xE3,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9238,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9239,.reg_data = 0xE9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923A,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923B,.reg_data = 0xEF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923C,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923D,.reg_data = 0xF5,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923E,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923F,.reg_data = 0xF9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9240,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9241,.reg_data = 0xFD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9242,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9243,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9244,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9245,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924A,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924B,.reg_data = 0x6B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924C,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924D,.reg_data = 0x7F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924E,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924F,.reg_data = 0x92,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9250,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9251,.reg_data = 0x9C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9252,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9253,.reg_data = 0xAB,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9254,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9255,.reg_data = 0xC4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9256,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9257,.reg_data = 0xCE,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9810,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9814,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA112,.reg_data = 0x68,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA113,.reg_data = 0x56,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA114,.reg_data = 0x2B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA115,.reg_data = 0x55,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA116,.reg_data = 0x55,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA117,.reg_data = 0x16,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA119,.reg_data = 0x51,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA11A,.reg_data = 0x34,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA139,.reg_data = 0x4F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA13A,.reg_data = 0x48,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA13B,.reg_data = 0x45,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA13C,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA13F,.reg_data = 0x23,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA140,.reg_data = 0x16,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA141,.reg_data = 0x12,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA142,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA596,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA597,.reg_data = 0x13,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA598,.reg_data = 0x13,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xA779,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAC12,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAC13,.reg_data = 0x26,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAC14,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAC15,.reg_data = 0x26,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAC17,.reg_data = 0xC4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAF05,.reg_data = 0x48,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xB069,.reg_data = 0x02,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC448,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC44B,.reg_data = 0x07,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC44C,.reg_data = 0x0E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC44D,.reg_data = 0x50,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC451,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC452,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC455,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE286,.reg_data = 0x31,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE2A6,.reg_data = 0x32,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE2C6,.reg_data = 0x33,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xEA4B,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xEA4C,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xEA4D,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xEA4E,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF001,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF00D,.reg_data = 0x40,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF031,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF03D,.reg_data = 0x40,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF44B,.reg_data = 0x80,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF44D,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF44E,.reg_data = 0x80,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF450,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF451,.reg_data = 0x80,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF453,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF454,.reg_data = 0x80,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF456,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF457,.reg_data = 0x80,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF459,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF478,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF47B,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF47E,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF481,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xF484,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x88D6,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9852,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE09,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE0A,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE12,.reg_data = 0x58,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE13,.reg_data = 0x58,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE15,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xAE16,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xB071,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, + }, + .size = 408, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +.sensor582_sma={ + .reg_setting={ +{.reg_addr = 0x0136,.reg_data = 0x13,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x0137,.reg_data = 0x33,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C7E,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C7F,.reg_data = 0x06,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C00,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C01,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C02,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C03,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C04,.reg_data = 0x10,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C05,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C06,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C07,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C08,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C09,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0A,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0B,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0C,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0D,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0E,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3C0F,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E1D,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E25,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E38,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x6E3B,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9004,.reg_data = 0x2C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9200,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9201,.reg_data = 0xA7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9202,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9203,.reg_data = 0xAA,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9204,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9205,.reg_data = 0xAD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9206,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9207,.reg_data = 0xB0,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9208,.reg_data = 0xF4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9209,.reg_data = 0xB3,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920A,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920B,.reg_data = 0x34,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920C,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920D,.reg_data = 0x36,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920E,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x920F,.reg_data = 0x37,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9210,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9211,.reg_data = 0x38,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9212,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9213,.reg_data = 0x39,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9214,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9215,.reg_data = 0x3A,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9216,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9217,.reg_data = 0x3C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9218,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9219,.reg_data = 0x3D,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921A,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921B,.reg_data = 0x3E,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921C,.reg_data = 0xB7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921D,.reg_data = 0x3F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921E,.reg_data = 0x85,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x921F,.reg_data = 0x77,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9226,.reg_data = 0x42,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9227,.reg_data = 0x52,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9228,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9229,.reg_data = 0xB9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922A,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922B,.reg_data = 0xBF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922C,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922D,.reg_data = 0xC5,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922E,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x922F,.reg_data = 0xCB,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9230,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9231,.reg_data = 0xD1,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9232,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9233,.reg_data = 0xD7,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9234,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9235,.reg_data = 0xDD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9236,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9237,.reg_data = 0xE3,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9238,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9239,.reg_data = 0xE9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923A,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923B,.reg_data = 0xEF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923C,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923D,.reg_data = 0xF5,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923E,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x923F,.reg_data = 0xF9,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9240,.reg_data = 0x60,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9241,.reg_data = 0xFD,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9242,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9243,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9244,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9245,.reg_data = 0x05,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924A,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924B,.reg_data = 0x6B,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924C,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924D,.reg_data = 0x7F,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924E,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x924F,.reg_data = 0x92,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9250,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9251,.reg_data = 0x9C,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9252,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9253,.reg_data = 0xAB,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9254,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9255,.reg_data = 0xC4,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9256,.reg_data = 0x61,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9257,.reg_data = 0xCE,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9810,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x9814,.reg_data = 0x14,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC449,.reg_data = 0x04,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xC44A,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE286,.reg_data = 0x31,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE2A6,.reg_data = 0x32,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0xE2C6,.reg_data = 0x33,.delay = 0x00,.data_mask = 0x00}, + }, + .size = 110, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index 9883517d74e0..283b16183080 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -23,6 +23,9 @@ #define CAM_FLUSH_REQ (CAM_COMMON_OPCODE_BASE + 0x8) #define CAM_COMMON_OPCODE_MAX (CAM_COMMON_OPCODE_BASE + 0x9) +#define CAM_GET_ID 0x900 +#define CAM_SENSOR_POWERON 0x901 + #define CAM_COMMON_OPCODE_BASE_v2 0x150 #define CAM_ACQUIRE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x1) #define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2) -- GitLab From 62fa0a52360bb7635a77ab39f72ee791347c0ce9 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Sat, 18 Sep 2021 15:14:57 +0800 Subject: [PATCH 387/410] [ALM:11087279] [FP4]:[Aicview]power optimization &&&%%%comment:[FP4]:[Aicview] power optimization &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor/cam_sensor_core.c | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 9cbd794d399d..d62235303cd6 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -16,8 +16,8 @@ int sensor_start_thread(void *ctrl); struct cam_sensor_i2c_reg_setting_oem{ struct cam_sensor_i2c_reg_array reg_setting[4600]; uint32_t size; - enum camera_sensor_i2c_type addr_type; - enum camera_sensor_i2c_type data_type; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; unsigned short delay; }; @@ -944,7 +944,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_INFO(CAM_SENSOR, "match SONY_imx582_UW"); snprintf(aux_camera_status, sizeof(aux_camera_status), "SONY_IMX582_UW"); } - if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) + if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) { rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { @@ -1059,7 +1059,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = -EAGAIN; goto release_mutex; } - + if(s_ctrl->power_stat == CAM_SENSOR_POWER_ON) { rc = cam_sensor_power_down(s_ctrl); @@ -1268,13 +1268,13 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } break; case CAM_GET_ID:{ - rc = copy_to_user((void __user *)cmd->handle,&s_ctrl->soc_info.index,sizeof(uint32_t)); - if(rc < 0){ - CAM_ERR(CAM_SENSOR,"get_id err"); - goto release_mutex; + rc = copy_to_user((void __user *)cmd->handle,&s_ctrl->soc_info.index,sizeof(uint32_t)); + if(rc < 0){ + CAM_ERR(CAM_SENSOR,"get_id err"); + goto release_mutex; } } - break; + break; case CAM_SENSOR_POWERON:{ struct task_struct *thread_hand = NULL; thread_hand = kthread_run(sensor_start_thread,s_ctrl,s_ctrl->device_name); @@ -1286,7 +1286,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } } break; - + default: CAM_ERR(CAM_SENSOR, "Invalid Opcode: %d", cmd->op_code); rc = -EINVAL; @@ -1691,7 +1691,9 @@ int sensor_start_thread(void *ctrl) mutex_lock(&(s_ctrl->cam_sensor_mutex)); if(s_ctrl->power_stat == CAM_SENSOR_POWER_OFF) { - rc = cam_sensor_power_up(s_ctrl); + if(s_ctrl->soc_info.index == 0 && s_ctrl->sensordata->slave_info.sensor_id == 0x582)//main + { + rc = cam_sensor_power_up(s_ctrl); if(rc < 0) { CAM_ERR(CAM_SENSOR,"sensor power up error"); @@ -1700,30 +1702,28 @@ int sensor_start_thread(void *ctrl) s_ctrl->power_stat = CAM_SENSOR_POWER_ON; if(s_ctrl->setting_stat != CAM_SENSOR_SETTING_SUCCESS) { - if(s_ctrl->soc_info.index == 0 && s_ctrl->sensordata->slave_info.sensor_id == 0x582)//main + struct cam_sensor_i2c_reg_setting sensor_setting; + sensor_setting.reg_setting = g_oem_sensor_setting.sensor582_sma.reg_setting; + sensor_setting.size = g_oem_sensor_setting.sensor582_sma.size; + sensor_setting.addr_type = g_oem_sensor_setting.sensor582_sma.addr_type; + sensor_setting.data_type = g_oem_sensor_setting.sensor582_sma.data_type; + sensor_setting.delay = g_oem_sensor_setting.sensor582_sma.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info),&sensor_setting); + if(rc < 0) { - struct cam_sensor_i2c_reg_setting sensor_setting; - sensor_setting.reg_setting = g_oem_sensor_setting.sensor582_sma.reg_setting; - sensor_setting.size = g_oem_sensor_setting.sensor582_sma.size; - sensor_setting.addr_type = g_oem_sensor_setting.sensor582_sma.addr_type; - sensor_setting.data_type = g_oem_sensor_setting.sensor582_sma.data_type; - sensor_setting.delay = g_oem_sensor_setting.sensor582_sma.delay; - rc = camera_io_dev_write(&(s_ctrl->io_master_info),&sensor_setting); - if(rc < 0) - { - CAM_ERR(CAM_SENSOR,"sensor init setting error!!!!"); - } - else - { - CAM_ERR(CAM_SENSOR,"sensor init setting success"); - s_ctrl->setting_stat = CAM_SENSOR_SETTING_SUCCESS; - } + CAM_ERR(CAM_SENSOR,"sensor init setting error!!!!"); + } + else + { + CAM_ERR(CAM_SENSOR,"sensor init setting success"); + s_ctrl->setting_stat = CAM_SENSOR_SETTING_SUCCESS; } } else{ CAM_ERR(CAM_SENSOR,"sensor already init setting !!!!"); } } + } } else{ CAM_ERR(CAM_SENSOR,"sensor already power on!!"); -- GitLab From 4f8a33eec7ceebba29e688fae48238e04d7af2c2 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 27 Sep 2021 10:42:01 +0800 Subject: [PATCH 388/410] [ALM:11087279] [FP4]:ois vsync &&&%%%comment:[FP4]:ois vsync &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.h | 2 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 203 ++++++++++++++++++ .../cam_sensor_module/cam_ois/cam_ois_dev.h | 5 + .../cam_sensor_module/cam_ois/cam_ois_soc.c | 24 +++ .../cam_sensor/cam_sensor_initsetting.h.txt | 8 + 5 files changed, 242 insertions(+) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index 7b49ecf0f8bf..bd5f5fe46b2f 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -42,5 +42,7 @@ ssize_t ois_init_before_sr_test_show(struct device *dev, struct device_attribute ssize_t ois_init_before_sr_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_gain_set_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_gain_set_show(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t ois_timestamps_position_show(struct device *dev, struct device_attribute *attr, char *buf); + #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index cb1046c87aea..b297c27561bc 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -8,6 +8,28 @@ #include "cam_ois_soc.h" #include "cam_ois_core.h" #include "cam_debug_util.h" +#include +#include +#include +#include +#include + +struct cam_ois_ctrl_t *o_ctrl_vsync = NULL; +int64_t timestamp_ois; +uint8_t *position_X_Y_timestamps=NULL; +uint8_t data_for_vsync[28] = {0}; + + +typedef struct REGSETTING{ + uint16_t reg ; + uint16_t val ; +}REGSETTING ; + +const REGSETTING ois_fw_control[]= { + {0x9b2c ,0x0001} ,//[0] +}; + + static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) @@ -173,12 +195,159 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) return rc; } +ssize_t ois_timestamps_position_show(struct device *dev, struct device_attribute *attr, char *buf){ + + int i = 0, len = 0; + + for( i = 0; i < 28; i++) + len += sprintf(buf + len, "0x%x,", data_for_vsync[i]); + len +=sprintf(buf + len , "\n"); + + return len; + +} + DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_store); DEVICE_ATTR(ois_status, 0664, ois_status_show, ois_status_store); DEVICE_ATTR(ois_reg, 0664, ois_reg_show, ois_reg_store); DEVICE_ATTR(ois_init_before_sr_test, 0664, ois_init_before_sr_test_show, ois_init_before_sr_test_store); DEVICE_ATTR(ois_gain_set, 0664, ois_gain_set_show, ois_gain_set_store); +DEVICE_ATTR(ois_timestamps_position_data, 0664, ois_timestamps_position_show, NULL); + + +static int cml_vsync_pinctrl_init(struct cam_ois_ctrl_t *o_ctrl) +{ + int retval = 0; + + /* Get pinctrl if target uses pinctrl */ + o_ctrl->vsync_pinctrl = devm_pinctrl_get((o_ctrl->pdev->dev.parent)); + if (IS_ERR_OR_NULL(o_ctrl->vsync_pinctrl)) { + retval = PTR_ERR(o_ctrl->vsync_pinctrl); + CAM_ERR(CAM_OIS, "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + o_ctrl->pin_default = pinctrl_lookup_state(o_ctrl->vsync_pinctrl, "default"); + if (IS_ERR_OR_NULL(o_ctrl->pin_default)) { + retval = PTR_ERR(o_ctrl->pin_default); + CAM_ERR(CAM_OIS, "Failed to look up default state\n"); + goto err_pinctrl_lookup; + } + + return retval; + +err_pinctrl_lookup: + devm_pinctrl_put(o_ctrl->vsync_pinctrl); +err_pinctrl_get: + o_ctrl->vsync_pinctrl = NULL; + return retval; +} + +irqreturn_t interrupt_ois_vsync_irq(int irq, void *dev) +{ + timestamp_ois = ktime_get_real_ns(); + queue_work(o_ctrl_vsync->ois_vsync_wq, &o_ctrl_vsync->ois_vsync_work); + + return IRQ_HANDLED; +} + +static void ois_vsync_function(struct work_struct *work) +{ + uint16_t total_bytes = 0; + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + uint32_t fw_size; + uint32_t cmd_data=0; + + if (!o_ctrl_vsync) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return; + } + total_bytes = sizeof(ois_fw_control[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return; + } + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; + i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + mdelay(1); + + rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); + + data_for_vsync[0] = position_X_Y_timestamps[6]; + data_for_vsync[1] = position_X_Y_timestamps[7];//6X + data_for_vsync[2] = position_X_Y_timestamps[8]; + data_for_vsync[3] = position_X_Y_timestamps[9];//6Y + data_for_vsync[4] = position_X_Y_timestamps[22]; + data_for_vsync[5] = position_X_Y_timestamps[23];//7X + data_for_vsync[6] = position_X_Y_timestamps[24]; + data_for_vsync[7] = position_X_Y_timestamps[25];//7Y + data_for_vsync[8] = position_X_Y_timestamps[38]; + data_for_vsync[9] = position_X_Y_timestamps[39];//8X + data_for_vsync[10] = position_X_Y_timestamps[40]; + data_for_vsync[11] = position_X_Y_timestamps[41];//8Y + data_for_vsync[12] = position_X_Y_timestamps[54]; + data_for_vsync[13] = position_X_Y_timestamps[55];//9X + data_for_vsync[14] = position_X_Y_timestamps[56]; + data_for_vsync[15] = position_X_Y_timestamps[57];//9Y + data_for_vsync[16] = position_X_Y_timestamps[70]; + data_for_vsync[17] = position_X_Y_timestamps[71];//10X + data_for_vsync[18] = position_X_Y_timestamps[72]; + data_for_vsync[19] = position_X_Y_timestamps[73];//10Y + + data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); + data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); + data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); + data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); + data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); + data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); + data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); + data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); + + cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); + page = NULL; + +} static int cam_ois_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -321,7 +490,31 @@ static int32_t cam_ois_platform_driver_probe( CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc); goto free_soc; } + + rc = cml_vsync_pinctrl_init(o_ctrl); + if (!rc && o_ctrl->vsync_pinctrl) { + rc = pinctrl_select_state( + o_ctrl->vsync_pinctrl, + o_ctrl->pin_default); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Can't select pinctrl state\n"); + } + } + + o_ctrl->ois_vsync_wq= create_singlethread_workqueue("ois_vsync_wq"); + INIT_WORK(&o_ctrl->ois_vsync_work, ois_vsync_function); + queue_work(o_ctrl->ois_vsync_wq, &o_ctrl->ois_vsync_work); + + rc = request_irq(gpio_to_irq(o_ctrl->irq_gpio), interrupt_ois_vsync_irq, IRQ_TYPE_EDGE_RISING , "ois_vsync_work", &o_ctrl->soc_info.dev); + if(rc < 0) + { + + CAM_ERR(CAM_OIS, "request_irq failed\n"); + goto exit_free_gpio; + } + enable_irq_wake(gpio_to_irq(o_ctrl->irq_gpio)); + rc = cam_ois_init_subdev_param(o_ctrl); if (rc) goto free_soc; @@ -330,6 +523,7 @@ static int32_t cam_ois_platform_driver_probe( (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_status)) || (device_create_file(&pdev->dev, &dev_attr_ois_reg)) || + (device_create_file(&pdev->dev, &dev_attr_ois_timestamps_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_gain_set)) || (device_create_file(&pdev->dev, &dev_attr_ois_init_before_sr_test))) { @@ -346,8 +540,16 @@ static int32_t cam_ois_platform_driver_probe( platform_set_drvdata(pdev, o_ctrl); o_ctrl->cam_ois_state = CAM_OIS_INIT; o_ctrl->open_cnt = 0; + + o_ctrl_vsync = o_ctrl; + position_X_Y_timestamps = (uint8_t *) + vzalloc(80 * sizeof(uint8_t)); + timestamp_ois = 0; return rc; + +exit_free_gpio: + gpio_free(o_ctrl->irq_gpio); unreg_subdev: cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); free_soc: @@ -377,6 +579,7 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_ois_status); device_remove_file(&pdev->dev, &dev_attr_ois_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_reg); + device_remove_file(&pdev->dev, &dev_attr_ois_timestamps_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_gain_set); device_remove_file(&pdev->dev, &dev_attr_ois_init_before_sr_test); CAM_ERR(CAM_OIS, " device_remove_file node"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index d3ba747d96e7..a5be088ec2ea 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -119,6 +119,11 @@ struct cam_ois_ctrl_t { enum msm_camera_device_type_t ois_device_type; enum cam_ois_state cam_ois_state; char ois_name[32]; + int irq_gpio; + struct pinctrl *vsync_pinctrl; + struct pinctrl_state *pin_default; + struct workqueue_struct *ois_vsync_wq; + struct work_struct ois_vsync_work; uint8_t ois_fw_flag; uint8_t is_ois_calib; struct cam_ois_opcode opcode; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c index 9c14d87e233d..b0fd63a6dc6f 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -113,6 +113,30 @@ int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl) CAM_DBG(CAM_OIS, "cci-device %d", o_ctrl->cci_num, rc); } + o_ctrl->irq_gpio = of_get_named_gpio(of_node, "interrupt-gpios", 0); + if (o_ctrl->irq_gpio < 0) + { + + CAM_DBG(CAM_OIS, "Looking up %s property failed. rc = %d\n", + "interrupt-gpios", o_ctrl->irq_gpio); + } + else + { + rc = gpio_request(o_ctrl->irq_gpio, "OIS_VSYNC_INTERRUPT"); + if (rc) + { + CAM_DBG(CAM_OIS, "Failed to request gpio %d,rc = %d", + o_ctrl->irq_gpio, rc); + } + rc = gpio_direction_input(o_ctrl->irq_gpio); + if (rc) + { + + CAM_DBG(CAM_OIS, "Unable to set direction for irq gpio [%d]\n", + o_ctrl->irq_gpio); + gpio_free(o_ctrl->irq_gpio); + } + } rc = cam_ois_get_dt_data(o_ctrl); if (rc < 0) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt index 9d37aaa52985..485f06bfdeb9 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt @@ -652,6 +652,14 @@ {.reg_addr = 0x3C0D,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x3C0E,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x3C0F,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3041,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x424A,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x424B,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4B48,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4B49,.reg_data = 0x15,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x423D,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4225,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3040,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E1D,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E25,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E38,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, -- GitLab From c67af52f3b09eab6ff43af844e666c6dbc19105d Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Tue, 28 Sep 2021 17:47:48 +0800 Subject: [PATCH 389/410] [ALM:11087279] [FP4]:ois fw &&&%%%comment:[FP4]:ois fw &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 479 +++++++++++++++++- 1 file changed, 477 insertions(+), 2 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index dfed5fddc158..8a018ccd62c1 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -16,12 +16,22 @@ #define default_gain_X 0.075 #define default_gain_Y 0.05 +#define FW_VERSION_MAJOR 0x0001 +#define FW_VERSION_MINOR 0x002B +#define OIS_FW_FILE "/vendor/etc/camera/cm401_fw.txt" + typedef struct REGSETTING{ uint16_t reg ; uint16_t val ; }REGSETTING ; +typedef struct REGSETTING_1{ + uint16_t reg ; + uint32_t val ; +}REGSETTING_1 ; + + static int32_t gyro_offset_X = 0; static int32_t gyro_offset_Y = 0; static int32_t gyro_offset_X_check = -1; @@ -761,6 +771,11 @@ const REGSETTING cml_ois_control[]= { {0x9b2a ,0x0002} ,//[9] }; +const REGSETTING_1 cml_ois_fw[]= { + {0x302c ,0x000012b7} ,//[0] +}; + + static int cam_ois_init(struct cam_ois_ctrl_t *o_ctrl) { uint16_t total_bytes = 0; @@ -989,6 +1004,428 @@ static int cam_cml_ois_disable(struct cam_ois_ctrl_t *o_ctrl) return rc; } +static int32_t get_size_from_file(const char *filename, uint64_t* size) +{ + struct kstat stat; + mm_segment_t fs; + int rc = 0; + + stat.size = 0; + + fs = get_fs(); + set_fs(KERNEL_DS); + + rc = vfs_stat(filename,&stat); + if(rc < 0) + { + pr_err("vfs_stat(%s) failed, rc = %d\n",filename,rc); + rc = -1; + goto END; + } + + *size = stat.size; + END: + set_fs(fs); + return rc; +} + +static int read_file_into_buffer(const char *filename, uint8_t* data, uint32_t size) +{ + struct file *fp; + mm_segment_t fs; + loff_t pos; + int rc; + + fp = filp_open(filename,O_RDONLY,S_IRWXU | S_IRWXG | S_IRWXO); + if (IS_ERR(fp)) { + pr_err("open(%s) failed\n", filename); + return -1; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + + pos = 0; + rc = vfs_read(fp, data, size, &pos); + + set_fs(fs); + filp_close(fp, NULL); + + return rc; +} + +static uint32_t change_byte_to_dword_data(uint8_t* pBuffer,int count,int size) +{ + uint32_t read_data=0; + uint32_t tmp[8]={0}; + int i=0; + + for(i=0;i47) + pBuffer[count+i] = pBuffer[count+i] - 48; + else if(pBuffer[count+i] < 103 && pBuffer[count+i]>96) + pBuffer[count+i] = pBuffer[count+i] -87; + + tmp[i]= pBuffer[count+i]; + } + read_data = ((tmp[6]<<28)&0xF0000000) | + ((tmp[7]<<24)&0x0F000000) | + ((tmp[4]<<20)&0x00F00000) | + ((tmp[5]<<16)&0x000F0000) | + ((tmp[2]<<12)&0x0000F000) | + ((tmp[3]<<8)&0x00000F00) | + ((tmp[0]<<4)&0x000000F0) | + ((tmp[1]<<0)&0x0000000F); + + return read_data; +} + + +static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + uint16_t total_bytes_1 = 0; + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct cam_sensor_i2c_reg_setting i2c_reg_setting_1; + struct page *page = NULL; + struct page *page_1 = NULL; + uint32_t fw_size,fw_size_1; + unsigned short addr= 0; + uint32_t csH=0,csL=0; + uint32_t mcs_checksum_flash=0,if_checksum_flash=0; + int get_size = 0; + uint64_t size; + uint8_t* pBuffer; + int i= 0; + uint32_t read_data=0; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + rc = get_size_from_file(OIS_FW_FILE, &size); + CAM_ERR(CAM_OIS, "size 0x%x",size); + if (rc != 0) + CAM_ERR(CAM_OIS, "get ois fw file size failed."); + + pBuffer = kzalloc(size, GFP_KERNEL); + + if (pBuffer) { + get_size = read_file_into_buffer(OIS_FW_FILE, pBuffer, size); + CAM_ERR(CAM_OIS, "get_size 0x%x",get_size); + if(get_size < 0) + kfree(pBuffer); + }else{ + CAM_ERR(CAM_OIS,"alloc buffer fail\n"); + } + +#if 1 + total_bytes = sizeof(cml_ois_control[0]); + total_bytes_1 = sizeof(cml_ois_fw[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + i2c_reg_setting_1.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting_1.data_type = CAMERA_SENSOR_I2C_TYPE_DWORD; + i2c_reg_setting_1.size = total_bytes_1; + i2c_reg_setting_1.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return -ENOMEM; + } + + fw_size_1 = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes_1) >> PAGE_SHIFT; + page_1 = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)),fw_size_1, 0, GFP_KERNEL); + if (!page_1) { + CAM_ERR(CAM_OIS, "Failed in allocating page_1 i2c_array"); + return -ENOMEM; + } + + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + i2c_reg_setting_1.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page_1)); + + /* cm4x1_MCS_download begin*/ + mdelay(1); + i2c_reg_setting.reg_setting[0].reg_addr = 0x0020; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0020 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(1); + i2c_reg_setting.reg_setting[0].reg_addr = 0x0024; + i2c_reg_setting.reg_setting[0].reg_data = 0x0000; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(1); + i2c_reg_setting.reg_setting[0].reg_addr = 0x0220; + i2c_reg_setting.reg_setting[0].reg_data = 0xC0D4; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0220 -> 0xC0D4"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(1); + i2c_reg_setting.reg_setting[0].reg_addr = 0x3000; + i2c_reg_setting.reg_setting[0].reg_data = 0x0000; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3000 -> 0x0000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + mdelay(1); + + addr = 0x8000;//MCS_START_ADDRESS + for (i=0; i < 16; i++) + { + //erase address + i2c_reg_setting.reg_setting[0].reg_addr = 0x3008; + i2c_reg_setting.reg_setting[0].reg_data = addr; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3008 -> 0x%x",addr); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(1); + //erase sector 2kbyte + i2c_reg_setting.reg_setting[0].reg_addr = 0x300C; + i2c_reg_setting.reg_setting[0].reg_data = 0x0002; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x300C -> 0x0002"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + addr += 0x800; //2kbyte + mdelay(5); + } + + /* flash fw write */ + addr = 0x8000;//MCS_START_ADDRESS + for(i=0;i<65536;i+=8){ + read_data=change_byte_to_dword_data(pBuffer,i,8); + //CAM_ERR(CAM_OIS, "read_data[%d]:0x%x,",i/4,read_data); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x3028; + i2c_reg_setting.reg_setting[0].reg_data = addr; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3028 -> 0x%x",addr); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + addr += 0x4; //2kbyte + + /* program sequential write 2K byte */ + i2c_reg_setting_1.reg_setting[0].reg_addr = 0x302C; + i2c_reg_setting_1.reg_setting[0].reg_data = read_data; + i2c_reg_setting_1.reg_setting[0].delay = 1; + i2c_reg_setting_1.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x302C -> 0x%x",read_data); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting_1); + } + + i2c_reg_setting.reg_setting[0].reg_addr = 0x3048; + i2c_reg_setting.reg_setting[0].reg_data = 0x8000; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3048 -> 0x8000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x304C; + i2c_reg_setting.reg_setting[0].reg_data = 0x2000; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x304C -> 0x2000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + mdelay(1); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x3050; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3050 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + mdelay(1); + + rc = camera_io_dev_read(&(o_ctrl->io_master_info),0x3054,&csH,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "csH : 0x%x",csH); + rc = camera_io_dev_read(&(o_ctrl->io_master_info),0x3058,&csL,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "csL : 0x%x",csL); + mcs_checksum_flash = (csH << 16) + csL; + //if(mcs_checksum_criteria != mcs_checksum_flash) + //{ + // msg = CHECKSUM_ERROR; + // log_tprintf(1, _T("mcs checksum fail, mcs_checksum_criteria: 0x%08X, mcs_checksum_flash: 0x%08X"), mcs_checksum_criteria, mcs_checksum_flash); + //code protection on + // RamWriteA(0x0220, 0x0000); + // return msg; + //} + CAM_ERR(CAM_OIS, "mcs_checksum_flash : 0x%08X",mcs_checksum_flash); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x0018; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + mdelay(10); + + /* cm4x1_MCS_download end*/ + + /* cm4x1_IF_download begin*/ + + //chip enable + i2c_reg_setting.reg_setting[0].reg_addr = 0x0020; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0020 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + //stanby mode(MCU off) + i2c_reg_setting.reg_setting[0].reg_addr = 0x0024; + i2c_reg_setting.reg_setting[0].reg_data = 0x0000; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + //code protection + i2c_reg_setting.reg_setting[0].reg_addr = 0x0220; + i2c_reg_setting.reg_setting[0].reg_data = 0xC0D4; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0220 -> 0xC0D4"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + //select if flash + i2c_reg_setting.reg_setting[0].reg_addr = 0x3000; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3000 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + mdelay(1); + addr = 0x0000; + for (i=0; i < 4; i++) + { + //erase address + i2c_reg_setting.reg_setting[0].reg_addr = 0x3008; + i2c_reg_setting.reg_setting[0].reg_data = addr; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3008 -> 0x%x",addr); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + //erase page 512 byte + i2c_reg_setting.reg_setting[0].reg_addr = 0x300C; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x300C -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + addr += 0x200; //512 byte + mdelay(5); + } + addr = 0x0000; + for (i = 65536; i < 69632; i+=8) + { + /* program sequential write 2K byte */ + read_data=change_byte_to_dword_data(pBuffer,i,8); + //CAM_ERR(CAM_OIS, "read_data[%d]:0x%x,",i/4,read_data); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x3028; + i2c_reg_setting.reg_setting[0].reg_data = addr; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3028 -> 0x%x",addr); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + addr += 0x4; + + /* program sequential write 2K byte */ + i2c_reg_setting_1.reg_setting[0].reg_addr = 0x302C; + i2c_reg_setting_1.reg_setting[0].reg_data = read_data; + i2c_reg_setting_1.reg_setting[0].delay = 1; + i2c_reg_setting_1.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x302C -> 0x%x",read_data); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting_1); + } + + /* Checksum calculation for fw data */ + + /* Set the checksum area */ + i2c_reg_setting.reg_setting[0].reg_addr = 0x3048; + i2c_reg_setting.reg_setting[0].reg_data = 0x0000; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3048 -> 0x0000"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x304C; + i2c_reg_setting.reg_setting[0].reg_data = 0x0200; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x304C -> 0x0200"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x3050; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x3050 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + mdelay(1); + + rc = camera_io_dev_read(&(o_ctrl->io_master_info),0x3054,&csH,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "csH : 0x%x",csH); + rc = camera_io_dev_read(&(o_ctrl->io_master_info),0x3058,&csL,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "csL : 0x%x",csL); + rc = camera_io_dev_read(&(o_ctrl->io_master_info),0x3058,&csL,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "csL : 0x%x",csL); + + if_checksum_flash = (csH << 16) + csL; + //if(if_checksum_criteria != if_checksum_flash) + //{ + // msg = CHECKSUM_ERROR; + // log_tprintf(1, _T("if checksum fail, if_checksum_criteria: 0x%08X, if_checksum_flash: 0x%08X"), if_checksum_criteria, if_checksum_flash); + //code protection on + // RamWriteA(0x0220, 0x0000); + // return msg; + //} + + CAM_ERR(CAM_OIS, "if_checksum_flash : 0x%08X",if_checksum_flash); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x0018; + i2c_reg_setting.reg_setting[0].reg_data = 0x0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + mdelay(10); + + /* cm4x1_IF_download end*/ + kfree(pBuffer); + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page_1, fw_size_1); + page = NULL; + page_1 = NULL; + +#endif + return rc; +} + + ssize_t ois_reg_show(struct device *dev, struct device_attribute *attr, char *buf){ return sprintf(buf, "0x%x\n", ois_reg_value); @@ -1003,6 +1440,8 @@ ssize_t ois_reg_store(struct device *dev, struct device_attribute *attr, const char flag; int rc = 0; int i = 0; + uint32_t fw_version_major = 0; + uint32_t fw_version_minor = 0; uint16_t total_bytes = 0; struct cam_sensor_i2c_reg_setting i2c_reg_setting; @@ -1067,6 +1506,44 @@ ssize_t ois_reg_store(struct device *dev, struct device_attribute *attr, const } mdelay(50); } + else if (flag == 'u')//upgrade fw + { + mdelay(10); + cmd_adress = 0x9b08; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&fw_version_major,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "read 0x9b08 -> 0x%x",fw_version_major); + + mdelay(10); + cmd_adress = 0x9b0a; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&fw_version_minor,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "read 0x9b0a -> 0x%x",fw_version_minor); + if (fw_version_major == FW_VERSION_MAJOR && fw_version_minor == FW_VERSION_MINOR) + { + CAM_ERR(CAM_OIS, "The fw version of ois is already up to date,fw_version:0x%x-0x%x ",fw_version_major,fw_version_minor); + } + else + { + CAM_ERR(CAM_OIS, "The fw version of ois is old,current fw_version:0x%x-0x%x ,target fw_version:0x%x-0x%x.Now begin to upgrate!!!",fw_version_major,fw_version_minor,FW_VERSION_MAJOR,FW_VERSION_MINOR); + rc = cam_cml_ois_fw_upgrade(o_ctrl); + + mdelay(10); + cmd_adress = 0x9b08; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&fw_version_major,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "read 0x9b08 -> 0x%x",fw_version_major); + + mdelay(10); + cmd_adress = 0x9b0a; + rc = camera_io_dev_read(&(o_ctrl->io_master_info),cmd_adress,&fw_version_minor,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "read 0x9b0a -> 0x%x",fw_version_minor); + if (fw_version_major == FW_VERSION_MAJOR && fw_version_minor == FW_VERSION_MINOR) + { + CAM_ERR(CAM_OIS, "upgrade success!!!"); + } + else + CAM_ERR(CAM_OIS, "upgrade failed!!!"); + + } + } else { if (flag == 'k') @@ -1091,8 +1568,6 @@ ssize_t ois_reg_store(struct device *dev, struct device_attribute *attr, const } } - - return count; } -- GitLab From 31568e078e71681efcada3044a5ccecc3caef5be Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Sun, 10 Oct 2021 10:19:11 +0800 Subject: [PATCH 390/410] [ALM:11087279] [FP4]:remove dbg log &&&%%%comment:[FP4]:remove dbg log &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- drivers/cam_sensor_module/cam_ois/cam_ois_dev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index b297c27561bc..54e8e0a54dc4 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -284,31 +284,31 @@ static void ois_vsync_function(struct work_struct *work) i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); + //CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; i2c_reg_setting.reg_setting[0].reg_data = 0X0001; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); + //CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; i2c_reg_setting.reg_setting[0].reg_data = 0X0001; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); + //CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); + //CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; i2c_reg_setting.reg_setting[0].reg_data = 0X0001; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); + //CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); mdelay(1); -- GitLab From ff45efb127df8e7350aa1c4af13d8ab46d79f8c2 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 11 Oct 2021 13:31:49 +0800 Subject: [PATCH 391/410] [ALM:11087279] [FP4]:catch ois data after cci is ready. &&&%%%comment:[FP4]:catch ois data after cci is ready. &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 5 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 163 +++++++++--------- 2 files changed, 88 insertions(+), 80 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index 10f274c907eb..625a1c7058d2 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -6,6 +6,9 @@ #include "cam_cci_dev.h" #include "cam_cci_core.h" +enum cam_cci_state_t cci_state_for_vsync = 0; + + static int cam_cci_init_master(struct cci_device *cci_dev, enum cci_i2c_master_t master) { @@ -186,6 +189,7 @@ int cam_cci_init(struct v4l2_subdev *sd, base + CCI_I2C_M1_RD_THRESHOLD_ADDR); cci_dev->cci_state = CCI_STATE_ENABLED; + cci_state_for_vsync = 1; return 0; @@ -433,6 +437,7 @@ int cam_cci_soc_release(struct cci_device *cci_dev, } cci_dev->cci_state = CCI_STATE_DISABLED; + cci_state_for_vsync = 0; cci_dev->cycles_per_us = 0; cam_cpas_stop(cci_dev->cpas_handle); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 54e8e0a54dc4..dc1c00427643 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -18,7 +18,7 @@ struct cam_ois_ctrl_t *o_ctrl_vsync = NULL; int64_t timestamp_ois; uint8_t *position_X_Y_timestamps=NULL; uint8_t data_for_vsync[28] = {0}; - +extern enum cam_cci_state_t cci_state_for_vsync; typedef struct REGSETTING{ uint16_t reg ; @@ -265,87 +265,90 @@ static void ois_vsync_function(struct work_struct *work) CAM_ERR(CAM_OIS, "Invalid Args"); return; } - total_bytes = sizeof(ois_fw_control[0]); + if (cci_state_for_vsync) + { + total_bytes = sizeof(ois_fw_control[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return; + } + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); - i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.size = total_bytes; - i2c_reg_setting.delay = 0; - - fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; - page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); - if (!page) { - CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); - return; + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; + i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + //CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + mdelay(1); + + rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); + + data_for_vsync[0] = position_X_Y_timestamps[6]; + data_for_vsync[1] = position_X_Y_timestamps[7];//6X + data_for_vsync[2] = position_X_Y_timestamps[8]; + data_for_vsync[3] = position_X_Y_timestamps[9];//6Y + data_for_vsync[4] = position_X_Y_timestamps[22]; + data_for_vsync[5] = position_X_Y_timestamps[23];//7X + data_for_vsync[6] = position_X_Y_timestamps[24]; + data_for_vsync[7] = position_X_Y_timestamps[25];//7Y + data_for_vsync[8] = position_X_Y_timestamps[38]; + data_for_vsync[9] = position_X_Y_timestamps[39];//8X + data_for_vsync[10] = position_X_Y_timestamps[40]; + data_for_vsync[11] = position_X_Y_timestamps[41];//8Y + data_for_vsync[12] = position_X_Y_timestamps[54]; + data_for_vsync[13] = position_X_Y_timestamps[55];//9X + data_for_vsync[14] = position_X_Y_timestamps[56]; + data_for_vsync[15] = position_X_Y_timestamps[57];//9Y + data_for_vsync[16] = position_X_Y_timestamps[70]; + data_for_vsync[17] = position_X_Y_timestamps[71];//10X + data_for_vsync[18] = position_X_Y_timestamps[72]; + data_for_vsync[19] = position_X_Y_timestamps[73];//10Y + + data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); + data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); + data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); + data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); + data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); + data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); + data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); + data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); + + cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); + page = NULL; } - i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; - i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - //CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - mdelay(1); - - rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); - - data_for_vsync[0] = position_X_Y_timestamps[6]; - data_for_vsync[1] = position_X_Y_timestamps[7];//6X - data_for_vsync[2] = position_X_Y_timestamps[8]; - data_for_vsync[3] = position_X_Y_timestamps[9];//6Y - data_for_vsync[4] = position_X_Y_timestamps[22]; - data_for_vsync[5] = position_X_Y_timestamps[23];//7X - data_for_vsync[6] = position_X_Y_timestamps[24]; - data_for_vsync[7] = position_X_Y_timestamps[25];//7Y - data_for_vsync[8] = position_X_Y_timestamps[38]; - data_for_vsync[9] = position_X_Y_timestamps[39];//8X - data_for_vsync[10] = position_X_Y_timestamps[40]; - data_for_vsync[11] = position_X_Y_timestamps[41];//8Y - data_for_vsync[12] = position_X_Y_timestamps[54]; - data_for_vsync[13] = position_X_Y_timestamps[55];//9X - data_for_vsync[14] = position_X_Y_timestamps[56]; - data_for_vsync[15] = position_X_Y_timestamps[57];//9Y - data_for_vsync[16] = position_X_Y_timestamps[70]; - data_for_vsync[17] = position_X_Y_timestamps[71];//10X - data_for_vsync[18] = position_X_Y_timestamps[72]; - data_for_vsync[19] = position_X_Y_timestamps[73];//10Y - - data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); - data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); - data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); - data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); - data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); - data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); - data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); - data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); - - cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); - page = NULL; } -- GitLab From 2c877562302951097875c677d7a1ab28536ba3a8 Mon Sep 17 00:00:00 2001 From: Fairphone ODM Date: Wed, 13 Oct 2021 17:32:38 +0800 Subject: [PATCH 392/410] Revert "[ALM:11087279] [FP4]:catch ois data after cci is ready." This reverts commit ea589bfbd59bacaff438882b1890ec1d934abf7e. Change-Id: I0a811dc74e0cdfc2ad4d8be18e7c269f8a4ff675 --- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 5 - .../cam_sensor_module/cam_ois/cam_ois_dev.c | 163 +++++++++--------- 2 files changed, 80 insertions(+), 88 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index 625a1c7058d2..10f274c907eb 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -6,9 +6,6 @@ #include "cam_cci_dev.h" #include "cam_cci_core.h" -enum cam_cci_state_t cci_state_for_vsync = 0; - - static int cam_cci_init_master(struct cci_device *cci_dev, enum cci_i2c_master_t master) { @@ -189,7 +186,6 @@ int cam_cci_init(struct v4l2_subdev *sd, base + CCI_I2C_M1_RD_THRESHOLD_ADDR); cci_dev->cci_state = CCI_STATE_ENABLED; - cci_state_for_vsync = 1; return 0; @@ -437,7 +433,6 @@ int cam_cci_soc_release(struct cci_device *cci_dev, } cci_dev->cci_state = CCI_STATE_DISABLED; - cci_state_for_vsync = 0; cci_dev->cycles_per_us = 0; cam_cpas_stop(cci_dev->cpas_handle); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index dc1c00427643..54e8e0a54dc4 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -18,7 +18,7 @@ struct cam_ois_ctrl_t *o_ctrl_vsync = NULL; int64_t timestamp_ois; uint8_t *position_X_Y_timestamps=NULL; uint8_t data_for_vsync[28] = {0}; -extern enum cam_cci_state_t cci_state_for_vsync; + typedef struct REGSETTING{ uint16_t reg ; @@ -265,90 +265,87 @@ static void ois_vsync_function(struct work_struct *work) CAM_ERR(CAM_OIS, "Invalid Args"); return; } - if (cci_state_for_vsync) - { - total_bytes = sizeof(ois_fw_control[0]); - - i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.size = total_bytes; - i2c_reg_setting.delay = 0; - - fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; - page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); - if (!page) { - CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); - return; - } - i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; - i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - //CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - mdelay(1); - - rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); - - data_for_vsync[0] = position_X_Y_timestamps[6]; - data_for_vsync[1] = position_X_Y_timestamps[7];//6X - data_for_vsync[2] = position_X_Y_timestamps[8]; - data_for_vsync[3] = position_X_Y_timestamps[9];//6Y - data_for_vsync[4] = position_X_Y_timestamps[22]; - data_for_vsync[5] = position_X_Y_timestamps[23];//7X - data_for_vsync[6] = position_X_Y_timestamps[24]; - data_for_vsync[7] = position_X_Y_timestamps[25];//7Y - data_for_vsync[8] = position_X_Y_timestamps[38]; - data_for_vsync[9] = position_X_Y_timestamps[39];//8X - data_for_vsync[10] = position_X_Y_timestamps[40]; - data_for_vsync[11] = position_X_Y_timestamps[41];//8Y - data_for_vsync[12] = position_X_Y_timestamps[54]; - data_for_vsync[13] = position_X_Y_timestamps[55];//9X - data_for_vsync[14] = position_X_Y_timestamps[56]; - data_for_vsync[15] = position_X_Y_timestamps[57];//9Y - data_for_vsync[16] = position_X_Y_timestamps[70]; - data_for_vsync[17] = position_X_Y_timestamps[71];//10X - data_for_vsync[18] = position_X_Y_timestamps[72]; - data_for_vsync[19] = position_X_Y_timestamps[73];//10Y - - data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); - data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); - data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); - data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); - data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); - data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); - data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); - data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); + total_bytes = sizeof(ois_fw_control[0]); - cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); - page = NULL; + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return; } + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; + i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + //CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + //CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + mdelay(1); + + rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); + + data_for_vsync[0] = position_X_Y_timestamps[6]; + data_for_vsync[1] = position_X_Y_timestamps[7];//6X + data_for_vsync[2] = position_X_Y_timestamps[8]; + data_for_vsync[3] = position_X_Y_timestamps[9];//6Y + data_for_vsync[4] = position_X_Y_timestamps[22]; + data_for_vsync[5] = position_X_Y_timestamps[23];//7X + data_for_vsync[6] = position_X_Y_timestamps[24]; + data_for_vsync[7] = position_X_Y_timestamps[25];//7Y + data_for_vsync[8] = position_X_Y_timestamps[38]; + data_for_vsync[9] = position_X_Y_timestamps[39];//8X + data_for_vsync[10] = position_X_Y_timestamps[40]; + data_for_vsync[11] = position_X_Y_timestamps[41];//8Y + data_for_vsync[12] = position_X_Y_timestamps[54]; + data_for_vsync[13] = position_X_Y_timestamps[55];//9X + data_for_vsync[14] = position_X_Y_timestamps[56]; + data_for_vsync[15] = position_X_Y_timestamps[57];//9Y + data_for_vsync[16] = position_X_Y_timestamps[70]; + data_for_vsync[17] = position_X_Y_timestamps[71];//10X + data_for_vsync[18] = position_X_Y_timestamps[72]; + data_for_vsync[19] = position_X_Y_timestamps[73];//10Y + + data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); + data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); + data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); + data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); + data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); + data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); + data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); + data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); + + cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); + page = NULL; } -- GitLab From 3e7f448a2d49dcb016b7e1f5367d0ea99859f2fa Mon Sep 17 00:00:00 2001 From: Fairphone ODM Date: Wed, 13 Oct 2021 17:33:01 +0800 Subject: [PATCH 393/410] Revert "[ALM:11087279] [FP4]:remove dbg log" This reverts commit a7af53307cf0ced0bf914afb59f547d3107ed139. Change-Id: I5751b1cb5c8266b3d209722b14e59337d268585f --- drivers/cam_sensor_module/cam_ois/cam_ois_dev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 54e8e0a54dc4..b297c27561bc 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -284,31 +284,31 @@ static void ois_vsync_function(struct work_struct *work) i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); + CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; i2c_reg_setting.reg_setting[0].reg_data = 0X0001; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); + CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; i2c_reg_setting.reg_setting[0].reg_data = 0X0001; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); + CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - //CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); + CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; i2c_reg_setting.reg_setting[0].reg_data = 0X0001; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - //CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); + CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); mdelay(1); -- GitLab From bc574154624c4c8a31e0d31351d5b6db3e75a24d Mon Sep 17 00:00:00 2001 From: Fairphone ODM Date: Wed, 13 Oct 2021 17:33:47 +0800 Subject: [PATCH 394/410] Revert "[ALM:11087279] [FP4]:ois vsync" This reverts commit c4269e69a91d11ee3923d26f73e75b90417394cc. Change-Id: Id430406efa20a8ce0a1543373b47f3173e331abd --- .../cam_sensor_module/cam_ois/cam_ois_core.h | 2 - .../cam_sensor_module/cam_ois/cam_ois_dev.c | 203 ------------------ .../cam_sensor_module/cam_ois/cam_ois_dev.h | 5 - .../cam_sensor_module/cam_ois/cam_ois_soc.c | 24 --- .../cam_sensor/cam_sensor_initsetting.h.txt | 8 - 5 files changed, 242 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index bd5f5fe46b2f..7b49ecf0f8bf 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -42,7 +42,5 @@ ssize_t ois_init_before_sr_test_show(struct device *dev, struct device_attribute ssize_t ois_init_before_sr_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_gain_set_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_gain_set_show(struct device *dev, struct device_attribute *attr, char *buf); -ssize_t ois_timestamps_position_show(struct device *dev, struct device_attribute *attr, char *buf); - #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index b297c27561bc..cb1046c87aea 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -8,28 +8,6 @@ #include "cam_ois_soc.h" #include "cam_ois_core.h" #include "cam_debug_util.h" -#include -#include -#include -#include -#include - -struct cam_ois_ctrl_t *o_ctrl_vsync = NULL; -int64_t timestamp_ois; -uint8_t *position_X_Y_timestamps=NULL; -uint8_t data_for_vsync[28] = {0}; - - -typedef struct REGSETTING{ - uint16_t reg ; - uint16_t val ; -}REGSETTING ; - -const REGSETTING ois_fw_control[]= { - {0x9b2c ,0x0001} ,//[0] -}; - - static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) @@ -195,159 +173,12 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) return rc; } -ssize_t ois_timestamps_position_show(struct device *dev, struct device_attribute *attr, char *buf){ - - int i = 0, len = 0; - - for( i = 0; i < 28; i++) - len += sprintf(buf + len, "0x%x,", data_for_vsync[i]); - len +=sprintf(buf + len , "\n"); - - return len; - -} - DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_store); DEVICE_ATTR(ois_status, 0664, ois_status_show, ois_status_store); DEVICE_ATTR(ois_reg, 0664, ois_reg_show, ois_reg_store); DEVICE_ATTR(ois_init_before_sr_test, 0664, ois_init_before_sr_test_show, ois_init_before_sr_test_store); DEVICE_ATTR(ois_gain_set, 0664, ois_gain_set_show, ois_gain_set_store); -DEVICE_ATTR(ois_timestamps_position_data, 0664, ois_timestamps_position_show, NULL); - - -static int cml_vsync_pinctrl_init(struct cam_ois_ctrl_t *o_ctrl) -{ - int retval = 0; - - /* Get pinctrl if target uses pinctrl */ - o_ctrl->vsync_pinctrl = devm_pinctrl_get((o_ctrl->pdev->dev.parent)); - if (IS_ERR_OR_NULL(o_ctrl->vsync_pinctrl)) { - retval = PTR_ERR(o_ctrl->vsync_pinctrl); - CAM_ERR(CAM_OIS, "Target does not use pinctrl %d\n", retval); - goto err_pinctrl_get; - } - - o_ctrl->pin_default = pinctrl_lookup_state(o_ctrl->vsync_pinctrl, "default"); - if (IS_ERR_OR_NULL(o_ctrl->pin_default)) { - retval = PTR_ERR(o_ctrl->pin_default); - CAM_ERR(CAM_OIS, "Failed to look up default state\n"); - goto err_pinctrl_lookup; - } - - return retval; - -err_pinctrl_lookup: - devm_pinctrl_put(o_ctrl->vsync_pinctrl); -err_pinctrl_get: - o_ctrl->vsync_pinctrl = NULL; - return retval; -} - -irqreturn_t interrupt_ois_vsync_irq(int irq, void *dev) -{ - timestamp_ois = ktime_get_real_ns(); - queue_work(o_ctrl_vsync->ois_vsync_wq, &o_ctrl_vsync->ois_vsync_work); - - return IRQ_HANDLED; -} - -static void ois_vsync_function(struct work_struct *work) -{ - uint16_t total_bytes = 0; - int32_t rc = 0; - struct cam_sensor_i2c_reg_setting i2c_reg_setting; - struct page *page = NULL; - uint32_t fw_size; - uint32_t cmd_data=0; - - if (!o_ctrl_vsync) { - CAM_ERR(CAM_OIS, "Invalid Args"); - return; - } - total_bytes = sizeof(ois_fw_control[0]); - - i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.size = total_bytes; - i2c_reg_setting.delay = 0; - - fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; - page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); - if (!page) { - CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); - return; - } - i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; - i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - mdelay(1); - - rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); - - data_for_vsync[0] = position_X_Y_timestamps[6]; - data_for_vsync[1] = position_X_Y_timestamps[7];//6X - data_for_vsync[2] = position_X_Y_timestamps[8]; - data_for_vsync[3] = position_X_Y_timestamps[9];//6Y - data_for_vsync[4] = position_X_Y_timestamps[22]; - data_for_vsync[5] = position_X_Y_timestamps[23];//7X - data_for_vsync[6] = position_X_Y_timestamps[24]; - data_for_vsync[7] = position_X_Y_timestamps[25];//7Y - data_for_vsync[8] = position_X_Y_timestamps[38]; - data_for_vsync[9] = position_X_Y_timestamps[39];//8X - data_for_vsync[10] = position_X_Y_timestamps[40]; - data_for_vsync[11] = position_X_Y_timestamps[41];//8Y - data_for_vsync[12] = position_X_Y_timestamps[54]; - data_for_vsync[13] = position_X_Y_timestamps[55];//9X - data_for_vsync[14] = position_X_Y_timestamps[56]; - data_for_vsync[15] = position_X_Y_timestamps[57];//9Y - data_for_vsync[16] = position_X_Y_timestamps[70]; - data_for_vsync[17] = position_X_Y_timestamps[71];//10X - data_for_vsync[18] = position_X_Y_timestamps[72]; - data_for_vsync[19] = position_X_Y_timestamps[73];//10Y - - data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); - data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); - data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); - data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); - data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); - data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); - data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); - data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); - - cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); - page = NULL; - -} static int cam_ois_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -490,31 +321,7 @@ static int32_t cam_ois_platform_driver_probe( CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc); goto free_soc; } - - rc = cml_vsync_pinctrl_init(o_ctrl); - if (!rc && o_ctrl->vsync_pinctrl) { - rc = pinctrl_select_state( - o_ctrl->vsync_pinctrl, - o_ctrl->pin_default); - if (rc < 0) { - CAM_ERR(CAM_OIS, "Can't select pinctrl state\n"); - } - } - - o_ctrl->ois_vsync_wq= create_singlethread_workqueue("ois_vsync_wq"); - INIT_WORK(&o_ctrl->ois_vsync_work, ois_vsync_function); - queue_work(o_ctrl->ois_vsync_wq, &o_ctrl->ois_vsync_work); - - rc = request_irq(gpio_to_irq(o_ctrl->irq_gpio), interrupt_ois_vsync_irq, IRQ_TYPE_EDGE_RISING , "ois_vsync_work", &o_ctrl->soc_info.dev); - if(rc < 0) - { - - CAM_ERR(CAM_OIS, "request_irq failed\n"); - goto exit_free_gpio; - } - enable_irq_wake(gpio_to_irq(o_ctrl->irq_gpio)); - rc = cam_ois_init_subdev_param(o_ctrl); if (rc) goto free_soc; @@ -523,7 +330,6 @@ static int32_t cam_ois_platform_driver_probe( (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_status)) || (device_create_file(&pdev->dev, &dev_attr_ois_reg)) || - (device_create_file(&pdev->dev, &dev_attr_ois_timestamps_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_gain_set)) || (device_create_file(&pdev->dev, &dev_attr_ois_init_before_sr_test))) { @@ -540,16 +346,8 @@ static int32_t cam_ois_platform_driver_probe( platform_set_drvdata(pdev, o_ctrl); o_ctrl->cam_ois_state = CAM_OIS_INIT; o_ctrl->open_cnt = 0; - - o_ctrl_vsync = o_ctrl; - position_X_Y_timestamps = (uint8_t *) - vzalloc(80 * sizeof(uint8_t)); - timestamp_ois = 0; return rc; - -exit_free_gpio: - gpio_free(o_ctrl->irq_gpio); unreg_subdev: cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); free_soc: @@ -579,7 +377,6 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_ois_status); device_remove_file(&pdev->dev, &dev_attr_ois_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_reg); - device_remove_file(&pdev->dev, &dev_attr_ois_timestamps_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_gain_set); device_remove_file(&pdev->dev, &dev_attr_ois_init_before_sr_test); CAM_ERR(CAM_OIS, " device_remove_file node"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index a5be088ec2ea..d3ba747d96e7 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -119,11 +119,6 @@ struct cam_ois_ctrl_t { enum msm_camera_device_type_t ois_device_type; enum cam_ois_state cam_ois_state; char ois_name[32]; - int irq_gpio; - struct pinctrl *vsync_pinctrl; - struct pinctrl_state *pin_default; - struct workqueue_struct *ois_vsync_wq; - struct work_struct ois_vsync_work; uint8_t ois_fw_flag; uint8_t is_ois_calib; struct cam_ois_opcode opcode; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c index b0fd63a6dc6f..9c14d87e233d 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -113,30 +113,6 @@ int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl) CAM_DBG(CAM_OIS, "cci-device %d", o_ctrl->cci_num, rc); } - o_ctrl->irq_gpio = of_get_named_gpio(of_node, "interrupt-gpios", 0); - if (o_ctrl->irq_gpio < 0) - { - - CAM_DBG(CAM_OIS, "Looking up %s property failed. rc = %d\n", - "interrupt-gpios", o_ctrl->irq_gpio); - } - else - { - rc = gpio_request(o_ctrl->irq_gpio, "OIS_VSYNC_INTERRUPT"); - if (rc) - { - CAM_DBG(CAM_OIS, "Failed to request gpio %d,rc = %d", - o_ctrl->irq_gpio, rc); - } - rc = gpio_direction_input(o_ctrl->irq_gpio); - if (rc) - { - - CAM_DBG(CAM_OIS, "Unable to set direction for irq gpio [%d]\n", - o_ctrl->irq_gpio); - gpio_free(o_ctrl->irq_gpio); - } - } rc = cam_ois_get_dt_data(o_ctrl); if (rc < 0) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt index 485f06bfdeb9..9d37aaa52985 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt @@ -652,14 +652,6 @@ {.reg_addr = 0x3C0D,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x3C0E,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x3C0F,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x3041,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x424A,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x424B,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x4B48,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x4B49,.reg_data = 0x15,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x423D,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x4225,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, -{.reg_addr = 0x3040,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E1D,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E25,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E38,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, -- GitLab From 5c6d9b0eb5665d5a9bfb68c4d5c5c030c4af649e Mon Sep 17 00:00:00 2001 From: Fairphone ODM Date: Mon, 15 Nov 2021 13:57:16 +0800 Subject: [PATCH 395/410] Revert "Revert "[ALM:11087279] [FP4]:ois vsync"" This reverts commit 3c61088a2d51c4609c08cdb9bb0022c74bd6c6e0. Change-Id: I64878fcc2073629259b2e9397252c56213933971 --- .../cam_sensor_module/cam_ois/cam_ois_core.h | 2 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 203 ++++++++++++++++++ .../cam_sensor_module/cam_ois/cam_ois_dev.h | 5 + .../cam_sensor_module/cam_ois/cam_ois_soc.c | 24 +++ .../cam_sensor/cam_sensor_initsetting.h.txt | 8 + 5 files changed, 242 insertions(+) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h index 7b49ecf0f8bf..bd5f5fe46b2f 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -42,5 +42,7 @@ ssize_t ois_init_before_sr_test_show(struct device *dev, struct device_attribute ssize_t ois_init_before_sr_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_gain_set_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); ssize_t ois_gain_set_show(struct device *dev, struct device_attribute *attr, char *buf); +ssize_t ois_timestamps_position_show(struct device *dev, struct device_attribute *attr, char *buf); + #endif /* _CAM_OIS_CORE_H_ */ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index cb1046c87aea..b297c27561bc 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -8,6 +8,28 @@ #include "cam_ois_soc.h" #include "cam_ois_core.h" #include "cam_debug_util.h" +#include +#include +#include +#include +#include + +struct cam_ois_ctrl_t *o_ctrl_vsync = NULL; +int64_t timestamp_ois; +uint8_t *position_X_Y_timestamps=NULL; +uint8_t data_for_vsync[28] = {0}; + + +typedef struct REGSETTING{ + uint16_t reg ; + uint16_t val ; +}REGSETTING ; + +const REGSETTING ois_fw_control[]= { + {0x9b2c ,0x0001} ,//[0] +}; + + static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) @@ -173,12 +195,159 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) return rc; } +ssize_t ois_timestamps_position_show(struct device *dev, struct device_attribute *attr, char *buf){ + + int i = 0, len = 0; + + for( i = 0; i < 28; i++) + len += sprintf(buf + len, "0x%x,", data_for_vsync[i]); + len +=sprintf(buf + len , "\n"); + + return len; + +} + DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_store); DEVICE_ATTR(ois_status, 0664, ois_status_show, ois_status_store); DEVICE_ATTR(ois_reg, 0664, ois_reg_show, ois_reg_store); DEVICE_ATTR(ois_init_before_sr_test, 0664, ois_init_before_sr_test_show, ois_init_before_sr_test_store); DEVICE_ATTR(ois_gain_set, 0664, ois_gain_set_show, ois_gain_set_store); +DEVICE_ATTR(ois_timestamps_position_data, 0664, ois_timestamps_position_show, NULL); + + +static int cml_vsync_pinctrl_init(struct cam_ois_ctrl_t *o_ctrl) +{ + int retval = 0; + + /* Get pinctrl if target uses pinctrl */ + o_ctrl->vsync_pinctrl = devm_pinctrl_get((o_ctrl->pdev->dev.parent)); + if (IS_ERR_OR_NULL(o_ctrl->vsync_pinctrl)) { + retval = PTR_ERR(o_ctrl->vsync_pinctrl); + CAM_ERR(CAM_OIS, "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + o_ctrl->pin_default = pinctrl_lookup_state(o_ctrl->vsync_pinctrl, "default"); + if (IS_ERR_OR_NULL(o_ctrl->pin_default)) { + retval = PTR_ERR(o_ctrl->pin_default); + CAM_ERR(CAM_OIS, "Failed to look up default state\n"); + goto err_pinctrl_lookup; + } + + return retval; + +err_pinctrl_lookup: + devm_pinctrl_put(o_ctrl->vsync_pinctrl); +err_pinctrl_get: + o_ctrl->vsync_pinctrl = NULL; + return retval; +} + +irqreturn_t interrupt_ois_vsync_irq(int irq, void *dev) +{ + timestamp_ois = ktime_get_real_ns(); + queue_work(o_ctrl_vsync->ois_vsync_wq, &o_ctrl_vsync->ois_vsync_work); + + return IRQ_HANDLED; +} + +static void ois_vsync_function(struct work_struct *work) +{ + uint16_t total_bytes = 0; + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + uint32_t fw_size; + uint32_t cmd_data=0; + + if (!o_ctrl_vsync) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return; + } + total_bytes = sizeof(ois_fw_control[0]); + + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + return; + } + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; + i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + + rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); + CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); + + i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; + i2c_reg_setting.reg_setting[0].reg_data = 0X0001; + i2c_reg_setting.reg_setting[0].delay = 1; + i2c_reg_setting.reg_setting[0].data_mask = 0; + CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); + rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); + mdelay(1); + + rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); + + data_for_vsync[0] = position_X_Y_timestamps[6]; + data_for_vsync[1] = position_X_Y_timestamps[7];//6X + data_for_vsync[2] = position_X_Y_timestamps[8]; + data_for_vsync[3] = position_X_Y_timestamps[9];//6Y + data_for_vsync[4] = position_X_Y_timestamps[22]; + data_for_vsync[5] = position_X_Y_timestamps[23];//7X + data_for_vsync[6] = position_X_Y_timestamps[24]; + data_for_vsync[7] = position_X_Y_timestamps[25];//7Y + data_for_vsync[8] = position_X_Y_timestamps[38]; + data_for_vsync[9] = position_X_Y_timestamps[39];//8X + data_for_vsync[10] = position_X_Y_timestamps[40]; + data_for_vsync[11] = position_X_Y_timestamps[41];//8Y + data_for_vsync[12] = position_X_Y_timestamps[54]; + data_for_vsync[13] = position_X_Y_timestamps[55];//9X + data_for_vsync[14] = position_X_Y_timestamps[56]; + data_for_vsync[15] = position_X_Y_timestamps[57];//9Y + data_for_vsync[16] = position_X_Y_timestamps[70]; + data_for_vsync[17] = position_X_Y_timestamps[71];//10X + data_for_vsync[18] = position_X_Y_timestamps[72]; + data_for_vsync[19] = position_X_Y_timestamps[73];//10Y + + data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); + data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); + data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); + data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); + data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); + data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); + data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); + data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); + + cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); + page = NULL; + +} static int cam_ois_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -321,7 +490,31 @@ static int32_t cam_ois_platform_driver_probe( CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc); goto free_soc; } + + rc = cml_vsync_pinctrl_init(o_ctrl); + if (!rc && o_ctrl->vsync_pinctrl) { + rc = pinctrl_select_state( + o_ctrl->vsync_pinctrl, + o_ctrl->pin_default); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Can't select pinctrl state\n"); + } + } + + o_ctrl->ois_vsync_wq= create_singlethread_workqueue("ois_vsync_wq"); + INIT_WORK(&o_ctrl->ois_vsync_work, ois_vsync_function); + queue_work(o_ctrl->ois_vsync_wq, &o_ctrl->ois_vsync_work); + + rc = request_irq(gpio_to_irq(o_ctrl->irq_gpio), interrupt_ois_vsync_irq, IRQ_TYPE_EDGE_RISING , "ois_vsync_work", &o_ctrl->soc_info.dev); + if(rc < 0) + { + + CAM_ERR(CAM_OIS, "request_irq failed\n"); + goto exit_free_gpio; + } + enable_irq_wake(gpio_to_irq(o_ctrl->irq_gpio)); + rc = cam_ois_init_subdev_param(o_ctrl); if (rc) goto free_soc; @@ -330,6 +523,7 @@ static int32_t cam_ois_platform_driver_probe( (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_status)) || (device_create_file(&pdev->dev, &dev_attr_ois_reg)) || + (device_create_file(&pdev->dev, &dev_attr_ois_timestamps_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_gain_set)) || (device_create_file(&pdev->dev, &dev_attr_ois_init_before_sr_test))) { @@ -346,8 +540,16 @@ static int32_t cam_ois_platform_driver_probe( platform_set_drvdata(pdev, o_ctrl); o_ctrl->cam_ois_state = CAM_OIS_INIT; o_ctrl->open_cnt = 0; + + o_ctrl_vsync = o_ctrl; + position_X_Y_timestamps = (uint8_t *) + vzalloc(80 * sizeof(uint8_t)); + timestamp_ois = 0; return rc; + +exit_free_gpio: + gpio_free(o_ctrl->irq_gpio); unreg_subdev: cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); free_soc: @@ -377,6 +579,7 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_ois_status); device_remove_file(&pdev->dev, &dev_attr_ois_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_reg); + device_remove_file(&pdev->dev, &dev_attr_ois_timestamps_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_gain_set); device_remove_file(&pdev->dev, &dev_attr_ois_init_before_sr_test); CAM_ERR(CAM_OIS, " device_remove_file node"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index d3ba747d96e7..a5be088ec2ea 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -119,6 +119,11 @@ struct cam_ois_ctrl_t { enum msm_camera_device_type_t ois_device_type; enum cam_ois_state cam_ois_state; char ois_name[32]; + int irq_gpio; + struct pinctrl *vsync_pinctrl; + struct pinctrl_state *pin_default; + struct workqueue_struct *ois_vsync_wq; + struct work_struct ois_vsync_work; uint8_t ois_fw_flag; uint8_t is_ois_calib; struct cam_ois_opcode opcode; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c index 9c14d87e233d..b0fd63a6dc6f 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -113,6 +113,30 @@ int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl) CAM_DBG(CAM_OIS, "cci-device %d", o_ctrl->cci_num, rc); } + o_ctrl->irq_gpio = of_get_named_gpio(of_node, "interrupt-gpios", 0); + if (o_ctrl->irq_gpio < 0) + { + + CAM_DBG(CAM_OIS, "Looking up %s property failed. rc = %d\n", + "interrupt-gpios", o_ctrl->irq_gpio); + } + else + { + rc = gpio_request(o_ctrl->irq_gpio, "OIS_VSYNC_INTERRUPT"); + if (rc) + { + CAM_DBG(CAM_OIS, "Failed to request gpio %d,rc = %d", + o_ctrl->irq_gpio, rc); + } + rc = gpio_direction_input(o_ctrl->irq_gpio); + if (rc) + { + + CAM_DBG(CAM_OIS, "Unable to set direction for irq gpio [%d]\n", + o_ctrl->irq_gpio); + gpio_free(o_ctrl->irq_gpio); + } + } rc = cam_ois_get_dt_data(o_ctrl); if (rc < 0) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt index 9d37aaa52985..485f06bfdeb9 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_initsetting.h.txt @@ -652,6 +652,14 @@ {.reg_addr = 0x3C0D,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x3C0E,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x3C0F,.reg_data = 0x20,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3041,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x424A,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x424B,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4B48,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4B49,.reg_data = 0x15,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x423D,.reg_data = 0xFF,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x4225,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, +{.reg_addr = 0x3040,.reg_data = 0x01,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E1D,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E25,.reg_data = 0x00,.delay = 0x00,.data_mask = 0x00}, {.reg_addr = 0x6E38,.reg_data = 0x03,.delay = 0x00,.data_mask = 0x00}, -- GitLab From 942ddfc72c0897ed22f968fbcb582b6fa78b4d96 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 15 Nov 2021 14:00:16 +0800 Subject: [PATCH 396/410] [ALM:11087279] [FP4]:ois vsync &&&%%%comment:[FP4]:ois vsync &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 3 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 429 +++++++++++------- .../cam_sensor_module/cam_ois/cam_ois_dev.h | 33 +- .../cam_sensor_module/cam_ois/cam_ois_soc.c | 17 +- 4 files changed, 305 insertions(+), 177 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index f5fc6a84c722..46ba604e959c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -49,6 +49,8 @@ /* factor to conver qtime to boottime */ static int64_t qtime_to_boottime; +uint64_t time_stamp_val_for_cm401 = 0; + static int cam_ife_csid_reset_regs( struct cam_ife_csid_hw *csid_hw, bool reset_hw); @@ -3467,6 +3469,7 @@ static int cam_ife_csid_get_time_stamp( time_stamp->time_stamp_val, CAM_IFE_CSID_QTIMER_MUL_FACTOR, CAM_IFE_CSID_QTIMER_DIV_FACTOR); + time_stamp_val_for_cm401 = time_stamp->time_stamp_val; /* use a universal qtime-2-boottime offset for all cameras * this enables uniform timestamp comparision between cameras diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index b297c27561bc..12a8c20f9649 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -14,22 +14,9 @@ #include #include -struct cam_ois_ctrl_t *o_ctrl_vsync = NULL; -int64_t timestamp_ois; -uint8_t *position_X_Y_timestamps=NULL; -uint8_t data_for_vsync[28] = {0}; - - -typedef struct REGSETTING{ - uint16_t reg ; - uint16_t val ; -}REGSETTING ; - -const REGSETTING ois_fw_control[]= { - {0x9b2c ,0x0001} ,//[0] -}; - +extern uint64_t time_stamp_val_for_cm401; +static struct cam_ois_dev g_cam_ois_dev; static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) @@ -195,42 +182,29 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) return rc; } -ssize_t ois_timestamps_position_show(struct device *dev, struct device_attribute *attr, char *buf){ - - int i = 0, len = 0; - - for( i = 0; i < 28; i++) - len += sprintf(buf + len, "0x%x,", data_for_vsync[i]); - len +=sprintf(buf + len , "\n"); - - return len; - -} - DEVICE_ATTR(ois_gyro_cali_data, 0664, ois_gyro_cali_data_show, ois_gyro_cali_data_store); -DEVICE_ATTR(ois_position_data, 0664, ois_position_data_show, ois_position_data_store); DEVICE_ATTR(ois_status, 0664, ois_status_show, ois_status_store); DEVICE_ATTR(ois_reg, 0664, ois_reg_show, ois_reg_store); DEVICE_ATTR(ois_init_before_sr_test, 0664, ois_init_before_sr_test_show, ois_init_before_sr_test_store); DEVICE_ATTR(ois_gain_set, 0664, ois_gain_set_show, ois_gain_set_store); -DEVICE_ATTR(ois_timestamps_position_data, 0664, ois_timestamps_position_show, NULL); static int cml_vsync_pinctrl_init(struct cam_ois_ctrl_t *o_ctrl) { int retval = 0; + struct cam_ois_dev *pois_dev = o_ctrl->pois_dev; /* Get pinctrl if target uses pinctrl */ - o_ctrl->vsync_pinctrl = devm_pinctrl_get((o_ctrl->pdev->dev.parent)); - if (IS_ERR_OR_NULL(o_ctrl->vsync_pinctrl)) { - retval = PTR_ERR(o_ctrl->vsync_pinctrl); + pois_dev->vsync_pinctrl = devm_pinctrl_get((o_ctrl->pdev->dev.parent)); + if (IS_ERR_OR_NULL(pois_dev->vsync_pinctrl)) { + retval = PTR_ERR(pois_dev->vsync_pinctrl); CAM_ERR(CAM_OIS, "Target does not use pinctrl %d\n", retval); goto err_pinctrl_get; } - - o_ctrl->pin_default = pinctrl_lookup_state(o_ctrl->vsync_pinctrl, "default"); - if (IS_ERR_OR_NULL(o_ctrl->pin_default)) { - retval = PTR_ERR(o_ctrl->pin_default); + + pois_dev->pin_default = pinctrl_lookup_state(pois_dev->vsync_pinctrl, "default"); + if (IS_ERR_OR_NULL(pois_dev->pin_default)) { + retval = PTR_ERR(pois_dev->pin_default); CAM_ERR(CAM_OIS, "Failed to look up default state\n"); goto err_pinctrl_lookup; } @@ -238,115 +212,101 @@ static int cml_vsync_pinctrl_init(struct cam_ois_ctrl_t *o_ctrl) return retval; err_pinctrl_lookup: - devm_pinctrl_put(o_ctrl->vsync_pinctrl); + devm_pinctrl_put(pois_dev->vsync_pinctrl); err_pinctrl_get: - o_ctrl->vsync_pinctrl = NULL; + pois_dev->vsync_pinctrl = NULL; return retval; } irqreturn_t interrupt_ois_vsync_irq(int irq, void *dev) { - timestamp_ois = ktime_get_real_ns(); - queue_work(o_ctrl_vsync->ois_vsync_wq, &o_ctrl_vsync->ois_vsync_work); + struct cam_ois_dev *pois_dev = (struct cam_ois_dev *)dev; + + if (pois_dev->dev_state == CAM_OIS_DEV_START) + { + mutex_lock(&pois_dev->dev_mutex); + pois_dev->need_read = 1; + mutex_unlock(&pois_dev->dev_mutex); + wake_up_interruptible(&pois_dev->queue); + } return IRQ_HANDLED; } -static void ois_vsync_function(struct work_struct *work) +enum SETTING_INDEX { + SETTING_ADDR, + SETTING_DATA, + SETTING_DELAY, + SETTING_MASK, +}; + +static struct cam_sensor_i2c_reg_array ois_data_reader_setting[] = +{ + {0x9DFC, 0x0A04, 1, 0}, + {0x9B2C, 0X0001, 1, 0}, + {0x9B2A, 0X0001, 1, 0}, + {0x9DFE, 0X0001, 1, 0}, +}; +static int32_t cam_ois_reg_setting_init(struct cam_ois_ctrl_t *o_ctrl) +{ + int32_t rc = 0, i = 0, item_num = 0; + struct cam_sensor_i2c_reg_array *p_reg_array = NULL; + struct cam_ois_dev *pois_dev = o_ctrl->pois_dev; + pois_dev->reg_page_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * + (sizeof(ois_data_reader_setting) / + sizeof(ois_data_reader_setting[0]))) >> PAGE_SHIFT; + pois_dev->reg_setting_page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)), + pois_dev->reg_page_size, 0, GFP_KERNEL); + if (!pois_dev->reg_setting_page) { + rc = -ENOMEM; + } + + p_reg_array = (struct cam_sensor_i2c_reg_array *) (page_address(pois_dev->reg_setting_page)); + item_num = sizeof(ois_data_reader_setting) / sizeof(ois_data_reader_setting[0]); + + for (i = 0; i < item_num; i++) { + p_reg_array[i].reg_addr = ois_data_reader_setting[i].reg_addr; + p_reg_array[i].reg_data = ois_data_reader_setting[i].reg_data; + p_reg_array[i].delay = ois_data_reader_setting[i].delay; + p_reg_array[i].data_mask = ois_data_reader_setting[i].data_mask; + } + pois_dev->i2c_reg_setting.reg_setting = p_reg_array; + pois_dev->i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + pois_dev->i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + pois_dev->i2c_reg_setting.size = item_num; + pois_dev->i2c_reg_setting.delay = 0; + + return rc; +} + +static void cam_ois_reg_setting_uninit(struct cam_ois_ctrl_t *o_ctrl) { - uint16_t total_bytes = 0; - int32_t rc = 0; - struct cam_sensor_i2c_reg_setting i2c_reg_setting; - struct page *page = NULL; - uint32_t fw_size; - uint32_t cmd_data=0; - - if (!o_ctrl_vsync) { - CAM_ERR(CAM_OIS, "Invalid Args"); - return; - } - total_bytes = sizeof(ois_fw_control[0]); - - i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; - i2c_reg_setting.size = total_bytes; - i2c_reg_setting.delay = 0; - - fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes) >> PAGE_SHIFT; - page = cma_alloc(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)),fw_size, 0, GFP_KERNEL); - if (!page) { - CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); - return; - } - i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (page_address(page)); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFC; - i2c_reg_setting.reg_setting[0].reg_data = 0x0A04; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9DFC -> 0x0A04"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2C; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9B2C -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9B2A; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9B2A -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - - rc = camera_io_dev_read(&(o_ctrl_vsync->io_master_info),0x9B28,&cmd_data,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); - CAM_ERR(CAM_OIS, "read 0x9B28 -> 0x%x",cmd_data); - - i2c_reg_setting.reg_setting[0].reg_addr = 0x9DFE; - i2c_reg_setting.reg_setting[0].reg_data = 0X0001; - i2c_reg_setting.reg_setting[0].delay = 1; - i2c_reg_setting.reg_setting[0].data_mask = 0; - CAM_ERR(CAM_OIS, "write 0x9DFE -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl_vsync->io_master_info), &i2c_reg_setting); - mdelay(1); - - rc = camera_io_dev_read_seq(&(o_ctrl_vsync->io_master_info),0x9DAC,position_X_Y_timestamps,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); - - data_for_vsync[0] = position_X_Y_timestamps[6]; - data_for_vsync[1] = position_X_Y_timestamps[7];//6X - data_for_vsync[2] = position_X_Y_timestamps[8]; - data_for_vsync[3] = position_X_Y_timestamps[9];//6Y - data_for_vsync[4] = position_X_Y_timestamps[22]; - data_for_vsync[5] = position_X_Y_timestamps[23];//7X - data_for_vsync[6] = position_X_Y_timestamps[24]; - data_for_vsync[7] = position_X_Y_timestamps[25];//7Y - data_for_vsync[8] = position_X_Y_timestamps[38]; - data_for_vsync[9] = position_X_Y_timestamps[39];//8X - data_for_vsync[10] = position_X_Y_timestamps[40]; - data_for_vsync[11] = position_X_Y_timestamps[41];//8Y - data_for_vsync[12] = position_X_Y_timestamps[54]; - data_for_vsync[13] = position_X_Y_timestamps[55];//9X - data_for_vsync[14] = position_X_Y_timestamps[56]; - data_for_vsync[15] = position_X_Y_timestamps[57];//9Y - data_for_vsync[16] = position_X_Y_timestamps[70]; - data_for_vsync[17] = position_X_Y_timestamps[71];//10X - data_for_vsync[18] = position_X_Y_timestamps[72]; - data_for_vsync[19] = position_X_Y_timestamps[73];//10Y - - data_for_vsync[20] = (uint8_t)(timestamp_ois&0x00000000000000FF); - data_for_vsync[21] = (uint8_t)((timestamp_ois&0x000000000000FF00)>>8); - data_for_vsync[22] = (uint8_t)((timestamp_ois&0x0000000000FF0000)>>16); - data_for_vsync[23] = (uint8_t)((timestamp_ois&0x00000000FF000000)>>24); - data_for_vsync[24] = (uint8_t)((timestamp_ois&0x000000FF00000000)>>32); - data_for_vsync[25] = (uint8_t)((timestamp_ois&0x0000FF0000000000)>>40); - data_for_vsync[26] = (uint8_t)((timestamp_ois&0x00FF000000000000)>>48); - data_for_vsync[27] = (uint8_t)((timestamp_ois&0xFF00000000000000)>>56); - - cma_release(dev_get_cma_area((o_ctrl_vsync->soc_info.dev)), page, fw_size); - page = NULL; + struct cam_ois_dev *pois_dev = o_ctrl->pois_dev; + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), + pois_dev->reg_setting_page, + pois_dev->reg_page_size); + pois_dev->reg_setting_page = NULL; + pois_dev->reg_page_size = 0; +} + +static int32_t load_ois_data(struct cam_ois_dev *pois_dev) +{ + int32_t rc = 0; + struct cam_ois_ctrl_t *o_ctrl = pois_dev->o_ctrl; + struct timespec64 ts; + if (!pois_dev || !o_ctrl) { + CAM_ERR(CAM_OIS, "read failed: pois_dev: %p o_ctrl:%p", pois_dev, o_ctrl); + return -EINVAL; + } + mutex_lock(&(o_ctrl->ois_mutex)); + camera_io_dev_write_continuous(&o_ctrl->io_master_info, &pois_dev->i2c_reg_setting, 0); + mdelay(1); /* for safe read data */ + get_monotonic_boottime64(&ts); + pois_dev->load_ois_timestamp = time_stamp_val_for_cm401; + camera_io_dev_read_seq(&(o_ctrl->io_master_info),0x9DAC, pois_dev->reg_data_buffer,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); + mutex_unlock(&(o_ctrl->ois_mutex)); + return rc; } static int cam_ois_i2c_driver_probe(struct i2c_client *client, @@ -454,6 +414,7 @@ static int32_t cam_ois_platform_driver_probe( int32_t rc = 0; struct cam_ois_ctrl_t *o_ctrl = NULL; struct cam_ois_soc_private *soc_private = NULL; + struct cam_ois_dev *pois_dev = NULL; o_ctrl = kzalloc(sizeof(struct cam_ois_ctrl_t), GFP_KERNEL); if (!o_ctrl) @@ -461,6 +422,9 @@ static int32_t cam_ois_platform_driver_probe( o_ctrl->soc_info.pdev = pdev; o_ctrl->pdev = pdev; + o_ctrl->pois_dev = &g_cam_ois_dev; + pois_dev = o_ctrl->pois_dev; + pois_dev->o_ctrl = o_ctrl; o_ctrl->soc_info.dev = &pdev->dev; o_ctrl->soc_info.dev_name = pdev->name; @@ -478,6 +442,12 @@ static int32_t cam_ois_platform_driver_probe( rc = -ENOMEM; goto free_cci_client; } + + /*init ois data reader configuration*/ + rc = cam_ois_reg_setting_init(o_ctrl); + if (rc) { + goto free_soc; + } o_ctrl->soc_info.soc_private = soc_private; soc_private->power_info.dev = &pdev->dev; @@ -488,42 +458,34 @@ static int32_t cam_ois_platform_driver_probe( rc = cam_ois_driver_soc_init(o_ctrl); if (rc) { CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc); - goto free_soc; + goto free_reg_array; } - + rc = cml_vsync_pinctrl_init(o_ctrl); - if (!rc && o_ctrl->vsync_pinctrl) { + if (!rc && pois_dev->vsync_pinctrl) { rc = pinctrl_select_state( - o_ctrl->vsync_pinctrl, - o_ctrl->pin_default); + pois_dev->vsync_pinctrl, + pois_dev->pin_default); if (rc < 0) { CAM_ERR(CAM_OIS, "Can't select pinctrl state\n"); } } - o_ctrl->ois_vsync_wq= create_singlethread_workqueue("ois_vsync_wq"); - INIT_WORK(&o_ctrl->ois_vsync_work, ois_vsync_function); - queue_work(o_ctrl->ois_vsync_wq, &o_ctrl->ois_vsync_work); - - rc = request_irq(gpio_to_irq(o_ctrl->irq_gpio), interrupt_ois_vsync_irq, IRQ_TYPE_EDGE_RISING , "ois_vsync_work", &o_ctrl->soc_info.dev); + rc = request_irq(gpio_to_irq(pois_dev->irq_gpio), interrupt_ois_vsync_irq, IRQ_TYPE_EDGE_RISING , "ois_vsync_intf", pois_dev); if(rc < 0) { - CAM_ERR(CAM_OIS, "request_irq failed\n"); goto exit_free_gpio; } - enable_irq_wake(gpio_to_irq(o_ctrl->irq_gpio)); + enable_irq_wake(gpio_to_irq(pois_dev->irq_gpio)); - rc = cam_ois_init_subdev_param(o_ctrl); if (rc) - goto free_soc; + goto free_reg_array; - if ((device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data)) || - (device_create_file(&pdev->dev, &dev_attr_ois_position_data)) || + if ((device_create_file(&pdev->dev, &dev_attr_ois_gyro_cali_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_status)) || (device_create_file(&pdev->dev, &dev_attr_ois_reg)) || - (device_create_file(&pdev->dev, &dev_attr_ois_timestamps_position_data)) || (device_create_file(&pdev->dev, &dev_attr_ois_gain_set)) || (device_create_file(&pdev->dev, &dev_attr_ois_init_before_sr_test))) { @@ -540,24 +502,21 @@ static int32_t cam_ois_platform_driver_probe( platform_set_drvdata(pdev, o_ctrl); o_ctrl->cam_ois_state = CAM_OIS_INIT; o_ctrl->open_cnt = 0; - - o_ctrl_vsync = o_ctrl; - position_X_Y_timestamps = (uint8_t *) - vzalloc(80 * sizeof(uint8_t)); - timestamp_ois = 0; - return rc; - + exit_free_gpio: - gpio_free(o_ctrl->irq_gpio); + gpio_free(pois_dev->irq_gpio); unreg_subdev: cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); free_soc: kfree(soc_private); +free_reg_array: + cam_ois_reg_setting_uninit(o_ctrl); free_cci_client: kfree(o_ctrl->io_master_info.cci_client); free_o_ctrl: kfree(o_ctrl); + pois_dev->o_ctrl = NULL; return rc; } @@ -577,25 +536,26 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_ois_gyro_cali_data); device_remove_file(&pdev->dev, &dev_attr_ois_status); - device_remove_file(&pdev->dev, &dev_attr_ois_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_reg); - device_remove_file(&pdev->dev, &dev_attr_ois_timestamps_position_data); device_remove_file(&pdev->dev, &dev_attr_ois_gain_set); device_remove_file(&pdev->dev, &dev_attr_ois_init_before_sr_test); CAM_ERR(CAM_OIS, " device_remove_file node"); - + + cam_ois_reg_setting_uninit(o_ctrl); + CAM_INFO(CAM_OIS, "platform driver remove invoked"); soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + o_ctrl->pois_dev->o_ctrl = NULL; + o_ctrl->pois_dev = NULL; mutex_lock(&(o_ctrl->ois_mutex)); cam_ois_shutdown(o_ctrl); mutex_unlock(&(o_ctrl->ois_mutex)); cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); - soc_private = - (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + soc_private =(struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; power_info = &soc_private->power_info; kfree(o_ctrl->soc_info.soc_private); @@ -634,16 +594,120 @@ static struct i2c_driver cam_ois_i2c_driver = { .probe = cam_ois_i2c_driver_probe, .remove = cam_ois_i2c_driver_remove, .driver = { - .name = "msm_ois", + .name = "msm_ois", }, }; static struct cam_ois_registered_driver_t registered_driver = { 0, 0}; +static int c_ois_open(struct inode *inode,struct file *filp) +{ + struct cam_ois_dev *pois_dev = &g_cam_ois_dev; + mutex_lock(&pois_dev->dev_mutex); + filp->private_data = (void *)pois_dev; + if (CAM_OIS_DEV_UNINIT != g_cam_ois_dev.dev_state) + g_cam_ois_dev.dev_state = CAM_OIS_DEV_START; + mutex_unlock(&pois_dev->dev_mutex); + return 0; +} + +static int c_ois_release(struct inode *inode,struct file *filp) +{ + struct cam_ois_dev *pois_dev = (struct cam_ois_dev *)filp->private_data; + mutex_lock(&pois_dev->dev_mutex); + if (CAM_OIS_DEV_UNINIT != g_cam_ois_dev.dev_state) + g_cam_ois_dev.dev_state = CAM_OIS_DEV_STOP; + filp->private_data = NULL; + mutex_unlock(&pois_dev->dev_mutex); + return 0; +} + +static int regDataOffset[] = +{ + 6, 22, 38, 54, 70, +}; +static ssize_t c_ois_read(struct file *filp,char *buf,size_t len,loff_t *off) +{ + struct cam_ois_dev *pois_dev = (struct cam_ois_dev *)filp->private_data; + int rc = 0, i = 0, data_num = 0; + if (!pois_dev || len < 28) { + return -EINVAL; + } + if (wait_event_interruptible(pois_dev->queue, pois_dev->need_read != 0)) + return -ERESTARTSYS; + mutex_lock(&pois_dev->dev_mutex); + + rc = load_ois_data(pois_dev); + if (rc) { + goto error_handle; + } + /*OIS data protocol: + * |1-byte| 8-byte | N-byte | + * | N |timestamp| x,y data | + * */ + data_num = 5; //we just read 5-data now + if (copy_to_user(&buf[0], (void *)&data_num, 1)) + { + rc = -EFAULT; + goto error_handle; + } + rc += 1; + + if (copy_to_user(&buf[rc], &pois_dev->load_ois_timestamp, sizeof(uint64_t))) { + rc = -EFAULT; + goto error_handle; + } + rc += sizeof(uint64_t); + + for (i = 0; i < data_num; i++) + { + if (copy_to_user(&buf[rc], (void *)(&pois_dev->reg_data_buffer[regDataOffset[i]]), sizeof(uint32_t))) { + rc = -EFAULT; + goto error_handle; + } + rc += sizeof(uint32_t); + } + +error_handle: + pois_dev->need_read = 0; + mutex_unlock(&pois_dev->dev_mutex); + return rc; +} + +static ssize_t c_ois_write(struct file *filp,const char *buf,size_t len,loff_t *off) +{ + return 0; +} + +static __poll_t c_ois_poll(struct file *filp, poll_table *wait) +{ + struct cam_ois_dev *pois_dev = (struct cam_ois_dev *)filp->private_data; + __poll_t mask = 0; + + poll_wait(filp, &pois_dev->queue, wait); + mutex_lock(&pois_dev->dev_mutex); + if (pois_dev->need_read) { + mask |= EPOLLIN; + } + mutex_unlock(&pois_dev->dev_mutex); + + return mask; +} +static const struct file_operations cois_fops = +{ + .read = c_ois_read, + .write = c_ois_write, + .open = c_ois_open, + .release = c_ois_release, + .poll = c_ois_poll, +}; + static int __init cam_ois_driver_init(void) { int rc = 0; + dev_t ois_dev = 0; + memset(&g_cam_ois_dev, 0, sizeof(g_cam_ois_dev)); rc = platform_driver_register(&cam_ois_platform_driver); if (rc) { @@ -661,11 +725,48 @@ static int __init cam_ois_driver_init(void) } registered_driver.i2c_driver = 1; + + ois_dev = MKDEV(g_cam_ois_dev.ois_major, 0); +#define OISDEV_NAME "OISCDEV" + if (g_cam_ois_dev.ois_major) { + rc = register_chrdev_region(ois_dev, 1, OISDEV_NAME); + } else { + rc = alloc_chrdev_region(&ois_dev, 0, 1, OISDEV_NAME); + g_cam_ois_dev.ois_major = MAJOR(ois_dev); + } + + if (rc < 0) { + return rc; + } + + cdev_init(&g_cam_ois_dev.devm, &cois_fops); + g_cam_ois_dev.devm.owner = THIS_MODULE; + rc = cdev_add(&g_cam_ois_dev.devm, ois_dev, 1); + if (rc) { + CAM_ERR(CAM_OIS, "Error %d adding cm4_ois0 device", rc); + } else { + g_cam_ois_dev.ois_class = class_create(THIS_MODULE, "cm4_ois0"); + device_create(g_cam_ois_dev.ois_class, NULL, ois_dev, NULL, "cm4_ois0"); + } + + mutex_init(&(g_cam_ois_dev.dev_mutex)); + init_waitqueue_head(&g_cam_ois_dev.queue); + g_cam_ois_dev.reg_data_buffer = (uint8_t *)vzalloc(80 * sizeof(uint8_t)); + g_cam_ois_dev.dev_state = CAM_OIS_DEV_INIT; return rc; } static void __exit cam_ois_driver_exit(void) { + if (g_cam_ois_dev.reg_data_buffer) + { + vfree(g_cam_ois_dev.reg_data_buffer); + g_cam_ois_dev.reg_data_buffer = NULL; + } + device_destroy(g_cam_ois_dev.ois_class, MKDEV(g_cam_ois_dev.ois_major, 0)); + class_destroy(g_cam_ois_dev.ois_class); + cdev_del(&g_cam_ois_dev.devm); + unregister_chrdev_region(MKDEV(g_cam_ois_dev.ois_major, 0), 1); if (registered_driver.platform_driver) platform_driver_unregister(&cam_ois_platform_driver); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index a5be088ec2ea..bd56d57e0907 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -32,6 +32,33 @@ enum cam_ois_state { CAM_OIS_START, }; +enum cam_ois_dev_state { + CAM_OIS_DEV_UNINIT, + CAM_OIS_DEV_INIT, + CAM_OIS_DEV_START, + CAM_OIS_DEV_STOP, +}; + +struct cam_ois_dev +{ + struct cdev devm; + struct class *ois_class; + struct cam_ois_ctrl_t *o_ctrl; + struct pinctrl *vsync_pinctrl; + struct pinctrl_state *pin_default; + uint64_t load_ois_timestamp; + int irq_gpio; + int ois_major; + int dev_state; + int need_read; + int reg_page_size; + struct page *reg_setting_page; + uint8_t *reg_data_buffer; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct mutex dev_mutex; + wait_queue_head_t queue; +}; + /** * struct cam_ois_registered_driver_t - registered driver info * @platform_driver : flag indicates if platform driver is registered @@ -106,6 +133,7 @@ struct cam_ois_intf_params { struct cam_ois_ctrl_t { char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; struct platform_device *pdev; + struct cam_ois_dev *pois_dev; struct mutex ois_mutex; struct cam_hw_soc_info soc_info; struct camera_io_master io_master_info; @@ -119,11 +147,6 @@ struct cam_ois_ctrl_t { enum msm_camera_device_type_t ois_device_type; enum cam_ois_state cam_ois_state; char ois_name[32]; - int irq_gpio; - struct pinctrl *vsync_pinctrl; - struct pinctrl_state *pin_default; - struct workqueue_struct *ois_vsync_wq; - struct work_struct ois_vsync_work; uint8_t ois_fw_flag; uint8_t is_ois_calib; struct cam_ois_opcode opcode; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c index b0fd63a6dc6f..c8794781adb4 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -83,6 +83,7 @@ int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl) struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info; struct device_node *of_node = NULL; struct device_node *of_parent = NULL; + struct cam_ois_dev *pois_dev = o_ctrl->pois_dev; if (!soc_info->dev) { CAM_ERR(CAM_OIS, "soc_info is not initialized"); @@ -113,28 +114,28 @@ int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl) CAM_DBG(CAM_OIS, "cci-device %d", o_ctrl->cci_num, rc); } - o_ctrl->irq_gpio = of_get_named_gpio(of_node, "interrupt-gpios", 0); - if (o_ctrl->irq_gpio < 0) + pois_dev->irq_gpio = of_get_named_gpio(of_node, "interrupt-gpios", 0); + if (pois_dev->irq_gpio < 0) { CAM_DBG(CAM_OIS, "Looking up %s property failed. rc = %d\n", - "interrupt-gpios", o_ctrl->irq_gpio); + "interrupt-gpios", pois_dev->irq_gpio); } else { - rc = gpio_request(o_ctrl->irq_gpio, "OIS_VSYNC_INTERRUPT"); + rc = gpio_request(pois_dev->irq_gpio, "OIS_VSYNC_INTERRUPT"); if (rc) { CAM_DBG(CAM_OIS, "Failed to request gpio %d,rc = %d", - o_ctrl->irq_gpio, rc); + pois_dev->irq_gpio, rc); } - rc = gpio_direction_input(o_ctrl->irq_gpio); + rc = gpio_direction_input(pois_dev->irq_gpio); if (rc) { CAM_DBG(CAM_OIS, "Unable to set direction for irq gpio [%d]\n", - o_ctrl->irq_gpio); - gpio_free(o_ctrl->irq_gpio); + pois_dev->irq_gpio); + gpio_free(pois_dev->irq_gpio); } } -- GitLab From 822ccdefbd5d027f3ea8a10e42a4a69f515006e3 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Sun, 21 Nov 2021 18:14:05 +0800 Subject: [PATCH 397/410] [ALM:11087279] [FP4]:ois vsync &&&%%%comment:[FP4]:fix interrupt into sleep error &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- drivers/cam_sensor_module/cam_ois/cam_ois_dev.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 12a8c20f9649..2d28fe1b26fe 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -224,9 +224,7 @@ irqreturn_t interrupt_ois_vsync_irq(int irq, void *dev) if (pois_dev->dev_state == CAM_OIS_DEV_START) { - mutex_lock(&pois_dev->dev_mutex); pois_dev->need_read = 1; - mutex_unlock(&pois_dev->dev_mutex); wake_up_interruptible(&pois_dev->queue); } @@ -636,7 +634,7 @@ static ssize_t c_ois_read(struct file *filp,char *buf,size_t len,loff_t *off) } if (wait_event_interruptible(pois_dev->queue, pois_dev->need_read != 0)) return -ERESTARTSYS; - mutex_lock(&pois_dev->dev_mutex); + pois_dev->need_read = 0; rc = load_ois_data(pois_dev); if (rc) { @@ -670,8 +668,6 @@ static ssize_t c_ois_read(struct file *filp,char *buf,size_t len,loff_t *off) } error_handle: - pois_dev->need_read = 0; - mutex_unlock(&pois_dev->dev_mutex); return rc; } @@ -686,11 +682,9 @@ static __poll_t c_ois_poll(struct file *filp, poll_table *wait) __poll_t mask = 0; poll_wait(filp, &pois_dev->queue, wait); - mutex_lock(&pois_dev->dev_mutex); if (pois_dev->need_read) { mask |= EPOLLIN; } - mutex_unlock(&pois_dev->dev_mutex); return mask; } -- GitLab From edbd3ac69687cd179370a741dcff11e47ad6d471 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Tue, 23 Nov 2021 11:14:36 +0800 Subject: [PATCH 398/410] [ALM:11087279] [FP4]:ois vsync &&&%%%comment:[FP4]:read all ois position data from buffer &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_dev.c | 32 ++++++++++++++----- .../cam_sensor_module/cam_ois/cam_ois_dev.h | 1 + 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 2d28fe1b26fe..b78909cf6f5d 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -241,10 +241,21 @@ enum SETTING_INDEX { static struct cam_sensor_i2c_reg_array ois_data_reader_setting[] = { {0x9DFC, 0x0A04, 1, 0}, - {0x9B2C, 0X0001, 1, 0}, - {0x9B2A, 0X0001, 1, 0}, - {0x9DFE, 0X0001, 1, 0}, + {0x9B2C, 0x0001, 1, 0}, + {0x9B2A, 0x0001, 1, 0}, + {0x9DFE, 0x0001, 1, 0}, }; + +static int regDataOffset[] = +{ + 86, 102, 118, 134, 150, 6, 22, 38, 54, 70 +}; + +static struct cam_sensor_i2c_reg_array ois_data_reader_setting_for_buffer0[] = +{ + {0x9DFE, 0x0000, 1, 0}, +}; + static int32_t cam_ois_reg_setting_init(struct cam_ois_ctrl_t *o_ctrl) { int32_t rc = 0, i = 0, item_num = 0; @@ -274,6 +285,12 @@ static int32_t cam_ois_reg_setting_init(struct cam_ois_ctrl_t *o_ctrl) pois_dev->i2c_reg_setting.size = item_num; pois_dev->i2c_reg_setting.delay = 0; + pois_dev->i2c_reg_setting_for_buffer0.reg_setting = ois_data_reader_setting_for_buffer0; + pois_dev->i2c_reg_setting_for_buffer0.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + pois_dev->i2c_reg_setting_for_buffer0.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + pois_dev->i2c_reg_setting_for_buffer0.size = 1; + pois_dev->i2c_reg_setting_for_buffer0.delay = 0; + return rc; } @@ -303,6 +320,9 @@ static int32_t load_ois_data(struct cam_ois_dev *pois_dev) get_monotonic_boottime64(&ts); pois_dev->load_ois_timestamp = time_stamp_val_for_cm401; camera_io_dev_read_seq(&(o_ctrl->io_master_info),0x9DAC, pois_dev->reg_data_buffer,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); + camera_io_dev_write(&o_ctrl->io_master_info,&pois_dev->i2c_reg_setting_for_buffer0); + mdelay(1); /* for safe read data */ + camera_io_dev_read_seq(&(o_ctrl->io_master_info),0x9DAC, &pois_dev->reg_data_buffer[80],CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); mutex_unlock(&(o_ctrl->ois_mutex)); return rc; } @@ -621,10 +641,6 @@ static int c_ois_release(struct inode *inode,struct file *filp) return 0; } -static int regDataOffset[] = -{ - 6, 22, 38, 54, 70, -}; static ssize_t c_ois_read(struct file *filp,char *buf,size_t len,loff_t *off) { struct cam_ois_dev *pois_dev = (struct cam_ois_dev *)filp->private_data; @@ -644,7 +660,7 @@ static ssize_t c_ois_read(struct file *filp,char *buf,size_t len,loff_t *off) * |1-byte| 8-byte | N-byte | * | N |timestamp| x,y data | * */ - data_num = 5; //we just read 5-data now + data_num = 10; //we just read 5-data now if (copy_to_user(&buf[0], (void *)&data_num, 1)) { rc = -EFAULT; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index bd56d57e0907..26cc334eb90d 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -55,6 +55,7 @@ struct cam_ois_dev struct page *reg_setting_page; uint8_t *reg_data_buffer; struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct cam_sensor_i2c_reg_setting i2c_reg_setting_for_buffer0; struct mutex dev_mutex; wait_queue_head_t queue; }; -- GitLab From 66d0e7ca62f96505eded73a4059a1697b0990695 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Thu, 25 Nov 2021 20:01:48 +0800 Subject: [PATCH 399/410] [ALM:11087279] [FP4]:ois vsync &&&%%%comment:[FP4]:reverse byte &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- .../cam_sensor_module/cam_ois/cam_ois_dev.c | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index b78909cf6f5d..f5eee740698a 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -304,6 +304,26 @@ static void cam_ois_reg_setting_uninit(struct cam_ois_ctrl_t *o_ctrl) pois_dev->reg_page_size = 0; } +static int32_t reverse_byte(struct cam_ois_dev *pois_dev) +{ + int32_t rc = 0,i=0; + struct cam_ois_ctrl_t *o_ctrl = pois_dev->o_ctrl; + uint8_t tmp_data=0; + + if (!pois_dev || !o_ctrl) { + CAM_ERR(CAM_OIS, "read failed: pois_dev: %p o_ctrl:%p", pois_dev, o_ctrl); + return -EINVAL; + } + + for (i = 0;i<160;i+=2) + { + tmp_data = pois_dev->reg_data_buffer[i]; + pois_dev->reg_data_buffer[i] = pois_dev->reg_data_buffer[i+1]; + pois_dev->reg_data_buffer[i+1] = tmp_data; + } + return rc; +} + static int32_t load_ois_data(struct cam_ois_dev *pois_dev) { int32_t rc = 0; @@ -323,6 +343,7 @@ static int32_t load_ois_data(struct cam_ois_dev *pois_dev) camera_io_dev_write(&o_ctrl->io_master_info,&pois_dev->i2c_reg_setting_for_buffer0); mdelay(1); /* for safe read data */ camera_io_dev_read_seq(&(o_ctrl->io_master_info),0x9DAC, &pois_dev->reg_data_buffer[80],CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); + reverse_byte(pois_dev); mutex_unlock(&(o_ctrl->ois_mutex)); return rc; } @@ -761,7 +782,7 @@ static int __init cam_ois_driver_init(void) mutex_init(&(g_cam_ois_dev.dev_mutex)); init_waitqueue_head(&g_cam_ois_dev.queue); - g_cam_ois_dev.reg_data_buffer = (uint8_t *)vzalloc(80 * sizeof(uint8_t)); + g_cam_ois_dev.reg_data_buffer = (uint8_t *)vzalloc(160 * sizeof(uint8_t)); g_cam_ois_dev.dev_state = CAM_OIS_DEV_INIT; return rc; } -- GitLab From 7b845dc9edbfd4f1707763757f0827afeb3e0cfc Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Wed, 5 Jan 2022 13:48:51 +0800 Subject: [PATCH 400/410] [ALM:11087279] [FP4]:read ois data &&&%%%comment:[FP4]:buffer0 -> buffer1 &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- drivers/cam_sensor_module/cam_ois/cam_ois_dev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index f5eee740698a..e379cd8a5da7 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -243,17 +243,17 @@ static struct cam_sensor_i2c_reg_array ois_data_reader_setting[] = {0x9DFC, 0x0A04, 1, 0}, {0x9B2C, 0x0001, 1, 0}, {0x9B2A, 0x0001, 1, 0}, - {0x9DFE, 0x0001, 1, 0}, + {0x9DFE, 0x0000, 1, 0}, }; static int regDataOffset[] = { - 86, 102, 118, 134, 150, 6, 22, 38, 54, 70 + 6, 22, 38, 54, 70, 86, 102, 118, 134, 150 }; -static struct cam_sensor_i2c_reg_array ois_data_reader_setting_for_buffer0[] = +static struct cam_sensor_i2c_reg_array ois_data_reader_setting_for_buffer1[] = { - {0x9DFE, 0x0000, 1, 0}, + {0x9DFE, 0x0001, 1, 0}, }; static int32_t cam_ois_reg_setting_init(struct cam_ois_ctrl_t *o_ctrl) @@ -285,7 +285,7 @@ static int32_t cam_ois_reg_setting_init(struct cam_ois_ctrl_t *o_ctrl) pois_dev->i2c_reg_setting.size = item_num; pois_dev->i2c_reg_setting.delay = 0; - pois_dev->i2c_reg_setting_for_buffer0.reg_setting = ois_data_reader_setting_for_buffer0; + pois_dev->i2c_reg_setting_for_buffer0.reg_setting = ois_data_reader_setting_for_buffer1; pois_dev->i2c_reg_setting_for_buffer0.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; pois_dev->i2c_reg_setting_for_buffer0.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; pois_dev->i2c_reg_setting_for_buffer0.size = 1; -- GitLab From 3449bec1a6b07600dbcb8c14f6ebad6cedd1dcd2 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Mon, 21 Feb 2022 15:34:19 +0800 Subject: [PATCH 401/410] [ALM:11087279] [FP4]:ois data -> 0 &&&%%%comment:[FP4]:ois data[3/4]=0 &&&%%%bug number:10872982 &&&%%%jira id:FP4-1868 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:chi-cdk &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA --- drivers/cam_sensor_module/cam_ois/cam_ois_dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index e379cd8a5da7..0ac1c78b69a9 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -673,6 +673,7 @@ static ssize_t c_ois_read(struct file *filp,char *buf,size_t len,loff_t *off) return -ERESTARTSYS; pois_dev->need_read = 0; + mdelay(1); rc = load_ois_data(pois_dev); if (rc) { goto error_handle; -- GitLab From 3291e7a6ee918ebdca6184631deda4eecd9d0db4 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Thu, 10 Mar 2022 10:23:44 +0800 Subject: [PATCH 402/410] [FP4]:[Monkey][Crash]com.fp.camera:android.os.ServiceSpecificException: supportsCameraApi:2367: Unknown camera ID 3 &&&%%%comment:[FP4]:NA &&&%%%bug number:NA &&&%%%jira id:FP4-3455 &&&%%%product name:sm7225_r_fp4 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:camera-kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:waiting for test &&&%%%VAL Can Test:NA --- drivers/cam_sync/cam_sync_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cam_sync/cam_sync_private.h b/drivers/cam_sync/cam_sync_private.h index a8612fdcd7c5..347f866e7cc8 100644 --- a/drivers/cam_sync/cam_sync_private.h +++ b/drivers/cam_sync/cam_sync_private.h @@ -25,7 +25,7 @@ #define CAM_SYNC_OBJ_NAME_LEN 64 #define CAM_SYNC_MAX_OBJS 1024 -#define CAM_SYNC_MAX_V4L2_EVENTS 100 +#define CAM_SYNC_MAX_V4L2_EVENTS 255 #define CAM_SYNC_DEBUG_FILENAME "cam_debug" #define CAM_SYNC_DEBUG_BASEDIR "cam" #define CAM_SYNC_DEBUG_BUF_SIZE 32 -- GitLab From ec337e29705cd67342f7b20923537da95d31f655 Mon Sep 17 00:00:00 2001 From: "yan.han" Date: Sat, 25 Jun 2022 22:29:28 +0800 Subject: [PATCH 403/410] [FP4-3781]: Fix BUS err for HFR &&&%%%comment:[FP4]:ix BUS err for HFR &&&%%%bug number:FP4-3781 &&&%%%product name:sm7225_s_fp4_target_dev &&&%%%jira id:FP4-3781 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:ok in native &&&%%%VAL Can Test:NA Change-Id: I4de1f1c6c5e72fbc97fbb70db7270561a7deaf0e --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index f395d1f1180d..922aff899f03 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1325,6 +1325,9 @@ static int cam_vfe_bus_start_wm( * i.e enable wm only if io buffers are allocated */ + /* Enable WM for BUS err */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + rsrc_data->hw_regs->cfg); + CAM_DBG(CAM_ISP, "WM res %d width = %d, height = %d", rsrc_data->index, rsrc_data->width, rsrc_data->height); CAM_DBG(CAM_ISP, "WM res %d pk_fmt = %d", rsrc_data->index, -- GitLab From 2d006e566128869ec368f84f689954efd438f2fc Mon Sep 17 00:00:00 2001 From: Rajesh Bharathwaj Date: Tue, 26 Jul 2022 16:47:02 -0700 Subject: [PATCH 404/410] msm: camera: reqmgr: Increase V4L2 Queue depth Increasing V4L2 Queue depth from 30 to 100 to avoid frame drops in XR Usecases. Change-Id: I82d2238af52c638c02dc0e4379cfb276915f8c53 CRs-Fixed: 3245359 Signed-off-by: Rajesh Bharathwaj --- drivers/cam_req_mgr/cam_req_mgr_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index c783aa0fc519..f3b3b19a8c4c 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -27,7 +28,7 @@ #include "cam_debug_util.h" #include "cam_common_util.h" -#define CAM_REQ_MGR_EVENT_MAX 30 +#define CAM_REQ_MGR_EVENT_MAX 100 static struct cam_req_mgr_device g_dev; struct kmem_cache *g_cam_req_mgr_timer_cachep; -- GitLab From bb262c551642e4c533f71c098d9af0973e3a40a4 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Mon, 13 Jun 2022 14:04:58 +0530 Subject: [PATCH 405/410] Revert "msm: camera: isp: Dont enable Wm configurations during HW start" This reverts commit c3547a2716052cc8564d3747b853bbeb7f9afc40. This change is reverted as it results in bus error during EPCR disabled case in some targets. The actual fix for the pagefault is merged through commit '74b976742099 ("msm: camera: isp: Change logic of acquiring dual composite group")'. CRs-Fixed: 3170082 Change-Id: I3a3bb053a3d22dac5e13b83181a5e5c8e9922c80 Signed-off-by: Nirmal Abraham --- .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index be06a36262d5..87822eb459b8 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1323,9 +1323,10 @@ static int cam_vfe_bus_start_wm( return -EINVAL; } } - /* enabling Wm configuratons are taken care in update_wm(). - * i.e enable wm only if io buffers are allocated - */ + + /* Enable WM */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + + rsrc_data->hw_regs->cfg); CAM_DBG(CAM_ISP, "WM res %d width = %d, height = %d", rsrc_data->index, rsrc_data->width, rsrc_data->height); -- GitLab From 60c1f3bb1395bfdb63ad49692b1c6901a3ad8a06 Mon Sep 17 00:00:00 2001 From: "junwen.ye" Date: Thu, 4 Aug 2022 17:20:04 +0800 Subject: [PATCH 406/410] [Camera]Record 4K video can not be saved &&&%%%comment:[Camera]Record 4K video can not be saved &&&%%%product name:sm7225_s_fp4_target_dev &&&%%%jira id:FP4S-434 &&&%%%root cause:coding &&&%%%Bug category:T2M &&&%%%Module_Impact:kernel &&&%%%Test_Suggestion:NA &&&%%%Solution:NA &&&%%%Test_Report:waiting for test &&&%%%VAL Can Test:NA --- drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c | 6 +++--- .../cam_sensor_module/cam_sensor_utils/cam_sensor_util.c | 5 +++++ drivers/cam_utils/cam_debug_util.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index d62235303cd6..919edf1dc417 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -882,7 +882,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->power_stat = CAM_SENSOR_POWER_ON; } else{ - CAM_ERR(CAM_SENSOR,"SENSOR already power on !!"); + CAM_DBG(CAM_SENSOR,"SENSOR already power on !!"); } if (s_ctrl->i2c_data.poweron_reg_settings.is_settings_valid) { rc = cam_sensor_apply_settings(s_ctrl, 0, @@ -1030,7 +1030,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->power_stat = CAM_SENSOR_POWER_ON; } else{ - CAM_ERR(CAM_SENSOR,"SENSOR already power on!!"); + CAM_DBG(CAM_SENSOR,"SENSOR already power on!!"); } s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; @@ -1209,7 +1209,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } else { - CAM_ERR(CAM_SENSOR,"sensor already init setting !!!!"); + CAM_DBG(CAM_SENSOR,"sensor already init setting !!!!"); } rc = delete_request(&s_ctrl->i2c_data.init_settings); if (rc < 0) { diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 2e1b94a20917..21ddcc12a270 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1861,6 +1861,11 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, if (soc_info->use_shared_clk) cam_res_mgr_shared_clk_config(true); + if (!strcmp(soc_info->dev_name,"ac4a000.qcom,cci0:qcom,ois@0")) { + CAM_DBG(CAM_SENSOR, "OIS no need power up again!"); + return 0; + } + ret = msm_camera_pinctrl_init(&(ctrl->pinctrl_info), ctrl->dev); if (ret < 0) { /* Some sensor subdev no pinctrl. */ diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 181a1558a904..9ab1c2761590 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -98,7 +98,7 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_INFO(__module, fmt, args...) \ - pr_info("CAM_INFO: %s: %s: %d " fmt "\n", \ + pr_debug("CAM_INFO: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) /* -- GitLab From e6d03e41b7982dc0decaa97e304e6be25907f9af Mon Sep 17 00:00:00 2001 From: Ashish Bhimanpalliwar Date: Wed, 3 Aug 2022 11:04:07 +0530 Subject: [PATCH 407/410] msm: camera: common: Add conditions to catch invalid packet data Add conditions to catch invalid cmd_desc, io buffers, and kmd buffers in the packet payload. CRs-Fixed: 3250331 Change-Id: I2db474572a8c5391ba9b9821de2da0db8f10eb4d Signed-off-by: Ashish Bhimanpalliwar --- drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 5 ++++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 6 ++++-- drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 6 ++++-- .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 6 ++++++ .../cam_csiphy/cam_csiphy_core.c | 19 ++++++++++++++++--- drivers/cam_utils/cam_packet_util.c | 14 ++++++++++++++ 6 files changed, 48 insertions(+), 8 deletions(-) diff --git a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index ba83d4db92a9..4871e5351291 100644 --- a/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -53,7 +54,9 @@ static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet, } /* All buffers must come through io config, do not support patching */ - if (packet->num_patches || !packet->num_io_configs) { + if (packet->num_patches || + !packet->num_io_configs || + !packet->num_cmd_buf) { CAM_ERR(CAM_FD, "wrong number of cmd/patch info: %u %u", packet->num_cmd_buf, packet->num_patches); return -EINVAL; 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 40bb64848b39..85eeb6a5d1ce 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 @@ -4215,13 +4215,15 @@ static int cam_icp_mgr_pkt_validation(struct cam_packet *packet) return -EINVAL; } - if (packet->num_io_configs > IPE_IO_IMAGES_MAX) { + if (!packet->num_io_configs || + packet->num_io_configs > IPE_IO_IMAGES_MAX) { CAM_ERR(CAM_ICP, "Invalid number of io configs: %d %d", IPE_IO_IMAGES_MAX, packet->num_io_configs); return -EINVAL; } - if (packet->num_cmd_buf > CAM_ICP_CTX_MAX_CMD_BUFFERS) { + if (!packet->num_cmd_buf || + packet->num_cmd_buf > CAM_ICP_CTX_MAX_CMD_BUFFERS) { CAM_ERR(CAM_ICP, "Invalid number of cmd buffers: %d %d", CAM_ICP_CTX_MAX_CMD_BUFFERS, packet->num_cmd_buf); return -EINVAL; diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index e30033d1169b..045b133d1e1e 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -727,8 +728,9 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, return rc; } - if ((packet->num_cmd_buf > 5) || !packet->num_patches || - !packet->num_io_configs || + if (!packet->num_cmd_buf || + (packet->num_cmd_buf > 5) || + !packet->num_patches || !packet->num_io_configs || (packet->num_io_configs > CAM_JPEG_IMAGE_MAX)) { CAM_ERR(CAM_JPEG, "wrong number of cmd/patch/io_configs info: %u %u %u", diff --git a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index a054d5f84709..31d835d60e90 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -112,6 +113,11 @@ static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet, return -EINVAL; } + if (!packet->num_cmd_buf) { + CAM_ERR(CAM_LRME, "no cmd bufs"); + return -EINVAL; + } + cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)&packet->payload + packet->cmd_buf_offset); diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index b4ebae694ef3..53fdf4f6f9f5 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -261,9 +261,22 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, return rc; } - cmd_desc = (struct cam_cmd_buf_desc *) - ((uint32_t *)&csl_packet->payload + - csl_packet->cmd_buf_offset / 4); + if (csl_packet->num_cmd_buf) + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset / 4); + else { + CAM_ERR(CAM_CSIPHY, "num_cmd_buffers = %d", + csl_packet->num_cmd_buf); + rc = -EINVAL; + return rc; + } + + rc = cam_packet_util_validate_cmd_desc(cmd_desc); + if (rc) { + CAM_ERR(CAM_CSIPHY, "Invalid cmd desc ret: %d", rc); + return rc; + } rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, &generic_ptr, &len); diff --git a/drivers/cam_utils/cam_packet_util.c b/drivers/cam_utils/cam_packet_util.c index 1569d5dbafa6..4b1b60b66704 100644 --- a/drivers/cam_utils/cam_packet_util.c +++ b/drivers/cam_utils/cam_packet_util.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -32,6 +33,12 @@ int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc) { + + if (!cmd_desc) { + CAM_ERR(CAM_UTIL, "Invalid cmd desc"); + return -EINVAL; + } + if ((cmd_desc->length > cmd_desc->size) || (cmd_desc->mem_handle <= 0)) { CAM_ERR(CAM_UTIL, "invalid cmd arg %d %d %d %d", @@ -72,6 +79,7 @@ int cam_packet_util_validate_packet(struct cam_packet *packet, pkt_wo_payload = offsetof(struct cam_packet, payload); if ((!packet->header.size) || + ((size_t)packet->header.size <= pkt_wo_payload) || ((pkt_wo_payload + (size_t)packet->cmd_buf_offset + sum_cmd_desc) > (size_t)packet->header.size) || ((pkt_wo_payload + (size_t)packet->io_configs_offset + @@ -101,6 +109,12 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, return -EINVAL; } + if (!packet->num_cmd_buf) { + CAM_ERR(CAM_UTIL, "Invalid num_cmd_buf = %d", + packet->num_cmd_buf); + return -EINVAL; + } + if ((packet->kmd_cmd_buf_index < 0) || (packet->kmd_cmd_buf_index >= packet->num_cmd_buf)) { CAM_ERR(CAM_UTIL, "Invalid kmd buf index: %d", -- GitLab From a7573e07554c7c2ba95b4a72d76de87e30b9d90f Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Tue, 29 Nov 2022 20:15:25 +0800 Subject: [PATCH 408/410] msm: camera: sensor: Using low priority queue for init setting This change uses low priority queue to write sensor init setting. CRs-Fixed: 3368476 Change-Id: I265920c40fae562b4f86d92a65785a73a9b78116 Signed-off-by: Depeng Shao --- .../cam_actuator/cam_actuator_core.c | 7 +++-- .../cam_sensor_module/cam_cci/cam_cci_core.c | 30 ++++++++++++------- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 2 ++ .../cam_eeprom/cam_eeprom_core.c | 8 ++--- .../cam_sensor_module/cam_ois/cam_ois_core.c | 7 +++-- .../cam_sensor/cam_sensor_core.c | 19 +++++++----- .../cam_sensor/cam_sensor_dev.h | 3 ++ .../cam_sensor/cam_sensor_soc.c | 14 +++++++++ .../cam_sensor_io/cam_sensor_cci_i2c.c | 17 +++++++---- .../cam_sensor_io/cam_sensor_i2c.h | 7 +++-- .../cam_sensor_io/cam_sensor_io.c | 12 +++++--- .../cam_sensor_io/cam_sensor_io.h | 7 +++-- .../cam_sensor_utils/cam_sensor_util.c | 9 ++++-- 13 files changed, 98 insertions(+), 44 deletions(-) diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index 8ee158472765..afdb117005d1 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -153,7 +154,7 @@ static int32_t cam_actuator_i2c_modes_util( if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { rc = camera_io_dev_write(io_master_info, - &(i2c_list->i2c_settings)); + &(i2c_list->i2c_settings), false); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to random write I2C settings: %d", @@ -164,7 +165,7 @@ static int32_t cam_actuator_i2c_modes_util( rc = camera_io_dev_write_continuous( io_master_info, &(i2c_list->i2c_settings), - 0); + 0, false); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to seq write I2C settings: %d", @@ -175,7 +176,7 @@ static int32_t cam_actuator_i2c_modes_util( rc = camera_io_dev_write_continuous( io_master_info, &(i2c_list->i2c_settings), - 1); + 1, false); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to burst write I2C settings: %d", diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index f0f91289887f..06a68bb422d4 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1654,18 +1655,27 @@ static int32_t cam_cci_write(struct v4l2_subdev *sd, case MSM_CCI_I2C_WRITE: case MSM_CCI_I2C_WRITE_SEQ: case MSM_CCI_I2C_WRITE_BURST: - for (i = 0; i < NUM_QUEUES; i++) { - if (mutex_trylock(&cci_master_info->mutex_q[i])) { - rc = cam_cci_i2c_write(sd, c_ctrl, i, - MSM_SYNC_DISABLE); - mutex_unlock(&cci_master_info->mutex_q[i]); - return rc; + if (!c_ctrl->force_low_priority) { + for (i = 0; i < NUM_QUEUES; i++) { + if (mutex_trylock( + &cci_master_info->mutex_q[i])) { + rc = cam_cci_i2c_write(sd, c_ctrl, i, + MSM_SYNC_DISABLE); + mutex_unlock( + &cci_master_info->mutex_q[i]); + return rc; + } } + mutex_lock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); + rc = cam_cci_i2c_write(sd, c_ctrl, + PRIORITY_QUEUE, MSM_SYNC_DISABLE); + mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); + } else { + mutex_lock(&cci_master_info->mutex_q[SYNC_QUEUE]); + rc = cam_cci_i2c_write(sd, c_ctrl, + SYNC_QUEUE, MSM_SYNC_DISABLE); + mutex_unlock(&cci_master_info->mutex_q[SYNC_QUEUE]); } - mutex_lock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); - rc = cam_cci_i2c_write(sd, c_ctrl, - PRIORITY_QUEUE, MSM_SYNC_DISABLE); - mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); break; case MSM_CCI_I2C_WRITE_ASYNC: rc = cam_cci_i2c_write_async(sd, c_ctrl, diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index 1aee97cf4ee4..404b41df8044 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_CCI_DEV_H_ @@ -284,6 +285,7 @@ struct cam_cci_ctrl { struct cam_cci_wait_sync_cfg cci_wait_sync_cfg; struct cam_cci_gpio_cfg gpio_cfg; } cfg; + bool force_low_priority; }; struct cci_write_async { diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 41f3a9538c08..b648b9a11d80 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -65,7 +65,7 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, i2c_reg_array.delay = emap[j].page.delay; i2c_reg_settings.reg_setting = &i2c_reg_array; rc = camera_io_dev_write(&e_ctrl->io_master_info, - &i2c_reg_settings); + &i2c_reg_settings, false); if (rc) { CAM_ERR(CAM_EEPROM, "page write failed rc %d", rc); @@ -82,7 +82,7 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, i2c_reg_array.delay = emap[j].pageen.delay; i2c_reg_settings.reg_setting = &i2c_reg_array; rc = camera_io_dev_write(&e_ctrl->io_master_info, - &i2c_reg_settings); + &i2c_reg_settings, false); if (rc) { CAM_ERR(CAM_EEPROM, "page enable failed rc %d", rc); @@ -126,7 +126,7 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, i2c_reg_array.delay = emap[j].pageen.delay; i2c_reg_settings.reg_setting = &i2c_reg_array; rc = camera_io_dev_write(&e_ctrl->io_master_info, - &i2c_reg_settings); + &i2c_reg_settings, false); if (rc) { CAM_ERR(CAM_EEPROM, "page disable failed rc %d", @@ -1172,7 +1172,7 @@ static int32_t cam_eeprom_write(struct cam_eeprom_ctrl_t *e_ctrl) &(i2c_set->list_head), list) { rc = camera_io_dev_write_continuous( &e_ctrl->io_master_info, - &i2c_list->i2c_settings, 1); + &i2c_list->i2c_settings, 1, false); if (rc < 0) { CAM_ERR(CAM_EEPROM, "Error in EEPROM write"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 4520139fa001..0953bba90ec5 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -223,7 +224,7 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, &(i2c_set->list_head), list) { if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { rc = camera_io_dev_write(&(o_ctrl->io_master_info), - &(i2c_list->i2c_settings)); + &(i2c_list->i2c_settings), false); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed in Applying i2c wrt settings"); @@ -354,7 +355,7 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) } rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), - &i2c_reg_setting, 1); + &i2c_reg_setting, 1, false); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); goto release_firmware; @@ -399,7 +400,7 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) } rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), - &i2c_reg_setting, 1); + &i2c_reg_setting, 1, false); if (rc < 0) CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index a6cbd20d62af..718a2ae3512b 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -12,7 +13,6 @@ #include "cam_common_util.h" #include "cam_packet_util.h" - static void cam_sensor_update_req_mgr( struct cam_sensor_ctrl_t *s_ctrl, struct cam_packet *csl_packet) @@ -384,7 +384,8 @@ static int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info, static int32_t cam_sensor_i2c_modes_util( struct cam_sensor_ctrl_t *s_ctrl, - struct i2c_settings_list *i2c_list) + struct i2c_settings_list *i2c_list, + bool force_low_priority) { int32_t rc = 0; uint32_t i, size; @@ -399,7 +400,8 @@ static int32_t cam_sensor_i2c_modes_util( if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { rc = camera_io_dev_write(io_master_info, - &(i2c_list->i2c_settings)); + &(i2c_list->i2c_settings), + force_low_priority); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to random write I2C settings: %d", @@ -410,7 +412,7 @@ static int32_t cam_sensor_i2c_modes_util( rc = camera_io_dev_write_continuous( io_master_info, &(i2c_list->i2c_settings), - 0); + 0, force_low_priority); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to seq write I2C settings: %d", @@ -421,7 +423,7 @@ static int32_t cam_sensor_i2c_modes_util( rc = camera_io_dev_write_continuous( io_master_info, &(i2c_list->i2c_settings), - 1); + 1, force_low_priority); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to burst write I2C settings: %d", @@ -1348,6 +1350,7 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, uint64_t top = 0, del_req_id = 0; struct i2c_settings_array *i2c_set = NULL; struct i2c_settings_list *i2c_list; + bool force_low_priority = false; if (req_id == 0) { switch (opcode) { @@ -1357,6 +1360,8 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, } case CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG: { i2c_set = &s_ctrl->i2c_data.init_settings; + force_low_priority = + s_ctrl->force_low_priority_for_init_setting; break; } case CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG: { @@ -1388,7 +1393,7 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, list_for_each_entry(i2c_list, &(i2c_set->list_head), list) { rc = cam_sensor_i2c_modes_util(s_ctrl, - i2c_list); + i2c_list, force_low_priority); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to apply settings: %d", @@ -1405,7 +1410,7 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, list_for_each_entry(i2c_list, &(i2c_set->list_head), list) { rc = cam_sensor_i2c_modes_util(s_ctrl, - i2c_list); + i2c_list, force_low_priority); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to apply settings: %d", diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h index d9e8eaaeb129..d38a4f1a186c 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -85,6 +85,8 @@ struct intf_params { * @bob_pwm_switch: Boolean flag to switch into PWM mode for BoB regulator * @last_flush_req: Last request to flush * @pipeline_delay: Sensor pipeline delay + * @force_low_priority_for_init_setting: Using low priority queue to send + * init setting */ struct cam_sensor_ctrl_t { char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; @@ -112,6 +114,7 @@ struct cam_sensor_ctrl_t { uint32_t last_flush_req; uint16_t pipeline_delay; int32_t open_cnt; + bool force_low_priority_for_init_setting; }; #endif /* _CAM_SENSOR_DEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c index 2c25ee0aa6f0..3f45685cb786 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c @@ -98,6 +98,7 @@ static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) { int32_t rc = 0; int i = 0; + uint32_t concurrency_sensors = 0; struct cam_sensor_board_info *sensordata = NULL; struct device_node *of_node = s_ctrl->of_node; struct device_node *of_parent = NULL; @@ -185,6 +186,19 @@ static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->cci_num = CCI_DEVICE_0; CAM_DBG(CAM_SENSOR, "cci-index %d", s_ctrl->cci_num); + + rc = of_property_read_u32(of_node, + "concurrency-sensors-on-same-cci", + &concurrency_sensors); + CAM_DBG(CAM_SENSOR, + "sensor %d concurrency_sensors %d, rc %d", + soc_info->index, concurrency_sensors, rc); + if (rc < 0 || concurrency_sensors < 2) { + s_ctrl->force_low_priority_for_init_setting = false; + rc = 0; + } else + s_ctrl->force_low_priority_for_init_setting = true; + } if (of_property_read_u32(of_node, "sensor-position-pitch", diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c index a5e780a2e119..4b3cfaeceb55 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "cam_sensor_cmn_header.h" @@ -96,7 +97,8 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, static int32_t cam_cci_i2c_write_table_cmd( struct camera_io_master *client, struct cam_sensor_i2c_reg_setting *write_setting, - enum cam_cci_cmd_type cmd) + enum cam_cci_cmd_type cmd, + bool force_low_priority) { int32_t rc = -EINVAL; struct cam_cci_ctrl cci_ctrl; @@ -117,6 +119,7 @@ static int32_t cam_cci_i2c_write_table_cmd( cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = write_setting->addr_type; cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; + cci_ctrl.force_low_priority = force_low_priority; rc = v4l2_subdev_call(client->cci_client->cci_subdev, core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); if (rc < 0) { @@ -136,25 +139,27 @@ static int32_t cam_cci_i2c_write_table_cmd( int32_t cam_cci_i2c_write_table( struct camera_io_master *client, - struct cam_sensor_i2c_reg_setting *write_setting) + struct cam_sensor_i2c_reg_setting *write_setting, + bool force_low_priority) { return cam_cci_i2c_write_table_cmd(client, write_setting, - MSM_CCI_I2C_WRITE); + MSM_CCI_I2C_WRITE, force_low_priority); } int32_t cam_cci_i2c_write_continuous_table( struct camera_io_master *client, struct cam_sensor_i2c_reg_setting *write_setting, - uint8_t cam_sensor_i2c_write_flag) + uint8_t cam_sensor_i2c_write_flag, + bool force_low_priority) { int32_t rc = 0; if (cam_sensor_i2c_write_flag == 1) rc = cam_cci_i2c_write_table_cmd(client, write_setting, - MSM_CCI_I2C_WRITE_BURST); + MSM_CCI_I2C_WRITE_BURST, force_low_priority); else if (cam_sensor_i2c_write_flag == 0) rc = cam_cci_i2c_write_table_cmd(client, write_setting, - MSM_CCI_I2C_WRITE_SEQ); + MSM_CCI_I2C_WRITE_SEQ, force_low_priority); return rc; } diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h index def8be55bc8b..094b57cb6916 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -1,6 +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. */ #ifndef _CAM_SENSOR_I2C_H_ @@ -57,7 +58,8 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *client, */ int32_t cam_cci_i2c_write_table( struct camera_io_master *client, - struct cam_sensor_i2c_reg_setting *write_setting); + struct cam_sensor_i2c_reg_setting *write_setting, + bool force_low_priority); /** * @client: CCI client structure @@ -69,7 +71,8 @@ int32_t cam_cci_i2c_write_table( int32_t cam_cci_i2c_write_continuous_table( struct camera_io_master *client, struct cam_sensor_i2c_reg_setting *write_setting, - uint8_t cam_sensor_i2c_write_flag); + uint8_t cam_sensor_i2c_write_flag, + bool force_low_priority); /** * @cci_client: CCI client structure diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c index 108c47923eb7..b9c0fb127636 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c @@ -1,6 +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. */ #include "cam_sensor_io.h" @@ -116,7 +117,8 @@ int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, } int32_t camera_io_dev_write(struct camera_io_master *io_master_info, - struct cam_sensor_i2c_reg_setting *write_setting) + struct cam_sensor_i2c_reg_setting *write_setting, + bool force_low_priority) { if (!write_setting || !io_master_info) { CAM_ERR(CAM_SENSOR, @@ -132,7 +134,7 @@ int32_t camera_io_dev_write(struct camera_io_master *io_master_info, if (io_master_info->master_type == CCI_MASTER) { return cam_cci_i2c_write_table(io_master_info, - write_setting); + write_setting, force_low_priority); } else if (io_master_info->master_type == I2C_MASTER) { return cam_qup_i2c_write_table(io_master_info, write_setting); @@ -148,7 +150,8 @@ int32_t camera_io_dev_write(struct camera_io_master *io_master_info, int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info, struct cam_sensor_i2c_reg_setting *write_setting, - uint8_t cam_sensor_i2c_write_flag) + uint8_t cam_sensor_i2c_write_flag, + bool force_low_priority) { if (!write_setting || !io_master_info) { CAM_ERR(CAM_SENSOR, @@ -164,7 +167,8 @@ int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info, if (io_master_info->master_type == CCI_MASTER) { return cam_cci_i2c_write_continuous_table(io_master_info, - write_setting, cam_sensor_i2c_write_flag); + write_setting, cam_sensor_i2c_write_flag, + force_low_priority); } else if (io_master_info->master_type == I2C_MASTER) { return cam_qup_i2c_write_continuous_table(io_master_info, write_setting, cam_sensor_i2c_write_flag); diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h index f70709997e69..1cfd8bacce1c 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h @@ -1,6 +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. */ #ifndef _CAM_SENSOR_IO_H_ @@ -78,7 +79,8 @@ int32_t camera_io_release(struct camera_io_master *io_master_info); * This API abstracts write functionality based on master type */ int32_t camera_io_dev_write(struct camera_io_master *io_master_info, - struct cam_sensor_i2c_reg_setting *write_setting); + struct cam_sensor_i2c_reg_setting *write_setting, + bool force_low_priority); /** * @io_master_info: I2C/SPI master information @@ -90,7 +92,8 @@ int32_t camera_io_dev_write(struct camera_io_master *io_master_info, */ int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info, struct cam_sensor_i2c_reg_setting *write_setting, - uint8_t cam_sensor_i2c_write_flag); + uint8_t cam_sensor_i2c_write_flag, + bool force_low_priority); int32_t camera_io_dev_erase(struct camera_io_master *io_master_info, uint32_t addr, uint32_t size); diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index b0c0b4384366..f8259d188122 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -724,7 +725,7 @@ int cam_sensor_util_i2c_apply_setting( switch (i2c_list->op_code) { case CAM_SENSOR_I2C_WRITE_RANDOM: { rc = camera_io_dev_write(io_master_info, - &(i2c_list->i2c_settings)); + &(i2c_list->i2c_settings), false); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to random write I2C settings: %d", @@ -735,7 +736,8 @@ int cam_sensor_util_i2c_apply_setting( } case CAM_SENSOR_I2C_WRITE_SEQ: { rc = camera_io_dev_write_continuous( - io_master_info, &(i2c_list->i2c_settings), 0); + io_master_info, &(i2c_list->i2c_settings), + 0, false); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to seq write I2C settings: %d", @@ -746,7 +748,8 @@ int cam_sensor_util_i2c_apply_setting( } case CAM_SENSOR_I2C_WRITE_BURST: { rc = camera_io_dev_write_continuous( - io_master_info, &(i2c_list->i2c_settings), 1); + io_master_info, &(i2c_list->i2c_settings), + 1, false); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to burst write I2C settings: %d", -- GitLab From 2d0bdfe4ebe2bc04b09804dedd895389c5951876 Mon Sep 17 00:00:00 2001 From: Shivakumar Malke Date: Thu, 5 Jan 2023 11:34:51 +0530 Subject: [PATCH 409/410] msm: camera: isp: Handle RUP in applied substate In RDI only context, if RUP is received earlier than SOF, the state machine is set to applied state and there is no handling for RUP in applied substate. Hence leading to bubble scenario and apply failures. To overcome such scenario, handling for RUP in applied substate is introduced in RDI only context statemachine. In this handling, substate is moved to EPOCH so when SOF is scheduled next state machine moves in right direction. CRs-Fixed: 3371187 Change-Id: I44442a8aa85a996c0adc658be52cfe92b7ecfc4d Signed-off-by: Shivakumar Malke --- drivers/cam_isp/cam_isp_context.c | 67 ++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index d890af0ba824..8deaf1343f25 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-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. */ #include @@ -3843,6 +3843,69 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( return 0; } +static int __cam_isp_ctx_rdi_only_reg_upd_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_ctx_request *req = NULL; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Reg upd ack with no waiting req ctx %u active cnt %d", + ctx->ctx_id, ctx_isp->active_req_cnt); + + /* move the sub state machine to SOF sub state */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + goto end; + } + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + request_id = (req_isp->hw_update_data.packet_opcode_type == + CAM_ISP_PACKET_INIT_DEV) ? 0 : req->request_id; + + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + request_id = req->request_id; + CAM_DBG(CAM_REQ, + "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_ISP, + "move active req %lld to free list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } + + if (request_id) { + ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } + + CAM_DBG(CAM_ISP, "next Substate[%s] ctx %u", + __cam_isp_ctx_substate_val_to_type(ctx_isp->substate_activated), + ctx->ctx_id); + + __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_RUP, req); + + return 0; +end: + __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_RUP, NULL); + + return 0; +} + static struct cam_isp_ctx_irq_ops cam_isp_ctx_rdi_only_activated_state_machine_irq [CAM_ISP_CTX_ACTIVATED_MAX] = { @@ -3862,7 +3925,7 @@ static struct cam_isp_ctx_irq_ops .irq_ops = { __cam_isp_ctx_handle_error, __cam_isp_ctx_rdi_only_sof_in_applied_state, - NULL, + __cam_isp_ctx_rdi_only_reg_upd_in_applied_state, NULL, NULL, __cam_isp_ctx_buf_done_in_applied, -- GitLab From 8274bad57173ea3fc797a72dc64adb8bee15fcdc Mon Sep 17 00:00:00 2001 From: android-t1 Date: Wed, 19 Apr 2023 16:06:23 +0800 Subject: [PATCH 410/410] fix build error --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 94 +++++++++---------- .../cam_sensor_module/cam_ois/cam_ois_dev.c | 4 +- .../cam_sensor/cam_sensor_core.c | 2 +- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 938f03ff6047..b2cb400b8436 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -386,7 +386,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[13].val; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); mdelay(50); @@ -394,7 +394,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[14].val; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); CAM_ERR(CAM_OIS, "write 0x9E18 -> 0x0002"); mdelay(50); @@ -402,7 +402,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].reg_data = cml_ois_gyro_calibration[15].val; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); mdelay(50); @@ -420,7 +420,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9fb2 -> 0x%x(default offset)",c); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[17].reg; @@ -428,7 +428,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9fb4 -> 0x%x(default offset)",d); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); } else CAM_ERR(CAM_OIS, "invalid x(0x%x) or y(0x%x) gain",c,d); @@ -447,7 +447,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9fb2 -> 0x%x(manual)",c); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_gyro_calibration[17].reg; @@ -455,7 +455,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9fb4 -> 0x%x(manual)",d); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); } else CAM_ERR(CAM_OIS, "invalid x(0x%x) or y(0x%x) gain",c,d); @@ -467,7 +467,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0002"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); cmd_adress = cml_ois_gyro_calibration[5].reg; @@ -490,7 +490,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(3000); @@ -532,7 +532,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0006"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0001} failed %d", rc); } @@ -549,7 +549,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0220 -> 0xc0d4"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write 0x0220 -> 0xc0d4 failed %d", rc); } @@ -560,7 +560,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001 failed %d", rc); } @@ -576,7 +576,7 @@ static int cam_ois_gyro_calibration(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0220 -> 0x0000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write 0x0220 -> 0x0000 failed %d", rc); } @@ -812,7 +812,7 @@ static int cam_ois_init(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[6].reg; @@ -820,7 +820,7 @@ static int cam_ois_init(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9e18 -> 0x0002"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[7].reg; @@ -828,7 +828,7 @@ static int cam_ois_init(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[8].reg; @@ -836,7 +836,7 @@ static int cam_ois_init(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x8820 -> 0x0028"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); i2c_reg_setting.reg_setting[0].reg_addr = cml_ois_control[9].reg; @@ -844,7 +844,7 @@ static int cam_ois_init(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0002"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(50); cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); @@ -925,7 +925,7 @@ static int cam_cml_ois_enable(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write {0x9b2c ,0x0001} failed %d", rc); @@ -937,7 +937,7 @@ static int cam_cml_ois_enable(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0001} failed %d", rc); } @@ -981,7 +981,7 @@ static int cam_cml_ois_disable(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2c -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write {0x9b2c ,0x0001} failed %d", rc); @@ -993,7 +993,7 @@ static int cam_cml_ois_disable(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x9b2a -> 0x0000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write {0x9b2a ,0x0000} failed %d", rc); } @@ -1161,7 +1161,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0020 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); i2c_reg_setting.reg_setting[0].reg_addr = 0x0024; @@ -1169,7 +1169,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); i2c_reg_setting.reg_setting[0].reg_addr = 0x0220; @@ -1177,7 +1177,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0220 -> 0xC0D4"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); i2c_reg_setting.reg_setting[0].reg_addr = 0x3000; @@ -1185,7 +1185,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3000 -> 0x0000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); addr = 0x8000;//MCS_START_ADDRESS @@ -1197,7 +1197,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3008 -> 0x%x",addr); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); //erase sector 2kbyte @@ -1206,7 +1206,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x300C -> 0x0002"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); addr += 0x800; //2kbyte mdelay(5); } @@ -1222,7 +1222,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3028 -> 0x%x",addr); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); addr += 0x4; //2kbyte @@ -1232,7 +1232,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting_1.reg_setting[0].delay = 1; i2c_reg_setting_1.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x302C -> 0x%x",read_data); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting_1); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting_1, false); } i2c_reg_setting.reg_setting[0].reg_addr = 0x3048; @@ -1240,14 +1240,14 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3048 -> 0x8000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); i2c_reg_setting.reg_setting[0].reg_addr = 0x304C; i2c_reg_setting.reg_setting[0].reg_data = 0x2000; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x304C -> 0x2000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); i2c_reg_setting.reg_setting[0].reg_addr = 0x3050; @@ -1255,7 +1255,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3050 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); rc = camera_io_dev_read(&(o_ctrl->io_master_info),0x3054,&csH,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); @@ -1278,7 +1278,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(10); /* cm4x1_MCS_download end*/ @@ -1291,7 +1291,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0020 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); //stanby mode(MCU off) i2c_reg_setting.reg_setting[0].reg_addr = 0x0024; @@ -1299,7 +1299,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0024 -> 0x0000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); //code protection i2c_reg_setting.reg_setting[0].reg_addr = 0x0220; @@ -1307,7 +1307,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0220 -> 0xC0D4"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); //select if flash i2c_reg_setting.reg_setting[0].reg_addr = 0x3000; @@ -1315,7 +1315,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3000 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); addr = 0x0000; @@ -1327,7 +1327,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3008 -> 0x%x",addr); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); //erase page 512 byte i2c_reg_setting.reg_setting[0].reg_addr = 0x300C; @@ -1335,7 +1335,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x300C -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); addr += 0x200; //512 byte mdelay(5); } @@ -1351,7 +1351,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3028 -> 0x%x",addr); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); addr += 0x4; /* program sequential write 2K byte */ @@ -1360,7 +1360,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting_1.reg_setting[0].delay = 1; i2c_reg_setting_1.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x302C -> 0x%x",read_data); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting_1); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting_1, false); } /* Checksum calculation for fw data */ @@ -1371,21 +1371,21 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3048 -> 0x0000"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); i2c_reg_setting.reg_setting[0].reg_addr = 0x304C; i2c_reg_setting.reg_setting[0].reg_data = 0x0200; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x304C -> 0x0200"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); i2c_reg_setting.reg_setting[0].reg_addr = 0x3050; i2c_reg_setting.reg_setting[0].reg_data = 0x0001; i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x3050 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(1); rc = camera_io_dev_read(&(o_ctrl->io_master_info),0x3054,&csH,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD); @@ -1412,7 +1412,7 @@ static int cam_cml_ois_fw_upgrade(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x0018 -> 0x0001"); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); mdelay(10); /* cm4x1_IF_download end*/ @@ -1500,7 +1500,7 @@ ssize_t ois_reg_store(struct device *dev, struct device_attribute *attr, const i2c_reg_setting.reg_setting[0].delay = 1; i2c_reg_setting.reg_setting[0].data_mask = 0; CAM_ERR(CAM_OIS, "write 0x%x -> 0x%x",cmd_adress,cmd_data); - rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting); + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_reg_setting, false); if (rc < 0) { CAM_ERR(CAM_OIS, "write 0x%x -> 0x%x failed %d",cmd_adress,cmd_data,rc); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index 0ac1c78b69a9..8402d0cfabed 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -335,12 +335,12 @@ static int32_t load_ois_data(struct cam_ois_dev *pois_dev) return -EINVAL; } mutex_lock(&(o_ctrl->ois_mutex)); - camera_io_dev_write_continuous(&o_ctrl->io_master_info, &pois_dev->i2c_reg_setting, 0); + camera_io_dev_write_continuous(&o_ctrl->io_master_info, &pois_dev->i2c_reg_setting, 0, false); mdelay(1); /* for safe read data */ get_monotonic_boottime64(&ts); pois_dev->load_ois_timestamp = time_stamp_val_for_cm401; camera_io_dev_read_seq(&(o_ctrl->io_master_info),0x9DAC, pois_dev->reg_data_buffer,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); - camera_io_dev_write(&o_ctrl->io_master_info,&pois_dev->i2c_reg_setting_for_buffer0); + camera_io_dev_write(&o_ctrl->io_master_info,&pois_dev->i2c_reg_setting_for_buffer0, false); mdelay(1); /* for safe read data */ camera_io_dev_read_seq(&(o_ctrl->io_master_info),0x9DAC, &pois_dev->reg_data_buffer[80],CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,80); reverse_byte(pois_dev); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index cb94682a0c85..27a74fece09e 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1714,7 +1714,7 @@ int sensor_start_thread(void *ctrl) sensor_setting.addr_type = g_oem_sensor_setting.sensor582_sma.addr_type; sensor_setting.data_type = g_oem_sensor_setting.sensor582_sma.data_type; sensor_setting.delay = g_oem_sensor_setting.sensor582_sma.delay; - rc = camera_io_dev_write(&(s_ctrl->io_master_info),&sensor_setting); + rc = camera_io_dev_write(&(s_ctrl->io_master_info),&sensor_setting,false); if(rc < 0) { CAM_ERR(CAM_SENSOR,"sensor init setting error!!!!"); -- GitLab